name: Release Baron SSO to Production

on:
  workflow_dispatch:
    inputs:
      rc_version_tag:
        description: "The version tag to release to production (e.g., v1.2601.1-RC1)"
        required: true
        type: string

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

      - name: Login to Harbor Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ vars.HARBOR_ENDPOINT }}
          username: ${{ vars.HARBOR_ROBOT_ACCOUNT }}
          password: ${{ secrets.HARBOR_ROBOT_KEY }}

      - name: Parse RC and re-tag to final
        id: retag
        env:
          HARBOR_HOSTNAME: ${{ vars.HARBOR_HOSTNAME }}
          HARBOR_USER: ${{ vars.HARBOR_ROBOT_ACCOUNT }}
          HARBOR_PASSWORD: ${{ secrets.HARBOR_ROBOT_KEY }}
        run: |
          BASE_TAG=$(echo "${{ github.event.inputs.rc_version_tag }}" | xargs)

          if [[ ! "$BASE_TAG" =~ ^v[0-9]+\.[0-9]{4}\.[0-9]+-RC[0-9]+$ ]]; then
            echo "::error::rc_version_tag must look like vX.YYMM.Z-RC## (got: $BASE_TAG)"
            exit 1
          fi
          RE_TAG="${BASE_TAG%-RC*}"
          echo "Final tag will be: ${RE_TAG}"

          if ! command -v skopeo >/dev/null 2>&1; then
            sudo apt-get update -y && sudo apt-get install -y skopeo
          fi

          for image in backend userfront adminfront devfront orgfront; do
            echo "Re-tagging ${image} image..."
            skopeo copy --preserve-digests \
                        --src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \
                        --src-tls-verify=false --dest-tls-verify=false \
                        "docker://${HARBOR_HOSTNAME}/baron_sso/${image}:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/${image}:${RE_TAG}"
          done

          echo "final_image_tag=${RE_TAG}" >> "$GITHUB_OUTPUT"

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

      - name: Deploy to Production
        env:
          IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }}
          BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
          USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront
          ADMINFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront
          DEVFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront
          ORGFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/orgfront
          DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }}
          PROD_HOST: ${{ vars.PROD_HOST }}
          PROD_USER: ${{ vars.PROD_USER }}
          HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }}
          HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }}
          HARBOR_ROBOT_KEY: ${{ secrets.HARBOR_ROBOT_KEY }}
        run: |
          set -euo pipefail

          echo "DEBUG: PROD_USER='${PROD_USER}'"
          echo "DEBUG: PROD_HOST='${PROD_HOST}'"
          echo "DEBUG: DEPLOY_PATH='${DEPLOY_PATH}'"

          # Sanity check (fail fast with a clear message)
          if [ -z "${PROD_USER}" ] || [ -z "${PROD_HOST}" ] || [ -z "${DEPLOY_PATH}" ]; then
            echo "::error::Missing required vars (PROD_USER/PROD_HOST/DEPLOY_PATH). Check Gitea repo variables."
            exit 1
          fi

          ssh-keyscan -H "${PROD_HOST}" >> ~/.ssh/known_hosts

          ssh "${PROD_USER}@${PROD_HOST}" "mkdir -p '${DEPLOY_PATH}/adminfront'"

          # Create the main .env file for Baron SSO on the remote server
          # Note: All values are pulled from Gitea secrets and variables
          printf '%s\n' \
            "APP_ENV=production" \
            "TZ=Asia/Seoul" \
            "DB_PORT=${{ vars.PROD_DB_PORT }}" \
            "CLICKHOUSE_PORT_HTTP=${{ vars.PROD_CLICKHOUSE_PORT_HTTP }}" \
            "CLICKHOUSE_PORT_NATIVE=${{ vars.PROD_CLICKHOUSE_PORT_NATIVE }}" \
            "CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \
            "CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \
            "PROD_BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \
            "BACKEND_PORT=3000" \
            "USERFRONT_PORT=${{ vars.PROD_FRONTEND_PORT }}" \
            "ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}" \
            "DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}" \
            "ORGFRONT_PORT=${{ vars.ORGFRONT_PORT }}" \
            "DB_USER=${{ vars.PROD_DB_USER }}" \
            "DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
            "DB_NAME=${{ vars.PROD_DB_NAME }}" \
            "COOKIE_SECRET=${{ secrets.PROD_COOKIE_SECRET }}" \
            "JWT_SECRET=${{ secrets.PROD_JWT_SECRET }}" \
            "REDIS_ADDR=${{ vars.PROD_REDIS_ADDR }}" \
            "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 }}" \
            "USERFRONT_URL=${{ vars.PROD_FRONTEND_URL }}" \
            "ADMINFRONT_URL=${{ vars.ADMINFRONT_URL }}" \
            "DEVFRONT_URL=${{ vars.DEVFRONT_URL }}" \
            "ORGFRONT_URL=${{ vars.ORGFRONT_URL }}" \
            "BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \
            "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 }}" \
            > .env

          required_dotenv_keys="
          APP_ENV TZ DB_PORT CLICKHOUSE_PORT_HTTP CLICKHOUSE_PORT_NATIVE CLICKHOUSE_USER CLICKHOUSE_PASSWORD
          PROD_BACKEND_PORT BACKEND_PORT USERFRONT_PORT ADMINFRONT_PORT DEVFRONT_PORT ORGFRONT_PORT
          DB_USER DB_PASSWORD DB_NAME COOKIE_SECRET JWT_SECRET REDIS_ADDR
          NAVER_CLOUD_ACCESS_KEY NAVER_CLOUD_SECRET_KEY NAVER_CLOUD_SERVICE_ID NAVER_SENDER_PHONE_NUMBER
          AWS_REGION AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SES_SENDER
          USERFRONT_URL ADMINFRONT_URL DEVFRONT_URL ORGFRONT_URL BACKEND_URL VITE_OIDC_AUTHORITY
          ADMINFRONT_CALLBACK_URLS DEVFRONT_CALLBACK_URLS ORGFRONT_CALLBACK_URLS
          "
          for key in ${required_dotenv_keys}; do
            if ! grep -Eq "^${key}=.+" .env; then
              echo "::error::Missing required production .env value: ${key}. Check Gitea repo variables/secrets."
              exit 1
            fi
          done

          # Copy compose template and .env file to the remote server
          scp adminfront/seed-tenant.csv "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/adminfront/"
          scp docker/docker-compose.template.yaml .env "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/"
          scp docker/compose.infra.prd.yaml "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/compose.infra.yml"

          # Deploy Baron SSO
          echo "${HARBOR_ROBOT_KEY}" | ssh "${PROD_USER}@${PROD_HOST}" \
            "export DEPLOY_PATH='${DEPLOY_PATH}'; \
             export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \
             export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \
             export ADMINFRONT_IMAGE_NAME='${ADMINFRONT_IMAGE_NAME}'; \
             export DEVFRONT_IMAGE_NAME='${DEVFRONT_IMAGE_NAME}'; \
             export ORGFRONT_IMAGE_NAME='${ORGFRONT_IMAGE_NAME}'; \
             export IMAGE_TAG='${IMAGE_TAG}'; \
             export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \
             export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \
             set -e; \
             cd \"\${DEPLOY_PATH}\"; \
             docker login \"\${HARBOR_ENDPOINT}\" -u \"\${HARBOR_ROBOT_ACCOUNT}\" --password-stdin; \
             set -a; \
             . ./.env; \
             set +a; \
             envsubst < docker-compose.template.yaml > docker-compose.yml; \
             docker compose -f compose.infra.yml -f docker-compose.yml pull; \
             docker compose -f compose.infra.yml -f docker-compose.yml up -d --remove-orphans"
