# ─────────────────────────────────────────────────────────────────────────────
# GitHub Actions Deploy Pipeline – Claude Code Agent Monitor
#
# Triggers on version tags and manual dispatch. Deploys to staging
# automatically and to production after manual approval.
# ─────────────────────────────────────────────────────────────────────────────
name: Deploy

on:
  push:
    tags:
      - "v*"
  workflow_dispatch:
    inputs:
      environment:
        description: "Target environment"
        required: true
        type: choice
        options:
          - staging
          - production
      image_tag:
        description: "Image tag to deploy (default: latest from main)"
        required: false
        type: string

permissions:
  contents: read
  packages: read
  id-token: write # For OIDC cloud auth

concurrency:
  group: deploy-${{ github.event.inputs.environment || 'staging' }}
  cancel-in-progress: false

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}/agent-monitor
  MCP_IMAGE_NAME: ${{ github.repository }}/agent-monitor-mcp
  HELM_CHART_PATH: deployments/helm/agent-monitor

jobs:
  # ── Resolve image tag ──────────────────────────────────────────────────
  prepare:
    name: Prepare Deployment
    runs-on: ubuntu-latest
    outputs:
      image-tag: ${{ steps.resolve.outputs.tag }}
      version: ${{ steps.resolve.outputs.version }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Resolve image tag
        id: resolve
        run: |
          if [[ -n "${{ github.event.inputs.image_tag }}" ]]; then
            TAG="${{ github.event.inputs.image_tag }}"
          elif [[ "${{ github.ref_type }}" == "tag" ]]; then
            TAG="${{ github.ref_name }}"
          else
            TAG="sha-$(git rev-parse --short HEAD)"
          fi
          echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
          echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
          echo "Resolved image tag: ${TAG}"

  # ── Build (if triggered by tag) ────────────────────────────────────────
  build:
    name: Build Images
    runs-on: ubuntu-latest
    needs: prepare
    if: github.ref_type == 'tag'
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build & push app image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image-tag }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64

      - name: Build & push MCP image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./mcp/Dockerfile
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.MCP_IMAGE_NAME }}:${{ needs.prepare.outputs.image-tag }}
            ${{ env.REGISTRY }}/${{ env.MCP_IMAGE_NAME }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64

  # ── Deploy to Staging ──────────────────────────────────────────────────
  deploy-staging:
    name: Deploy to Staging
    runs-on: ubuntu-latest
    needs: [prepare, build]
    if: |
      always() &&
      needs.prepare.result == 'success' &&
      (needs.build.result == 'success' || needs.build.result == 'skipped') &&
      (github.event.inputs.environment == 'staging' || github.event.inputs.environment == '' || github.ref_type == 'tag')
    environment:
      name: staging
      url: https://staging.agent-monitor.example.com
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_STAGING }}
          aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}

      - name: Setup kubectl
        uses: azure/setup-kubectl@v3
        with:
          version: "v1.29.0"

      - name: Setup Helm
        uses: azure/setup-helm@v4
        with:
          version: "v3.14.0"

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig \
            --region ${{ vars.AWS_REGION || 'us-west-2' }} \
            --name ${{ vars.EKS_CLUSTER_STAGING || 'agent-monitor-staging' }}

      - name: Deploy to staging via Helm
        run: |
          helm upgrade --install agent-monitor ${{ env.HELM_CHART_PATH }} \
            --namespace agent-monitor-staging \
            --create-namespace \
            --set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
            --set image.tag=${{ needs.prepare.outputs.image-tag }} \
            --set mcp.image.repository=${{ env.REGISTRY }}/${{ env.MCP_IMAGE_NAME }} \
            --set mcp.image.tag=${{ needs.prepare.outputs.image-tag }} \
            --set environment=staging \
            --set ingress.host=staging.agent-monitor.example.com \
            --values ${{ env.HELM_CHART_PATH }}/values-staging.yaml \
            --wait \
            --atomic \
            --timeout 600s

      - name: Health check
        run: |
          echo "Waiting for pods to be ready..."
          kubectl wait --for=condition=ready pod \
            -l app.kubernetes.io/name=agent-monitor \
            -n agent-monitor-staging \
            --timeout=300s

          # Port forward and check health
          kubectl port-forward svc/agent-monitor 14820:4820 -n agent-monitor-staging &
          PF_PID=$!
          sleep 5

          for i in $(seq 1 10); do
            if curl -sf http://localhost:14820/api/health | grep -q '"status":"ok"'; then
              echo "✔ Health check passed"
              kill $PF_PID 2>/dev/null || true
              exit 0
            fi
            echo "Attempt $i/10..."
            sleep 5
          done

          kill $PF_PID 2>/dev/null || true
          echo "✖ Health check failed"
          exit 1

      - name: Notify Slack (staging)
        if: always()
        uses: slackapi/slack-github-action@v1.26.0
        with:
          payload: |
            {
              "text": "${{ job.status == 'success' && '✅' || '❌' }} Staging deployment ${{ job.status }}: `${{ needs.prepare.outputs.image-tag }}`",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "${{ job.status == 'success' && ':white_check_mark:' || ':x:' }} *Staging Deployment ${{ job.status }}*\n*Image:* `${{ needs.prepare.outputs.image-tag }}`\n*Commit:* `${{ github.sha }}`\n*Actor:* ${{ github.actor }}"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

  # ── Deploy to Production ───────────────────────────────────────────────
  deploy-production:
    name: Deploy to Production
    runs-on: ubuntu-latest
    needs: [prepare, deploy-staging]
    if: |
      always() &&
      needs.prepare.result == 'success' &&
      needs.deploy-staging.result == 'success' &&
      (github.event.inputs.environment == 'production' || github.ref_type == 'tag')
    environment:
      name: production
      url: https://agent-monitor.example.com
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_PRODUCTION }}
          aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}

      - name: Setup kubectl
        uses: azure/setup-kubectl@v3
        with:
          version: "v1.29.0"

      - name: Setup Helm
        uses: azure/setup-helm@v4
        with:
          version: "v3.14.0"

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig \
            --region ${{ vars.AWS_REGION || 'us-west-2' }} \
            --name ${{ vars.EKS_CLUSTER_PRODUCTION || 'agent-monitor-production' }}

      - name: Create database backup
        run: |
          chmod +x deployments/scripts/db-backup.sh
          # Find a running pod to backup from
          POD=$(kubectl get pods -n agent-monitor-production \
            -l app.kubernetes.io/name=agent-monitor \
            --field-selector=status.phase=Running \
            -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")

          if [[ -n "$POD" ]]; then
            echo "Backing up database from pod: $POD"
            kubectl exec "$POD" -n agent-monitor-production -- \
              sh -c "cp /app/data/dashboard.db /tmp/pre-deploy-backup.db 2>/dev/null || true"
            echo "Pre-deploy backup created"
          else
            echo "⚠ No running pods found – skipping backup"
          fi

      - name: Deploy to production via Helm
        run: |
          helm upgrade --install agent-monitor ${{ env.HELM_CHART_PATH }} \
            --namespace agent-monitor-production \
            --create-namespace \
            --set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
            --set image.tag=${{ needs.prepare.outputs.image-tag }} \
            --set mcp.image.repository=${{ env.REGISTRY }}/${{ env.MCP_IMAGE_NAME }} \
            --set mcp.image.tag=${{ needs.prepare.outputs.image-tag }} \
            --set environment=production \
            --set ingress.host=agent-monitor.example.com \
            --values ${{ env.HELM_CHART_PATH }}/values-production.yaml \
            --wait \
            --atomic \
            --timeout 600s

      - name: Health check
        run: |
          echo "Waiting for pods to be ready..."
          kubectl wait --for=condition=ready pod \
            -l app.kubernetes.io/name=agent-monitor \
            -n agent-monitor-production \
            --timeout=300s

          kubectl port-forward svc/agent-monitor 14820:4820 -n agent-monitor-production &
          PF_PID=$!
          sleep 5

          for i in $(seq 1 15); do
            if curl -sf http://localhost:14820/api/health | grep -q '"status":"ok"'; then
              echo "✔ Production health check passed"
              kill $PF_PID 2>/dev/null || true
              exit 0
            fi
            echo "Attempt $i/15..."
            sleep 5
          done

          kill $PF_PID 2>/dev/null || true
          echo "✖ Production health check failed!"
          exit 1

      - name: Notify Slack (production)
        if: always()
        uses: slackapi/slack-github-action@v1.26.0
        with:
          payload: |
            {
              "text": "${{ job.status == 'success' && '🚀' || '🚨' }} Production deployment ${{ job.status }}: `${{ needs.prepare.outputs.image-tag }}`",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "${{ job.status == 'success' && ':rocket:' || ':rotating_light:' }} *Production Deployment ${{ job.status }}*\n*Image:* `${{ needs.prepare.outputs.image-tag }}`\n*Version:* `${{ needs.prepare.outputs.version }}`\n*Commit:* `${{ github.sha }}`\n*Actor:* ${{ github.actor }}\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
