pipeline {
  agent any

  options {
    buildDiscarder(logRotator(numToKeepStr: '10'))
    timestamps()
    ansiColor('xterm')
  }

  // 构建时手选环境与分支：一份 Jenkinsfile 服务 dev / sit / uat 三个环境
  parameters {
    choice(
      name: 'APP_ENV',
      choices: ['dev', 'sit', 'uat'],
      description: '部署到哪个环境'
    )
    string(
      name: 'BRANCH',
      defaultValue: 'dev',
      description: '要部署的 Git 分支（一般 dev 环境用 dev 分支，sit 用 sit，uat 用 uat；只有一条主干时统一填 main）'
    )
  }

  environment {
    // ---------- Dockerfile 路径 ----------
    DOCKERFILE_STORE    = "alien_store/Dockerfile"
    DOCKERFILE_GATEWAY  = "alien_gateway/Dockerfile"
    DOCKERFILE_CONTRACT = "alien_contract/Dockerfile"

    // ---------- 镜像仓库（如不推远端 Registry 就留空） ----------
    REGISTRY      = ""
    REGISTRY_CRED = "registry-cred-id"

    // ---------- 三环境共用的命名规则：全部以 ${APP_ENV} 区分 ----------
    IMAGE_TAG               = "${params.APP_ENV}-${env.BUILD_NUMBER}"
    IMAGE_STORE             = "${REGISTRY ? REGISTRY + '/' : ''}alien_store:${IMAGE_TAG}"
    IMAGE_GATEWAY           = "${REGISTRY ? REGISTRY + '/' : ''}alien_gateway:${IMAGE_TAG}"
    IMAGE_CONTRACT          = "${REGISTRY ? REGISTRY + '/' : ''}alien_contract:${IMAGE_TAG}"

    CONTAINER_NAME_STORE    = "alien_store_py-${params.APP_ENV}"
    CONTAINER_NAME_GATEWAY  = "alien_gateway_py-${params.APP_ENV}"
    CONTAINER_NAME_CONTRACT = "alien_contract_py-${params.APP_ENV}"

    DOCKER_NET              = "alien_net_${params.APP_ENV}"
    LOG_ROOT                = "/docker/python-${params.APP_ENV}/logs"
  }

  stages {

    stage('Show Build Info') {
      steps {
        echo "============================================================"
        echo " 部署环境  : ${params.APP_ENV}"
        echo " 部署分支  : ${params.BRANCH}"
        echo " 镜像 TAG  : ${IMAGE_TAG}"
        echo " 网络名    : ${DOCKER_NET}"
        echo " 日志根目录: ${LOG_ROOT}"
        echo "============================================================"
      }
    }

    // 注意：使用 "Pipeline script from SCM" 模式时 Jenkins 已自动 checkout
    // 但因为我们参数化了 BRANCH，这里显式 checkout 指定分支
    stage('Checkout') {
      steps {
        checkout([
          $class: 'GitSCM',
          branches: [[name: "*/${params.BRANCH}"]],
          userRemoteConfigs: scm.userRemoteConfigs
        ])
      }
    }

    stage('Load Env Port Mapping') {
      // 从 .env.${APP_ENV} 解析 GATEWAY_PORT，作为 docker -p 宿主端口映射用
      // （容器内监听端口同样靠 Dockerfile 默认 ARG/ENV 与 .env 配合）
      steps {
        script {
          def envFile = ".env.${params.APP_ENV}"
          if (!fileExists(envFile)) {
            error "缺少环境配置文件: ${envFile}（仓库里应该有这份；请检查 .gitignore 是否误屏蔽）"
          }
          def gatewayPort = sh(
            script: "grep -E '^GATEWAY_PORT=' ${envFile} | head -n1 | cut -d= -f2 | tr -d '\"' | tr -d \"'\"",
            returnStdout: true
          ).trim()
          if (!gatewayPort) {
            gatewayPort = "33333"
          }
          env.GATEWAY_PORT = gatewayPort
          echo "从 ${envFile} 解析到 GATEWAY_PORT=${env.GATEWAY_PORT}"
        }
      }
    }

    stage('Build Images') {
      steps {
        script {
          def buildArgs = "--build-arg APP_ENV=${params.APP_ENV}"
          if (env.REGISTRY?.trim()) {
            withDockerRegistry(credentialsId: env.REGISTRY_CRED, url: "") {
              sh "docker build ${buildArgs} -f ${DOCKERFILE_STORE}    -t ${IMAGE_STORE}    ."
              sh "docker build ${buildArgs} -f ${DOCKERFILE_GATEWAY}  -t ${IMAGE_GATEWAY}  ."
              sh "docker build ${buildArgs} -f ${DOCKERFILE_CONTRACT} -t ${IMAGE_CONTRACT} ."
            }
          } else {
            sh "docker build ${buildArgs} -f ${DOCKERFILE_STORE}    -t ${IMAGE_STORE}    ."
            sh "docker build ${buildArgs} -f ${DOCKERFILE_GATEWAY}  -t ${IMAGE_GATEWAY}  ."
            sh "docker build ${buildArgs} -f ${DOCKERFILE_CONTRACT} -t ${IMAGE_CONTRACT} ."
          }
        }
      }
    }

    stage('Push Images') {
      when { expression { return env.REGISTRY?.trim() as boolean } }
      steps {
        withDockerRegistry(credentialsId: env.REGISTRY_CRED, url: "") {
          sh "docker push ${IMAGE_STORE}"
          sh "docker push ${IMAGE_GATEWAY}"
          sh "docker push ${IMAGE_CONTRACT}"
        }
      }
    }

    stage('Deploy') {
      steps {
        script {
          echo ">>> [${params.APP_ENV}] 部署镜像: ${IMAGE_STORE} / ${IMAGE_GATEWAY} / ${IMAGE_CONTRACT}"
          sh """
            set -e

            docker network create ${DOCKER_NET} 2>/dev/null || true
            mkdir -p ${LOG_ROOT}/store ${LOG_ROOT}/gateway ${LOG_ROOT}/contract

            docker rm -f ${CONTAINER_NAME_STORE} ${CONTAINER_NAME_GATEWAY} ${CONTAINER_NAME_CONTRACT} 2>/dev/null || true

            # 1) 下游：store
            #    APP_ENV=${params.APP_ENV} 让 config.py 加载镜像内的 .env.${params.APP_ENV}
            docker run -d --name ${CONTAINER_NAME_STORE} \\
              --network ${DOCKER_NET} \\
              -e APP_ENV=${params.APP_ENV} \\
              -v ${LOG_ROOT}/store:/app/common/logs/alien_store \\
              --restart unless-stopped \\
              ${IMAGE_STORE}

            # 2) 下游：contract
            docker run -d --name ${CONTAINER_NAME_CONTRACT} \\
              --network ${DOCKER_NET} \\
              -e APP_ENV=${params.APP_ENV} \\
              -v ${LOG_ROOT}/contract:/app/common/logs/alien_contract \\
              --restart unless-stopped \\
              ${IMAGE_CONTRACT}

            # 3) 网关：gateway（唯一对外端口，并用 -e 把下游地址覆盖为容器名）
            docker run -d --name ${CONTAINER_NAME_GATEWAY} \\
              --network ${DOCKER_NET} \\
              -p ${env.GATEWAY_PORT}:${env.GATEWAY_PORT} \\
              -e APP_ENV=${params.APP_ENV} \\
              -e STORE_BASE_URL=http://${CONTAINER_NAME_STORE}:8001 \\
              -e CONTRACT_BASE_URL=http://${CONTAINER_NAME_CONTRACT}:8002 \\
              -v ${LOG_ROOT}/gateway:/app/common/logs/alien_gateway \\
              --restart unless-stopped \\
              ${IMAGE_GATEWAY}
          """
        }
      }
    }

    stage('Smoke Test') {
      steps {
        script {
          sh """
            sleep 3
            echo '--- /health ---'
            curl -sf http://127.0.0.1:${env.GATEWAY_PORT}/health || (echo 'gateway /health 失败' && exit 1)
            echo
            echo '--- /health/redis ---'
            curl -sf http://127.0.0.1:${env.GATEWAY_PORT}/health/redis || echo 'redis 健康检查未通过（非阻塞，部署继续）'
          """
        }
      }
    }
  }

  post {
    success {
      echo "[${params.APP_ENV}] 环境部署成功！gateway: http://<host>:${env.GATEWAY_PORT}"
    }
    failure {
      echo "[${params.APP_ENV}] 环境部署失败，请检查上面日志。"
    }
    always {
      cleanWs()
    }
  }
}
