name: Release Baron SSO to Staging

on:
    workflow_dispatch:
        inputs:
            target_branch:
                description: "Branch to deploy"
                required: true
                default: "dev"

jobs:
    deploy-staging:
        runs-on: ubuntu-latest
        steps:
            - name: Checkout code
              uses: actions/checkout@v4

            - name: Setup SSH
              uses: webfactory/ssh-agent@v0.9.0
              with:
                  ssh-private-key: ${{ secrets.STAGE_SSH_PRIVATE_KEY }}

            - name: Deploy to Staging by git pull
              env:
                  DEPLOY_PATH: ${{ vars.STAGE_DEPLOY_PATH }}
                  STAGE_HOST: ${{ vars.STAGE_HOST }}
                  STAGE_USER: ${{ vars.STAGE_USER }}
                  TARGET_BRANCH: ${{ inputs.target_branch }}
              run: |
                  set -euo pipefail

                  echo "DEBUG: STAGE_USER='${STAGE_USER}'"
                  echo "DEBUG: STAGE_HOST='${STAGE_HOST}'"
                  echo "DEBUG: DEPLOY_PATH='${DEPLOY_PATH}'"
                  echo "DEBUG: TARGET_BRANCH='${TARGET_BRANCH}'"

                  # Sanity check
                  if [ -z "${STAGE_USER}" ] || [ -z "${STAGE_HOST}" ] || [ -z "${DEPLOY_PATH}" ] || [ -z "${TARGET_BRANCH}" ]; then
                    echo "::error::Missing required vars (STAGE_USER/STAGE_HOST/DEPLOY_PATH/TARGET_BRANCH)."
                    exit 1
                  fi

                  ssh-keyscan -H "${STAGE_HOST}" >> ~/.ssh/known_hosts
                  ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p '${DEPLOY_PATH}'"

                  # .env 파일 생성
                  cat <<'EOF' > .env
                  APP_ENV=stage
                  BACKEND_LOG_LEVEL=debug
                  CLIENT_LOG_DEBUG=true
                  TZ=Asia/Seoul
                  IDP_PROVIDER=ory

                  # DB & Clickhouse
                  DB_PORT=${{ vars.DB_PORT }}
                  CLICKHOUSE_PORT_HTTP=${{ vars.CLICKHOUSE_PORT_HTTP }}
                  CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }}
                  CLICKHOUSE_HOST=${{ vars.CLICKHOUSE_HOST }}
                  CLICKHOUSE_USER=${{ vars.CLICKHOUSE_USER }}
                  CLICKHOUSE_PASSWORD=${{ secrets.CLICKHOUSE_PASSWORD }}


                  BACKEND_PORT=${{ vars.BACKEND_PORT }}
                  ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}
                  DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}
                  ORGFRONT_PORT=${{ vars.ORGFRONT_PORT }}
                  USERFRONT_PORT=${{ vars.USERFRONT_PORT }}

                  OATHKEEPER_API_URL=${{ vars.OATHKEEPER_API_URL }}

                  DB_USER=${{ vars.DB_USER }}
                  DB_PASSWORD=${{ secrets.STG_DB_PASSWORD }}
                  DB_NAME=${{ vars.DB_NAME }}
                  COOKIE_SECRET=${{ secrets.STG_COOKIE_SECRET }}
                  JWT_SECRET=${{ secrets.STG_JWT_SECRET }}
                  REDIS_ADDR=${{ vars.REDIS_ADDR }}
                  CORS_ALLOWED_ORIGINS=${{ vars.CORS_ALLOWED_ORIGINS }}
                  AUDIT_WORKER_COUNT=5
                  AUDIT_QUEUE_SIZE=2000
                  PROFILE_CACHE_TTL=${{ vars.PROFILE_CACHE_TTL }}
                  NAVER_CLOUD_ACCESS_KEY=${{ vars.NAVER_CLOUD_ACCESS_KEY }}
                  NAVER_CLOUD_SECRET_KEY=${{ secrets.NAVER_CLOUD_SECRET_KEY }}
                  NAVER_CLOUD_SERVICE_ID=${{ vars.NAVER_CLOUD_SERVICE_ID }}
                  NAVER_SENDER_PHONE_NUMBER=${{ vars.NAVER_SENDER_PHONE_NUMBER }}
                  AWS_REGION=${{ vars.AWS_REGION }}
                  AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}
                  AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
                  AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}
                  ADMIN_EMAIL=${{ vars.ADMIN_EMAIL }}
                  ADMIN_PASSWORD=${{ secrets.STG_ADMIN_PASSWORD }}
                  USERFRONT_URL=${{ vars.USERFRONT_URL }}
                  ADMINFRONT_URL=${{ vars.ADMINFRONT_URL }}
                  DEVFRONT_URL=${{ vars.DEVFRONT_URL }}
                  ORGFRONT_URL=${{ vars.ORGFRONT_URL }}
                  BACKEND_PUBLIC_URL=${{ vars.BACKEND_URL }}
                  BACKEND_URL=${{ vars.BACKEND_URL }}
                  OATHKEEPER_PUBLIC_URL=${{ vars.OATHKEEPER_PUBLIC_URL }}
                  ORY_POSTGRES_TAG=${{ vars.ORY_POSTGRES_TAG }}
                  ORY_POSTGRES_USER=${{ vars.ORY_POSTGRES_USER }}
                  ORY_POSTGRES_PASSWORD=${{ secrets.STG_ORY_POSTGRES_PASSWORD }}
                  ORY_POSTGRES_DB=${{ vars.ORY_POSTGRES_DB }}
                  KRATOS_DB=${{ vars.KRATOS_DB }}
                  HYDRA_DB=${{ vars.HYDRA_DB }}
                  KETO_DB=${{ vars.KETO_DB }}
                  KRATOS_VERSION=${{ vars.KRATOS_VERSION }}
                  KRATOS_UI_NODE_VERSION=${{ vars.KRATOS_UI_NODE_VERSION }}
                  HYDRA_VERSION=${{ vars.HYDRA_VERSION }}
                  KETO_VERSION=${{ vars.KETO_VERSION }}
                  ORY_SDK_URL=${{ vars.ORY_SDK_URL }}
                  KRATOS_PUBLIC_URL=${{ vars.KRATOS_PUBLIC_URL }}
                  KRATOS_ADMIN_URL=${{ vars.KRATOS_ADMIN_URL }}
                  KRATOS_BROWSER_URL=${{ vars.KRATOS_BROWSER_URL }}
                  KRATOS_UI_URL=${{ vars.KRATOS_UI_URL }}
                  HYDRA_ADMIN_URL=${{ vars.HYDRA_ADMIN_URL }}
                  HYDRA_PUBLIC_URL=${{ vars.HYDRA_PUBLIC_URL }}
                  JWKS_URL=${{ vars.JWKS_URL }}
                  OATHKEEPER_VERSION=${{ vars.OATHKEEPER_VERSION }}
                  OATHKEEPER_UID=${{ vars.OATHKEEPER_UID }}
                  OATHKEEPER_GID=${{ vars.OATHKEEPER_GID }}
                  OATHKEEPER_HEALTH_URL=${{ vars.OATHKEEPER_HEALTH_URL }}
                  OATHKEEPER_HEALTH_INTERVAL_SECONDS=${{ vars.OATHKEEPER_HEALTH_INTERVAL_SECONDS }}
                  OATHKEEPER_HEALTH_TIMEOUT_SECONDS=${{ vars.OATHKEEPER_HEALTH_TIMEOUT_SECONDS }}
                  OATHKEEPER_HEALTH_ENABLED=${{ vars.OATHKEEPER_HEALTH_ENABLED }}
                  CSRF_COOKIE_NAME=${{ vars.CSRF_COOKIE_NAME }}
                  CSRF_COOKIE_SECRET=${{ secrets.STG_CSRF_COOKIE_SECRET }}

                  # Frontend/Ory URL configs for Staging
                  VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
                  ADMINFRONT_CALLBACK_URLS=${{ vars.ADMINFRONT_CALLBACK_URLS }}
                  DEVFRONT_CALLBACK_URLS=${{ vars.DEVFRONT_CALLBACK_URLS }}
                  ORGFRONT_CALLBACK_URLS=${{ vars.ORGFRONT_CALLBACK_URLS }}
                  KRATOS_ALLOWED_RETURN_URLS_JSON=${{ vars.KRATOS_ALLOWED_RETURN_URLS_JSON }}
                  KRATOS_ALLOWED_RETURN_URLS_EXTRA=${{ vars.KRATOS_ALLOWED_RETURN_URLS_EXTRA }}
                  # OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}
                  # OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
                  EOF

                  # 코드 업데이트 (Git)
                  ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p '${DEPLOY_PATH}' && cd '${DEPLOY_PATH}' && \
                  if [ ! -d .git ]; then
                    git init
                    git remote add origin  ssh://git@172.16.10.175:222/baron/baron-sso.git
                  else
                    git remote set-url origin  ssh://git@172.16.10.175:222/baron/baron-sso.git
                  fi
                  git fetch --depth 1 origin '${TARGET_BRANCH}' && \
                  git reset --hard FETCH_HEAD && \
                  git clean -fd && \
                  git checkout -B '${TARGET_BRANCH}' FETCH_HEAD"

                  # .env 파일 복사
                  scp .env "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/"

                  # 배포 실행
                  ssh "${STAGE_USER}@${STAGE_HOST}" "DEPLOY_PATH='${DEPLOY_PATH}' bash -s" <<'EOSSH'
                  set -euo pipefail
                  cd "${DEPLOY_PATH}"
                  set -a; . ./.env; set +a;

                  # 네트워크 생성
                  for net in baron_net public_net ory-net hydranet kratosnet; do
                    docker network inspect "${net}" >/dev/null 2>&1 || docker network create "${net}"
                  done


                  # Ory 컨테이너가 직접 읽는 설정은 env 기반으로 완성한 뒤 mount합니다.
                  bash scripts/render_ory_config.sh
                  chmod -R 777 config/.generated/ory || true

                  cp docker/staging_pull_compose.template.yaml staging_pull_compose.yaml

                  docker compose -f staging_pull_compose.yaml pull

                  # 코드 변경 반영을 위해 build 수행 (userfront nginx.conf 등)
                  docker compose -f staging_pull_compose.yaml build --pull

                  docker compose -f staging_pull_compose.yaml up -d --remove-orphans --renew-anon-volumes
                  docker compose -f staging_pull_compose.yaml up -d --force-recreate kratos hydra keto oathkeeper
                  docker compose -f staging_pull_compose.yaml up -d --force-recreate ory_stack_check
                  docker compose -f staging_pull_compose.yaml up -d init-rp

                  # 배포 후 상태 확인 (실패 시 로그 출력을 위함)
                  sleep 10

                  check_container_http() {
                    name="$1"
                    port="$2"
                    max="${FRONTEND_HEALTH_MAX_ATTEMPTS:-60}"
                    i=1
                    while [ "${i}" -le "${max}" ]; do
                      if docker exec "${name}" node -e "fetch('http://127.0.0.1:${port}/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" >/dev/null 2>&1; then
                        echo "Frontend ready: ${name}:${port}"
                        return 0
                      fi
                      echo "Waiting for frontend: ${name}:${port} (${i}/${max})"
                      i=$((i + 1))
                      sleep 2
                    done
                    echo "ERROR: frontend not ready: ${name}:${port}" >&2
                    docker logs "${name}" --tail 200 >&2 || true
                    return 1
                  }

                  check_container_http baron_adminfront 5173
                  check_container_http baron_devfront 5173
                  check_container_http baron_orgfront 5175
                  
                  echo "===== INIT-RP LOGS ====="
                  docker compose -f staging_pull_compose.yaml logs init-rp || true
                  echo "========================"
                  
                  kratos_migrate_cid="$(docker compose -f staging_pull_compose.yaml ps -q kratos-migrate || true)"
                  if [ -n "${kratos_migrate_cid}" ]; then
                    if [ "$(docker inspect -f '{{.State.ExitCode}}' "${kratos_migrate_cid}")" -ne 0 ]; then
                       echo 'Kratos Migrate Failed. Logs:'
                       docker logs "${kratos_migrate_cid}"
                       exit 1
                    fi
                  else
                    echo "WARN: kratos-migrate container not found; skipping exit-code check."
                  fi
                  EOSSH
