pipeline {
    agent any

    environment {
        // 环境变量定义
        PROJECT_NAME = 'timeline-frontend'
        DOCKER_REGISTRY = 'timeline-registry:5000'
        DOCKER_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}"
    }

    parameters {
        // 构建参数
        choice(
            name: 'DEPLOY_TARGET',
            choices: ['dev', 'staging', 'prod'],
            description: '选择部署环境'
        )
        string(
            name: 'GIT_COMMIT',
            defaultValue: '',
            description: '指定 Git Commit SHA 进行构建（留空则使用最新提交）'
        )
    }

    stages {
        stage('Checkout') {
            steps {
                script {
                    if (params.GIT_COMMIT) {
                        checkout scm
                        sh "git reset --hard ${params.GIT_COMMIT}"
                    } else {
                        checkout scm
                    }
                }
                echo "当前构建的 Git Commit: ${env.GIT_COMMIT}"
            }
        }

        stage('Build timeline-frontend dist') {
            steps {
                script {
                    def workspace = sh(script: "pwd", returnStdout: true).trim()
                    echo "当前工作空间路径:  ${workspace}"

                    // 确保路径正确
                    sh "ls -la  ${workspace}"

                    // 修复权限问题
                    sh "chmod -R 755  ${workspace}"
                    sh "chown -R jenkins:jenkins  ${workspace}"

                    // 使用 Jenkins Node.js 插件，并确保在工作空间目录中执行
                    dir(workspace) {
                        nodejs('NodeJS-18') {
                            // 检查是否存在 package.json 和 pnpm-lock.yaml
                            if (fileExists('package.json')) {
                                echo "package.json found"
                                if (fileExists('pnpm-lock.yaml')) {
                                    echo "pnpm-lock.yaml found"
                                } else {
                                    error('pnpm-lock.yaml not found')
                                }

                                // 安装 pnpm
                                sh 'npm install -g pnpm'

                                // 检查 package.json 或 pnpm-lock.yaml 是否自上次构建以来发生了更改
                                def shouldInstall = false

                                // 检查是否有上次构建的哈希记录
                                def packageJsonHash = ''
                                def pnpmLockHash = ''

                                if (fileExists('.last_build_hashes')) {
                                    def lastHashes = readFile('.last_build_hashes').split('\n')
                                    def lastPackageJsonHash = ''
                                    def lastPnpmLockHash = ''

                                    lastHashes.each { line ->
                                        if (line.startsWith('packageJson=')) {
                                            lastPackageJsonHash = line.split('=')[1].trim()
                                        } else if (line.startsWith('pnpmLock=')) {
                                            lastPnpmLockHash = line.split('=')[1].trim()
                                        }
                                    }

                                    // 计算当前文件哈希
                                    packageJsonHash = sh(script: 'cat package.json | md5sum | cut -d" " -f1', returnStdout: true).trim()
                                    pnpmLockHash = sh(script: 'cat pnpm-lock.yaml | md5sum | cut -d" " -f1', returnStdout: true).trim()

                                    // 如果任一文件哈希与上次不同，则需要安装
                                    if (packageJsonHash != lastPackageJsonHash || pnpmLockHash != lastPnpmLockHash) {
                                        shouldInstall = true
                                        echo "Detected changes in package management files, running pnpm install"
                                    } else {
                                        echo "No changes detected in package management files, skipping pnpm install"
                                    }
                                } else {
                                    // 第一次构建，需要安装
                                    shouldInstall = true
                                    packageJsonHash = sh(script: 'cat package.json | md5sum | cut -d" " -f1', returnStdout: true).trim()
                                    pnpmLockHash = sh(script: 'cat pnpm-lock.yaml | md5sum | cut -d" " -f1', returnStdout: true).trim()
                                    echo "First build, running pnpm install"
                                }

                                if (shouldInstall) {
                                    // 使用 pnpm 安装依赖，由于锁文件兼容性问题，不使用 --frozen-lockfile
                                    sh 'pnpm install --no-frozen-lockfile'

                                    // 保存当前哈希值供下次比较
                                    writeFile file: '.last_build_hashes', text: "packageJson=${packageJsonHash}\npnpmLock=${pnpmLockHash}"
                                } else {
                                    echo "Skipping pnpm install due to no changes in package management files"
                                }

                                // 构建项目
                                sh 'pnpm run build'

                                // 检查 dist 目录是否存在
                                if (!fileExists('dist')) {
                                    error('ERROR: dist directory does not exist after build')
                                } else {
                                    echo 'Build completed successfully, dist directory exists'
                                }
                            } else {
                                error('package.json not found')
                            }
                        }
                    }
                }
            }
        }

        stage('Build Docker Image') {
            steps {
                script {
                    def imageTag = "${BUILD_NUMBER}-${env.GIT_COMMIT.take(7)}"
                    env.IMAGE_TAG = imageTag

                    sh """
                        docker build -t ${DOCKER_IMAGE}:${imageTag} .
                        docker tag ${DOCKER_IMAGE}:${imageTag} ${DOCKER_IMAGE}:latest
                    """
                }
            }
        }

        stage('Push Docker Image') {
            steps {
                script {

                      sh "docker push ${DOCKER_IMAGE}:latest"
                }
            }
        }

        stage('Deploy to Environment') {
            steps {
                script {
                    deployToEnvironmentWithCompose('dev')
                }
             }
        }
    }

    post {
        always {
            // 清理构建产物
            cleanWs()
        }

        success {
            script {
                def slackMessage = """
                    *✅ 构建成功*
                    项目: ${PROJECT_NAME}
                    构建: ${BUILD_NUMBER}
                    分支: ${env.BRANCH_NAME}
                    提交: ${env.GIT_COMMIT}
                    镜像: ${DOCKER_IMAGE}:${env.IMAGE_TAG}
                """
                // 发送成功通知（如果配置了 Slack 通知）
                // slackSend(channel: '#builds', color: 'good', message: slackMessage)
            }
        }

        failure {
            script {
                def slackMessage = """
                    *❌ 构建失败*
                    项目: ${PROJECT_NAME}
                    构建: ${BUILD_NUMBER}
                    分支: ${env.BRANCH_NAME}
                    提交: ${env.GIT_COMMIT}
                    错误: ${currentBuild.description ?: '构建失败'}
                """
                // 发送失败通知（如果配置了 Slack 通知）
                // slackSend(channel: '#builds', color: 'danger', message: slackMessage)
            }
        }

        cleanup {
            // 清理 Docker 镜像
            script {
                sh """
                    docker rmi -f ${DOCKER_IMAGE}:${env.IMAGE_TAG} || true
                    docker rmi -f ${DOCKER_IMAGE}:latest || true
                """
            }
        }
    }
}

