name: Deploy to Production

on:
  workflow_dispatch:
    inputs:
      release:
        description: 'Release version to deploy (e.g., v0.1.20260711, or leave empty for latest)'
        required: false
        type: string

concurrency:
  group: deploy-prod-main
  cancel-in-progress: false

env:
  DEPLOY_HOST: 178.104.200.7
  DEPLOY_USER: kjh2064
  DEPLOY_PORT: 22
  SERVICE_NAME: quantengine
  REPO: kjh2064/QuantEngineByItz

jobs:
  deploy:
    name: Deploy to Production
    runs-on: ubuntu-latest
    timeout-minutes: 30
    outputs:
      release-tag: ${{ steps.fetch.outputs.tag }}
      artifact-name: ${{ steps.fetch.outputs.artifact }}
      commit-hash: ${{ steps.fetch.outputs.commit }}

    steps:
      - name: Verify SSH Key and Secrets
        run: |
          SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}"
          SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}"
          if [ -z "$SSH_KEY_B64" ] && [ -z "$SSH_KEY_RAW" ]; then
            echo "ERROR: DEPLOY_SSH_KEY_B64 or DEPLOY_SSH_KEY not configured"
            exit 1
          fi
          [ -z "${{ secrets.GITEA_TOKEN }}" ] && { echo "ERROR: GITEA_TOKEN not configured"; exit 1; }
          echo "✓ SSH key and GITEA_TOKEN configured"

      - name: Fetch Release Info
        id: fetch
        run: |
          RELEASE_INPUT="${{ github.event.inputs.release }}"
          TOKEN="${{ secrets.GITEA_TOKEN }}"
          REPO="${{ env.REPO }}"

          if [ -z "$RELEASE_INPUT" ]; then
            RELEASE_URL="https://gitea.taxbaik.com/api/v1/repos/$REPO/releases/latest"
          else
            RELEASE_URL="https://gitea.taxbaik.com/api/v1/repos/$REPO/releases/tags/$RELEASE_INPUT"
          fi

          RELEASE=$(curl -sf -H "Authorization: token $TOKEN" "$RELEASE_URL")
          TAG=$(echo "$RELEASE" | jq -r '.tag_name')
          COMMIT=$(echo "$RELEASE" | jq -r '.target_commitish' | cut -c1-7)
          ARTIFACT=$(echo "$RELEASE" | jq -r '.assets[0].name')
          DOWNLOAD_URL=$(echo "$RELEASE" | jq -r '.assets[0].browser_download_url')

          if [ "$TAG" = "null" ] || [ -z "$TAG" ]; then
            echo "ERROR: Release not found"; exit 1
          fi
          if [ "$ARTIFACT" = "null" ] || [ -z "$ARTIFACT" ]; then
            echo "ERROR: No artifacts found in release $TAG"; exit 1
          fi
          if [ "$DOWNLOAD_URL" = "null" ] || [ -z "$DOWNLOAD_URL" ]; then
            echo "ERROR: No browser_download_url found for asset"; exit 1
          fi

          echo "tag=${TAG}" >> $GITHUB_OUTPUT
          echo "artifact=${ARTIFACT}" >> $GITHUB_OUTPUT
          echo "download_url=${DOWNLOAD_URL}" >> $GITHUB_OUTPUT
          echo "commit=${COMMIT}" >> $GITHUB_OUTPUT

          echo "✓ Release: $TAG"
          echo "✓ Artifact: $ARTIFACT"
          echo "✓ Download URL: $DOWNLOAD_URL"

      - name: Download Release Artifact
        run: |
          ARTIFACT="${{ steps.fetch.outputs.artifact }}"
          TOKEN="${{ secrets.GITEA_TOKEN }}"
          DOWNLOAD_URL="${{ steps.fetch.outputs.download_url }}"

          echo "Downloading: $DOWNLOAD_URL"
          curl -sfL -H "Authorization: token $TOKEN" -o "$ARTIFACT" "$DOWNLOAD_URL"

          # A 404/error page would still create a small file -- verify it's a
          # real gzip archive, not an HTML/JSON error body (this is exactly
          # how the old /releases/download/{tag}/{file} guessed URL failed
          # silently: curl exited 0 but wrote a 19-byte "404 page not found").
          file "$ARTIFACT" | grep -q "gzip compressed" || {
            echo "ERROR: Downloaded file is not a valid gzip archive:"
            file "$ARTIFACT"
            cat "$ARTIFACT"
            exit 1
          }

          echo "✓ Downloaded: $(du -sh $ARTIFACT)"

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}"
          SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}"

          if [ -n "$SSH_KEY_B64" ]; then
            printf '%s' "$SSH_KEY_B64" | base64 -d > ~/.ssh/deploy_key
          elif [ -n "$SSH_KEY_RAW" ]; then
            if printf '%s' "$SSH_KEY_RAW" | grep -q 'BEGIN.*PRIVATE KEY'; then
              printf '%b\n' "$SSH_KEY_RAW" > ~/.ssh/deploy_key
            else
              printf '%s' "$SSH_KEY_RAW" | base64 -d > ~/.ssh/deploy_key
            fi
          else
            echo "ERROR: No SSH key configured"
            exit 1
          fi

          sed -i 's/\r$//' ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          ssh-keyscan -p ${{ env.DEPLOY_PORT }} ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
          echo "✓ SSH configured"

      - name: Upload Release Artifact
        run: |
          ARTIFACT="${{ steps.fetch.outputs.artifact }}"
          echo "Uploading: $ARTIFACT"
          ls -lh "$ARTIFACT"

          scp -i ~/.ssh/deploy_key \
            -P ${{ env.DEPLOY_PORT }} \
            -o StrictHostKeyChecking=accept-new \
            "$ARTIFACT" ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/
          echo "✓ Release artifact uploaded"

      - name: Deploy & Verify
        run: |
          ARTIFACT="${{ steps.fetch.outputs.artifact }}"
          RELEASE_TAG="${{ steps.fetch.outputs.tag }}"
          COMMIT="${{ steps.fetch.outputs.commit }}"

          ssh -i ~/.ssh/deploy_key \
            -p ${{ env.DEPLOY_PORT }} \
            -o StrictHostKeyChecking=accept-new \
            ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} bash << 'REMOTE'
          set -e

          ARTIFACT='$ARTIFACT'
          RELEASE_TAG='$RELEASE_TAG'
          COMMIT='$COMMIT'
          DEPLOY_HOME=$HOME
          DEPLOY_DIR="$DEPLOY_HOME/deployments/quantengine_${RELEASE_TAG}_${COMMIT}"

          echo "=== Deployment Start ==="
          echo "Release: $RELEASE_TAG"
          echo "Artifact: $ARTIFACT"
          echo "Commit: $COMMIT"
          echo "Deploy Dir: $DEPLOY_DIR"
          echo ""

          # 1. Extract
          echo "【 1/4 Extract Artifact 】"
          mkdir -p "$DEPLOY_DIR"
          tar -xzf "/tmp/$ARTIFACT" -C "$DEPLOY_DIR"
          rm -f "/tmp/$ARTIFACT"
          echo "✓ Extraction complete"

          # 2. Verify
          echo ""
          echo "【 2/4 Verify Deployment 】"
          if [ ! -f "$DEPLOY_DIR/QuantEngine.Web.dll" ]; then
            echo "ERROR: QuantEngine.Web.dll not found"
            exit 1
          fi
          if [ ! -f "$DEPLOY_DIR/appsettings.Production.json" ]; then
            echo "ERROR: appsettings.Production.json not found"
            exit 1
          fi
          echo "✓ DLL verified"
          echo "✓ Config verified"

          # 3. Update Symlink
          echo ""
          echo "【 3/4 Update Symlink 】"
          ln -sfn "$DEPLOY_DIR" "$DEPLOY_HOME/quantengine_active"
          echo "✓ Active: $(readlink $DEPLOY_HOME/quantengine_active)"

          # 4. Restart Service
          echo ""
          echo "【 4/4 Restart Service 】"
          sudo systemctl restart $SERVICE_NAME
          echo "✓ Service restarted"

          REMOTE

  post-deploy-check:
    name: Health Check & Verification
    runs-on: ubuntu-latest
    needs: deploy
    timeout-minutes: 10

    steps:
      - name: Setup SSH (for service check)
        run: |
          mkdir -p ~/.ssh
          SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}"
          SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}"

          if [ -n "$SSH_KEY_B64" ]; then
            printf '%s' "$SSH_KEY_B64" | base64 -d > ~/.ssh/deploy_key
          elif [ -n "$SSH_KEY_RAW" ]; then
            printf '%s' "$SSH_KEY_RAW" | base64 -d > ~/.ssh/deploy_key
          fi

          chmod 600 ~/.ssh/deploy_key 2>/dev/null || true
          ssh-keyscan -p 22 ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Health Check
        run: |
          set -e
          ATTEMPTS=20
          DEPLOY_HOST="${{ env.DEPLOY_HOST }}"

          echo "【 Health Checks (max ${ATTEMPTS} attempts) 】"

          for i in $(seq 1 $ATTEMPTS); do
            # Check 1: HTTP 200
            HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://$DEPLOY_HOST:5000/Account/Login 2>/dev/null || echo "000")
            if [ "$HTTP_CODE" = "200" ]; then
              echo "✓ [1/5] HTTP 200 OK (attempt $i)"

              # Check 2: Login Page
              LOGIN_BODY=$(curl -s http://$DEPLOY_HOST:5000/Account/Login 2>/dev/null || echo "")
              if echo "$LOGIN_BODY" | grep -q "login\|Login\|로그인"; then
                echo "✓ [2/5] Login page content verified"
              else
                echo "⚠ [2/5] Login page content verification skipped"
              fi

              # Check 3: CSS loaded
              CSS_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://$DEPLOY_HOST:5000/css/admin.css 2>/dev/null || echo "000")
              if [ "$CSS_CODE" = "200" ]; then
                echo "✓ [3/5] CSS file loaded"
              else
                echo "⚠ [3/5] CSS file check skipped (status: $CSS_CODE)"
              fi

              # Check 4: Service active
              SERVICE_STATUS=$(ssh -i ~/.ssh/deploy_key \
                -p 22 \
                -o StrictHostKeyChecking=accept-new \
                kjh2064@$DEPLOY_HOST \
                "systemctl is-active quantengine" 2>/dev/null || echo "unknown")
              if [ "$SERVICE_STATUS" = "active" ]; then
                echo "✓ [4/5] Service active (running)"
              else
                echo "⚠ [4/5] Service status: $SERVICE_STATUS"
              fi

              # Check 5: Release verified
              echo "✓ [5/5] Deployment release: ${{ needs.deploy.outputs.release-tag }} (commit: ${{ needs.deploy.outputs.commit-hash }})"

              # Check 6: DB connectivity (GET /Account/Login returns 200 even when
              # the DB password is stale -- the page itself has no DB dependency.
              # Only an actual login POST, or the app logs, reveal a broken
              # connection string. See CLAUDE.md "DB Secret Management" incident
              # 2026-07-12: this check would have caught it, the HTTP check alone
              # did not.)
              sleep 2
              DB_ERRORS=$(ssh -i ~/.ssh/deploy_key \
                -p 22 \
                -o StrictHostKeyChecking=accept-new \
                kjh2064@$DEPLOY_HOST \
                "journalctl -u quantengine --since '1 minute ago' --no-pager 2>/dev/null | grep -c '28P01\|password authentication failed'" || echo "0")
              if [ "$DB_ERRORS" = "0" ]; then
                echo "✓ [6/6] No DB authentication errors in recent logs"
              else
                echo "❌ [6/6] DB authentication errors found in logs ($DB_ERRORS occurrences)"
                echo ""
                echo "❌ FAILED: Deployment reachable over HTTP but DB connection is broken"
                exit 1
              fi

              echo ""
              echo "✅ All health checks passed!"
              exit 0
            fi

            if [ $i -lt $ATTEMPTS ]; then
              echo "  Attempt $i/$ATTEMPTS... (HTTP $HTTP_CODE, retrying in 3s)"
              sleep 3
            else
              echo ""
              echo "❌ FAILED: Service did not respond after $ATTEMPTS attempts"
              exit 1
            fi
          done

  post-deploy-report:
    name: Deployment Report
    runs-on: ubuntu-latest
    if: always()
    needs: [ deploy, post-deploy-check ]

    steps:
      - name: Report Status
        run: |
          RELEASE="${{ needs.deploy.outputs.release-tag }}"
          COMMIT="${{ needs.deploy.outputs.commit-hash }}"
          ARTIFACT="${{ needs.deploy.outputs.artifact-name }}"
          DEPLOY_STATUS="${{ needs.deploy.result }}"
          CHECK_STATUS="${{ needs.post-deploy-check.result }}"

          echo "╔════════════════════════════════════════════╗"
          echo "║      Deployment Report                     ║"
          echo "╚════════════════════════════════════════════╝"
          echo ""
          echo "Release: $RELEASE"
          echo "Commit: $COMMIT"
          echo "Artifact: $ARTIFACT"
          echo ""
          echo "【 Status 】"
          echo "Deploy: $([ "$DEPLOY_STATUS" = "success" ] && echo "✓" || echo "✗") $DEPLOY_STATUS"
          echo "Health: $([ "$CHECK_STATUS" = "success" ] && echo "✓" || echo "✗") $CHECK_STATUS"
          echo ""

          if [ "$DEPLOY_STATUS" = "success" ] && [ "$CHECK_STATUS" = "success" ]; then
            echo "✅ Deployment Successful"
            echo "Server: 178.104.200.7"
            echo "Release: $RELEASE"
            exit 0
          else
            echo "❌ Deployment Failed"
            exit 1
          fi
