pipeline {
    agent any

    options {
        timeout(time: 20, unit: 'MINUTES')
        timestamps()
    }

    stages {
        stage('Checkout') {
            steps {
                script {
                    cleanWs()
                    checkout scm

                    echo "✅ Code checked out successfully"
                    echo "📂 Working directory: ${pwd()}"
                    echo "🌿 Git branch: ${env.BRANCH_NAME}"
                    echo "🏷️  Git commit: ${env.GIT_COMMIT?.take(8)}"
                }
            }
        }

        stage('Validate Configuration') {
            steps {
                script {
                    echo "🔍 Validating configuration files..."

                    // Check required files exist
                    if (!fileExists('docker-compose.yml')) {
                        error("❌ docker-compose.yml not found")
                    }
                    echo "✅ Found: docker-compose.yml"

                    if (!fileExists('.env.example')) {
                        error("❌ .env.example not found")
                    }
                    echo "✅ Found: .env.example"

                    // Validate Docker Compose syntax
                    sh '''
                        echo "🐳 Validating Docker Compose files..."
                        # Set dummy values for required environment variables during validation
                        export PG_PASS="validation_dummy_password"
                        export AUTHENTIK_SECRET_KEY="validation_dummy_secret_key_min_60_chars_aaaaaaaaaaaaaaaaaaaaaa"

                        docker compose -f docker-compose.yml config --quiet || {
                            echo "❌ Docker Compose validation failed"
                            exit 1
                        }

                        echo "✅ Docker Compose syntax is valid"
                    '''

                    // Check Jenkins credentials configuration
                    sh '''
                        echo "🔐 Checking Jenkins credentials configuration..."
                        echo "ℹ️  Note: Make sure you have configured these Jenkins credentials:"
                        echo "   - authentik-pg-pass (Secret Text): PostgreSQL password"
                        echo "   - authentik-secret-key (Secret Text): Authentik secret key (60+ chars)"
                        echo "   - authentik-pg-db (String, optional): Database name (default: authentik)"
                        echo "   - authentik-pg-user (String, optional): Database user (default: authentik)"
                        echo "   - authentik-postgres-host (String, optional): PostgreSQL host (default: postgres-postgres)"
                        echo "   - authentik-postgres-port (String, optional): PostgreSQL port (default: 5432)"
                        echo "📝 Configure in: Jenkins → Manage Jenkins → Manage Credentials → (global)"
                    '''
                }
            }
        }

        stage('System Health Check') {
            steps {
                script {
                    echo "🔍 Checking system resources..."

                    sh '''
                        # Check Docker is running
                        docker info > /dev/null && echo "✅ Docker is running"

                        # Check available resources
                        echo "💾 Memory information:"
                        free -h || sysctl hw.memsize || echo "Memory check not available"

                        echo "💿 Disk space:"
                        df -h . || echo "Disk check not available"

                        echo "🖥️  CPU information:"
                        nproc || sysctl -n hw.ncpu || echo "CPU check not available"
                    '''
                }
            }
        }

        stage('Verify Database') {
            when {
                anyOf {
                    branch 'main'
                    branch 'master'
                    buildingTag()
                    changeset "**/*.yml"
                    changeset "**/*.yaml"
                    expression {
                        return env.BRANCH_NAME == null || env.BRANCH_NAME == 'main' || env.BRANCH_NAME == 'master'
                    }
                }
            }
            steps {
                script {
                    echo "🗄️  Verifying Authentik database exists in PostgreSQL..."

                    withCredentials([
                        string(credentialsId: 'authentik-pg-pass', variable: 'PG_PASS'),
                        string(credentialsId: 'authentik-pg-db', variable: 'PG_DB'),
                        string(credentialsId: 'authentik-pg-user', variable: 'PG_USER'),
                        string(credentialsId: 'authentik-postgres-host', variable: 'POSTGRES_HOST')
                    ]) {
                        sh '''
                            export PG_DB="${PG_DB:-authentik}"
                            export PG_USER="${PG_USER:-authentik}"
                            export POSTGRES_HOST="${POSTGRES_HOST:-postgres-postgres}"
                            export PGPASSWORD="${PG_PASS}"

                            echo "🔍 Checking if PostgreSQL server is running..."
                            if ! docker exec ${POSTGRES_HOST} pg_isready > /dev/null 2>&1; then
                                echo "❌ PostgreSQL server '${POSTGRES_HOST}' is not running or not accessible"
                                echo "Please ensure the PostgreSQL deployment is running first"
                                exit 1
                            fi
                            echo "✅ PostgreSQL server is running"

                            echo "ℹ️  Verifying database connection..."

                            # Test connection to the database
                            # If this succeeds, both the database and user exist with correct permissions
                            if docker exec -e PGPASSWORD="${PG_PASS}" ${POSTGRES_HOST} psql -h localhost -U ${PG_USER} -d ${PG_DB} -c "SELECT 1 as connection_test;" > /dev/null 2>&1; then
                                echo "✅ Successfully connected to database '${PG_DB}' as user '${PG_USER}'"
                                echo "✅ Database and user verification completed"
                            else
                                echo "❌ Cannot connect to database '${PG_DB}' as user '${PG_USER}'"
                                echo ""
                                echo "Possible causes:"
                                echo "  1. Database '${PG_DB}' does not exist"
                                echo "  2. User '${PG_USER}' does not exist"
                                echo "  3. User '${PG_USER}' does not have permissions on database '${PG_DB}'"
                                echo "  4. Password in Jenkins credentials does not match"
                                echo ""
                                echo "ℹ️  To create the database and user, run on the PostgreSQL server:"
                                echo "   cd /path/to/postgresql/scripts"
                                echo "   python3 create_db_user.py --username ${PG_USER} --password <password> --databases ${PG_DB}"
                                echo ""
                                exit 1
                            fi
                        '''
                    }
                }
            }
        }

        stage('Deploy Authentik') {
            when {
                anyOf {
                    branch 'main'
                    branch 'master'
                    buildingTag()
                    changeset "**/*.yml"
                    changeset "**/*.yaml"
                    expression {
                        return env.BRANCH_NAME == null || env.BRANCH_NAME == 'main' || env.BRANCH_NAME == 'master'
                    }
                }
            }
            steps {
                script {
                    echo "🚀 Deploying Authentik..."

                    try {
                        // Deploy with Jenkins credentials
                        withCredentials([
                            string(credentialsId: 'authentik-pg-pass', variable: 'PG_PASS'),
                            string(credentialsId: 'authentik-secret-key', variable: 'AUTHENTIK_SECRET_KEY'),
                            string(credentialsId: 'authentik-pg-db', variable: 'PG_DB'),
                            string(credentialsId: 'authentik-pg-user', variable: 'PG_USER'),
                            string(credentialsId: 'authentik-postgres-host', variable: 'POSTGRES_HOST'),
                            string(credentialsId: 'authentik-postgres-port', variable: 'POSTGRES_PORT')
                        ]) {
                            sh '''
                                echo "🔧 Using Jenkins credentials for deployment..."
                                export PG_DB="${PG_DB:-authentik}"
                                export PG_USER="${PG_USER:-authentik}"
                                export PG_PASS="${PG_PASS}"
                                export AUTHENTIK_SECRET_KEY="${AUTHENTIK_SECRET_KEY}"
                                export POSTGRES_HOST="${POSTGRES_HOST:-postgres-postgres}"
                                export POSTGRES_PORT="${POSTGRES_PORT:-5432}"

                                echo "📋 Deployment configuration:"
                                echo "   PostgreSQL Host: ${POSTGRES_HOST}"
                                echo "   PostgreSQL Port: ${POSTGRES_PORT}"
                                echo "   Database: ${PG_DB}"
                                echo "   User: ${PG_USER}"
                                echo "   Password: [REDACTED]"
                                echo "   Secret Key: [REDACTED]"

                                # Stop existing services
                                docker compose down || true

                                # Pull latest images
                                echo "📥 Pulling latest images..."
                                docker compose pull

                                # Start Authentik server and worker
                                echo "🚀 Starting Authentik server and worker..."
                                docker compose up -d server worker

                                # Wait for services to be ready
                                echo "⏳ Waiting for Authentik services to start..."
                                sleep 10

                                # Check if services are running
                                echo "🔍 Checking service status..."
                                docker compose ps
                            '''
                        }

                        echo "✅ Authentik deployed successfully"

                    } catch (Exception e) {
                        echo "❌ Deployment failed: ${e.getMessage()}"

                        // Show logs for debugging
                        sh '''
                            echo "🐳 Container logs:"
                            docker compose logs --tail=50 || echo "Could not get container logs"

                            echo "📋 System status:"
                            docker compose ps || echo "Could not get container status"
                        '''
                        throw e
                    }
                }
            }
        }

        stage('Verify Deployment') {
            steps {
                script {
                    echo "🔍 Verifying deployment..."

                    withCredentials([
                        string(credentialsId: 'authentik-pg-pass', variable: 'PG_PASS'),
                        string(credentialsId: 'authentik-pg-db', variable: 'PG_DB'),
                        string(credentialsId: 'authentik-pg-user', variable: 'PG_USER'),
                        string(credentialsId: 'authentik-postgres-host', variable: 'POSTGRES_HOST')
                    ]) {
                        sh '''
                            export PG_DB="${PG_DB:-authentik}"
                            export PG_USER="${PG_USER:-authentik}"
                            export POSTGRES_HOST="${POSTGRES_HOST:-postgres-postgres}"
                            export PGPASSWORD="${PG_PASS}"

                            echo "🐳 Container status:"
                            docker compose ps || echo "❌ Could not get container status"

                            echo "🔗 Testing database connection to external PostgreSQL..."
                            docker exec -e PGPASSWORD="${PG_PASS}" ${POSTGRES_HOST} psql -h localhost -U ${PG_USER} -d ${PG_DB} -c "SELECT 1 as connection_test;" || echo "⚠️  Database connection test failed"

                            echo "📊 Database statistics:"
                            docker exec -e PGPASSWORD="${PG_PASS}" ${POSTGRES_HOST} psql -h localhost -U ${PG_USER} -d ${PG_DB} -c "
                                SELECT
                                    schemaname,
                                    tablename
                                FROM pg_tables
                                WHERE schemaname = 'public'
                                LIMIT 5;
                            " || echo "⚠️  Could not query database"

                            echo "🌐 Checking Authentik server..."
                            # Wait a bit for Authentik to fully start
                            sleep 5

                            # Check if server container is healthy
                            if docker compose ps server | grep -q "Up"; then
                                echo "✅ Authentik server is running"
                            else
                                echo "⚠️  Authentik server status unclear"
                            fi

                            # Check if worker container is healthy
                            if docker compose ps worker | grep -q "Up"; then
                                echo "✅ Authentik worker is running"
                            else
                                echo "⚠️  Authentik worker status unclear"
                            fi
                        '''
                    }

                    echo "✅ Deployment verification completed"
                }
            }
        }

        stage('Create Backup') {
            steps {
                script {
                    def timestamp = new Date().format('yyyyMMdd_HHmmss')
                    def backupFile = "authentik_backup_${timestamp}.sql"

                    echo "💾 Creating deployment backup: ${backupFile}"

                    withCredentials([
                        string(credentialsId: 'authentik-pg-pass', variable: 'PG_PASS'),
                        string(credentialsId: 'authentik-pg-db', variable: 'PG_DB'),
                        string(credentialsId: 'authentik-pg-user', variable: 'PG_USER'),
                        string(credentialsId: 'authentik-postgres-host', variable: 'POSTGRES_HOST')
                    ]) {
                        sh """
                            export PG_DB="\${PG_DB:-authentik}"
                            export PG_USER="\${PG_USER:-authentik}"
                            export POSTGRES_HOST="\${POSTGRES_HOST:-postgres-postgres}"
                            export PGPASSWORD="\${PG_PASS}"

                            # Create backup directory
                            mkdir -p jenkins_backups

                            # Create backup from external PostgreSQL
                            docker exec -e PGPASSWORD="\${PG_PASS}" \${POSTGRES_HOST} pg_dump \\
                                -h localhost \\
                                -U \${PG_USER} \\
                                -d \${PG_DB} \\
                                --format=custom \\
                                --compress=9 \\
                                --file=/tmp/${backupFile}

                            # Copy backup from container
                            docker cp \${POSTGRES_HOST}:/tmp/${backupFile} jenkins_backups/

                            # Create checksum
                            cd jenkins_backups
                            sha256sum ${backupFile} > ${backupFile}.sha256

                            echo "✅ Backup created: ${backupFile}"
                            ls -lh ${backupFile}
                        """
                    }

                    // Archive backup artifacts
                    archiveArtifacts artifacts: 'jenkins_backups/*.sql,jenkins_backups/*.sha256',
                                 fingerprint: true,
                                 allowEmptyArchive: true
                }
            }
        }
    }

    post {
        always {
            script {
                echo "📋 Pipeline completed with status: ${currentBuild.currentResult}"

                // Generate pipeline summary
                def summary = """
                    🎯 Authentik Deployment Pipeline
                    📅 Build: ${env.BUILD_NUMBER}
                    🌿 Branch: ${env.BRANCH_NAME}
                    🏷️  Commit: ${env.GIT_COMMIT?.take(8)}
                    ⏱️  Duration: ${currentBuild.durationString}
                    ✅ Status: ${currentBuild.currentResult}
                """

                echo summary

                // Clean up old artifacts (keep last 5)
                sh 'find jenkins_backups -name "*.sql" -type f | sort -r | tail -n +6 | xargs rm -f || true'
            }
        }

        success {
            script {
                echo "🎉 Authentik deployment successful!"
                echo ""
                echo "📝 Next steps:"
                echo "   1. Access Authentik: http://<server>:9000/"
                echo "   2. Initial setup: http://<server>:9000/if/flow/initial-setup/"
                echo "   3. Admin interface: http://<server>:9000/if/admin/"
                echo ""
                echo "⚠️  Remember to configure:"
                echo "   - Admin account (initial setup)"
                echo "   - Email settings (for notifications)"
                echo "   - SSL/TLS (reverse proxy recommended)"
                echo "   - Applications and providers"
            }
        }

        failure {
            script {
                echo "❌ Authentik deployment failed!"

                // Show container logs for debugging
                sh '''
                    echo "🐳 Container logs:"
                    docker compose logs --tail=100 || echo "Could not get container logs"

                    echo "📋 System status:"
                    docker compose ps || echo "Could not get container status"
                '''
            }
        }

        unstable {
            script {
                echo "⚠️  Authentik deployment completed with warnings!"
            }
        }

        cleanup {
            script {
                echo "🧹 Cleaning up workspace..."

                // Remove temporary files
                sh 'rm -f *.tmp || true'

                // Only tear down containers for non-main branches (explicit check)
                // Keep containers running on main/master for production
                if (env.BRANCH_NAME && env.BRANCH_NAME != 'main' && env.BRANCH_NAME != 'master') {
                    echo "🗑️  Tearing down development containers for branch: ${env.BRANCH_NAME}"
                    sh 'docker compose down || true'
                } else {
                    echo "✅ Keeping containers running for production (main branch)"
                }
            }
        }
    }
}
