name: Deploy

on:
  push:
    branches: [main]

env:
  AWS_REGION: eu-central-1
  S3_BUCKET: filamenteka-frontend
  INSTANCE_ID: i-03956ecf32292d7d9
  NEXT_PUBLIC_API_URL: https://api.filamenteka.rs/api
  NEXT_PUBLIC_MATOMO_URL: https://analytics.demirix.dev
  NEXT_PUBLIC_MATOMO_SITE_ID: "7"

jobs:
  # ── Job 1: Change Detection ──────────────────────────────────────────
  detect:
    runs-on: ubuntu-latest
    outputs:
      frontend: ${{ steps.changes.outputs.frontend }}
      api: ${{ steps.changes.outputs.api }}
      migrations: ${{ steps.changes.outputs.migrations }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Detect changes since last deploy
        id: changes
        run: |
          # Find the latest deploy tag
          LAST_TAG=$(git tag -l 'deploy-*' --sort=-creatordate | head -n 1)

          if [ -z "$LAST_TAG" ]; then
            echo "No deploy tag found — deploying everything"
            echo "frontend=true" >> $GITHUB_OUTPUT
            echo "api=true" >> $GITHUB_OUTPUT
            echo "migrations=true" >> $GITHUB_OUTPUT
            exit 0
          fi

          echo "Last deploy tag: $LAST_TAG"
          DIFF_FILES=$(git diff --name-only "$LAST_TAG"..HEAD)
          echo "Changed files since $LAST_TAG:"
          echo "$DIFF_FILES"

          FRONTEND=false
          API=false
          MIGRATIONS=false

          if echo "$DIFF_FILES" | grep -qvE '^(api/|database/)'; then
            FRONTEND=true
          fi
          if echo "$DIFF_FILES" | grep -qE '^api/'; then
            API=true
          fi
          if echo "$DIFF_FILES" | grep -qE '^database/migrations/'; then
            MIGRATIONS=true
          fi

          echo "frontend=$FRONTEND" >> $GITHUB_OUTPUT
          echo "api=$API" >> $GITHUB_OUTPUT
          echo "migrations=$MIGRATIONS" >> $GITHUB_OUTPUT
          echo "Frontend: $FRONTEND | API: $API | Migrations: $MIGRATIONS"

  # ── Job 2: Frontend Deploy ───────────────────────────────────────────
  deploy-frontend:
    runs-on: ubuntu-latest
    needs: detect
    if: needs.detect.outputs.frontend == 'true'
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install dependencies
        run: npm ci

      - name: Security check & tests
        run: |
          npm run security:check
          npm test -- --passWithNoTests

      - name: Build Next.js
        run: npm run build

      - name: Verify build output
        run: |
          if [ ! -d "out" ]; then
            echo "ERROR: out/ directory not found after build"
            exit 1
          fi
          echo "Build output verified: $(find out -type f | wc -l) files"

      - name: Setup AWS
        run: |
          pip3 install -q --break-system-packages awscli
          aws configure set aws_access_key_id "${{ secrets.AWS_ACCESS_KEY_ID }}"
          aws configure set aws_secret_access_key "${{ secrets.AWS_SECRET_ACCESS_KEY }}"
          aws configure set region ${{ env.AWS_REGION }}

      - name: Deploy to S3 & invalidate CloudFront
        run: |
          # HTML files — no cache
          aws s3 sync out/ s3://$S3_BUCKET/ \
            --delete \
            --exclude "*" \
            --include "*.html" \
            --cache-control "public, max-age=0, must-revalidate" \
            --content-type "text/html"

          # Next.js assets — immutable
          aws s3 sync out/_next/ s3://$S3_BUCKET/_next/ \
            --cache-control "public, max-age=31536000, immutable"

          # Everything else — 24h cache
          aws s3 sync out/ s3://$S3_BUCKET/ \
            --exclude "*.html" \
            --exclude "_next/*" \
            --cache-control "public, max-age=86400"

          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

  # ── Job 3: API & Migrations Deploy ──────────────────────────────────
  deploy-api:
    runs-on: ubuntu-latest
    needs: detect
    if: needs.detect.outputs.api == 'true' || needs.detect.outputs.migrations == 'true'
    steps:
      - name: Setup AWS
        run: |
          pip3 install -q --break-system-packages awscli
          aws configure set aws_access_key_id "${{ secrets.AWS_ACCESS_KEY_ID }}"
          aws configure set aws_secret_access_key "${{ secrets.AWS_SECRET_ACCESS_KEY }}"
          aws configure set region ${{ env.AWS_REGION }}

      - name: Run database migrations
        if: needs.detect.outputs.migrations == 'true'
        run: |
          CMD_ID=$(aws ssm send-command \
            --region $AWS_REGION \
            --instance-ids "$INSTANCE_ID" \
            --document-name "AWS-RunShellScript" \
            --parameters 'commands=[
              "set -e",
              "cd /tmp",
              "rm -rf repo.tar.gz filamenteka",
              "curl -sf -o repo.tar.gz https://git.demirix.dev/dax/Filamenteka/archive/main.tar.gz",
              "tar xzf repo.tar.gz",
              "mkdir -p /home/ubuntu/filamenteka-api/api /home/ubuntu/filamenteka-api/database/migrations",
              "cp -r filamenteka/database/* /home/ubuntu/filamenteka-api/database/",
              "cp filamenteka/api/migrate.js /home/ubuntu/filamenteka-api/api/migrate.js",
              "rm -rf repo.tar.gz filamenteka",
              "echo Migration files:",
              "ls -la /home/ubuntu/filamenteka-api/database/migrations/",
              "export NVM_DIR=/home/ubuntu/.nvm && . $NVM_DIR/nvm.sh && cd /home/ubuntu/filamenteka-api && node api/migrate.js"
            ]' \
            --output json \
            --query "Command.CommandId" --output text)

          echo "Migration SSM command: $CMD_ID"

          # Poll for completion (max 2 minutes)
          for i in $(seq 1 24); do
            sleep 5
            STATUS=$(aws ssm get-command-invocation \
              --command-id "$CMD_ID" \
              --instance-id "$INSTANCE_ID" \
              --query "Status" --output text 2>/dev/null || echo "Pending")

            echo "Attempt $i: $STATUS"

            if [ "$STATUS" = "Success" ]; then
              echo "Migrations completed successfully"
              aws ssm get-command-invocation \
                --command-id "$CMD_ID" \
                --instance-id "$INSTANCE_ID" \
                --query "StandardOutputContent" --output text
              break
            elif [ "$STATUS" = "Failed" ] || [ "$STATUS" = "Cancelled" ] || [ "$STATUS" = "TimedOut" ]; then
              echo "Migration failed with status: $STATUS"
              aws ssm get-command-invocation \
                --command-id "$CMD_ID" \
                --instance-id "$INSTANCE_ID" \
                --query "StandardErrorContent" --output text
              exit 1
            fi
          done

          if [ "$STATUS" != "Success" ]; then
            echo "Migration timed out after 2 minutes"
            exit 1
          fi

      - name: Deploy server.js
        id: deploy
        run: |
          CMD_ID=$(aws ssm send-command \
            --region $AWS_REGION \
            --instance-ids "$INSTANCE_ID" \
            --document-name "AWS-RunShellScript" \
            --parameters 'commands=[
              "set -e",
              "cd /home/ubuntu/filamenteka-api",
              "cp server.js server.js.backup",
              "curl -sf -o server.js https://git.demirix.dev/dax/Filamenteka/raw/branch/main/api/server.js",
              "sudo systemctl restart node-api",
              "echo API deployed and restarted"
            ]' \
            --output json \
            --query "Command.CommandId" --output text)

          echo "Deploy SSM command: $CMD_ID"

          for i in $(seq 1 24); do
            sleep 5
            STATUS=$(aws ssm get-command-invocation \
              --command-id "$CMD_ID" \
              --instance-id "$INSTANCE_ID" \
              --query "Status" --output text 2>/dev/null || echo "Pending")

            echo "Attempt $i: $STATUS"

            if [ "$STATUS" = "Success" ]; then
              echo "API deploy completed"
              break
            elif [ "$STATUS" = "Failed" ] || [ "$STATUS" = "Cancelled" ] || [ "$STATUS" = "TimedOut" ]; then
              echo "API deploy failed with status: $STATUS"
              aws ssm get-command-invocation \
                --command-id "$CMD_ID" \
                --instance-id "$INSTANCE_ID" \
                --query "StandardErrorContent" --output text
              exit 1
            fi
          done

          if [ "$STATUS" != "Success" ]; then
            echo "API deploy timed out"
            exit 1
          fi

      - name: Health check
        id: health
        run: |
          echo "Waiting for API to be ready..."
          for i in $(seq 1 6); do
            HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://api.filamenteka.rs/api/filaments || echo "000")
            echo "Health check attempt $i: HTTP $HTTP_CODE"

            if [ "$HTTP_CODE" = "200" ]; then
              echo "API is healthy"
              exit 0
            fi
            sleep 5
          done

          echo "Health check failed after 6 attempts"
          exit 1

      - name: Rollback on failure
        if: failure() && steps.deploy.outcome == 'success'
        run: |
          echo "Rolling back to server.js.backup..."
          aws ssm send-command \
            --region $AWS_REGION \
            --instance-ids "$INSTANCE_ID" \
            --document-name "AWS-RunShellScript" \
            --parameters 'commands=[
              "cd /home/ubuntu/filamenteka-api",
              "if [ -f server.js.backup ]; then cp server.js.backup server.js && sudo systemctl restart node-api && echo Rollback complete; else echo No backup found; fi"
            ]' \
            --output json
          echo "Rollback command sent"

  # ── Job 4: Tag Successful Deploy ────────────────────────────────────
  tag-deploy:
    runs-on: ubuntu-latest
    needs: [detect, deploy-frontend, deploy-api]
    if: >-
      always() &&
      needs.detect.result == 'success' &&
      (needs.deploy-frontend.result == 'success' || needs.deploy-frontend.result == 'skipped') &&
      (needs.deploy-api.result == 'success' || needs.deploy-api.result == 'skipped') &&
      !(needs.deploy-frontend.result == 'skipped' && needs.deploy-api.result == 'skipped')
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 1
          token: ${{ github.token }}

      - name: Create deploy tag
        run: |
          TAG="deploy-$(date -u +%Y%m%d-%H%M%S)"
          git tag "$TAG"
          git push origin "$TAG"
          echo "Tagged successful deploy: $TAG"