// 公共函数定义
def deployToEnvironmentWithCompose(String env) {
    script {
        // 根据环境设置部署参数，确保容器名称合法
        def cleanEnv = env.replaceAll('[^a-zA-Z0-9]', '-')
        def containerName = "${PROJECT_NAME}-${cleanEnv}".replaceAll('[^a-zA-Z0-9_.-]', '')
        def imageToDeploy = "${DOCKER_IMAGE}:latest"

        // 创建 docker-compose.yml 文件，使用 host 网络模式以便访问宿主机上的后端服务
        def composeFileContent = """services:
  frontend:
    image: ${imageToDeploy}
    container_name: ${containerName}
    restart: unless-stopped
    ports:
      - "${getPortForEnvironment(env)}:80"
    network_mode: "host"
"""

        // 写入 docker-compose.yml 文件
        writeFile file: 'docker-compose.yml', text: composeFileContent

         // 强制停止并删除现有容器（无论是否由compose创建）
          sh """
              docker stop ${containerName} || true
              docker rm ${containerName} || true
          """

        // 启动新服务
        sh """
            docker compose -f docker-compose.yml up -d
        """

        // 验证部署
        sh """
            echo "等待服务启动..."
            sleep 10
            docker ps | grep ${containerName}
            docker logs ${containerName}
        """
    }
}

// 获取环境对应端口的辅助函数
def getPortForEnvironment(String env) {
    switch(env) {
        case 'dev':
            return '3001'
        case 'staging':
            return '3002'
        case 'prod':
            return '80'
        default:
            return '80'
    }
}

// 生成docker-compose文件内容的函数
def getComposeFileContent() {
    def imageToDeploy = "${DOCKER_IMAGE}:latest"
    def containerName = "${PROJECT_NAME}-${env}"
    return """
      version: '3.8'
      services:
        timeline-story-service:
          image: ${imageToDeploy}
          container_name: ${containerName}
          ports:
            - "3000:80"
          extra_hosts:
            - "host.docker.internal:host-gateway"
      """
}
