# MotoVaultPro Staging Deployment Workflow
# Triggers on push to main or any pull request, builds and deploys to staging.motovaultpro.com
# After verification, sends notification with link to trigger production deploy

name: Deploy to Staging
run-name: "Staging - ${{ gitea.event.pull_request.title || gitea.ref_name }}"

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened]

env:
  REGISTRY: git.motovaultpro.com
  DEPLOY_PATH: /opt/motovaultpro
  COMPOSE_FILE: docker-compose.yml
  COMPOSE_STAGING: docker-compose.staging.yml
  HEALTH_CHECK_TIMEOUT: "60"

jobs:
  # ============================================
  # BUILD - Build and push images
  # ============================================
  build:
    name: Build Images
    runs-on: stage
    outputs:
      backend_image: ${{ steps.tags.outputs.backend_image }}
      frontend_image: ${{ steps.tags.outputs.frontend_image }}
      short_sha: ${{ steps.tags.outputs.short_sha }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Login to Gitea Container Registry
        run: |
          echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin "$REGISTRY"

      - name: Set image tags
        id: tags
        run: |
          SHORT_SHA="${{ gitea.sha }}"
          SHORT_SHA="${SHORT_SHA:0:7}"
          echo "backend_image=$REGISTRY/egullickson/backend:$SHORT_SHA" >> $GITHUB_OUTPUT
          echo "frontend_image=$REGISTRY/egullickson/frontend:$SHORT_SHA" >> $GITHUB_OUTPUT
          echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT

      - name: Build backend image
        run: |
          docker build \
            --build-arg BUILDKIT_INLINE_CACHE=1 \
            --build-arg REGISTRY_MIRRORS=$REGISTRY/egullickson/mirrors \
            --cache-from $REGISTRY/egullickson/backend:latest \
            -t ${{ steps.tags.outputs.backend_image }} \
            -t $REGISTRY/egullickson/backend:latest \
            -f backend/Dockerfile \
            .

      - name: Build frontend image
        run: |
          docker build \
            --build-arg BUILDKIT_INLINE_CACHE=1 \
            --build-arg REGISTRY_MIRRORS=$REGISTRY/egullickson/mirrors \
            --build-arg VITE_AUTH0_DOMAIN=${{ vars.VITE_AUTH0_DOMAIN }} \
            --build-arg VITE_AUTH0_CLIENT_ID=${{ vars.VITE_AUTH0_CLIENT_ID }} \
            --build-arg VITE_AUTH0_AUDIENCE=${{ vars.VITE_AUTH0_AUDIENCE }} \
            --build-arg VITE_API_BASE_URL=/api \
            --cache-from $REGISTRY/egullickson/frontend:latest \
            -t ${{ steps.tags.outputs.frontend_image }} \
            -t $REGISTRY/egullickson/frontend:latest \
            -f frontend/Dockerfile \
            frontend

      - name: Push images
        run: |
          docker push ${{ steps.tags.outputs.backend_image }}
          docker push ${{ steps.tags.outputs.frontend_image }}
          docker push $REGISTRY/egullickson/backend:latest
          docker push $REGISTRY/egullickson/frontend:latest

  # ============================================
  # DEPLOY STAGING - Deploy to staging server
  # ============================================
  deploy-staging:
    name: Deploy to Staging
    runs-on: stage
    needs: build
    env:
      BACKEND_IMAGE: ${{ needs.build.outputs.backend_image }}
      FRONTEND_IMAGE: ${{ needs.build.outputs.frontend_image }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Login to registry
        run: |
          echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin "$REGISTRY"

      - name: Inject secrets
        run: |
          cd "$DEPLOY_PATH"
          chmod +x scripts/inject-secrets.sh
          SECRETS_DIR="$DEPLOY_PATH/secrets/app" ./scripts/inject-secrets.sh
        env:
          POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
          AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_CLIENT_SECRET }}
          AUTH0_MANAGEMENT_CLIENT_ID: ${{ secrets.AUTH0_MANAGEMENT_CLIENT_ID }}
          AUTH0_MANAGEMENT_CLIENT_SECRET: ${{ secrets.AUTH0_MANAGEMENT_CLIENT_SECRET }}
          GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
          GOOGLE_MAPS_MAP_ID: ${{ secrets.GOOGLE_MAPS_MAP_ID }}
          CF_DNS_API_TOKEN: ${{ secrets.CF_DNS_API_TOKEN }}
          RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}

      - name: Initialize data directories
        run: |
          cd "$DEPLOY_PATH"
          sudo mkdir -p data/backups data/documents data/traefik
          sudo chown -R 1001:1001 data/backups data/documents
          sudo chmod 755 data/backups data/documents
          # Traefik acme.json requires 600 permissions
          if [ ! -f data/traefik/acme.json ]; then
            sudo touch data/traefik/acme.json
          fi
          sudo chmod 600 data/traefik/acme.json

      - name: Pull new images
        run: |
          docker pull $BACKEND_IMAGE
          docker pull $FRONTEND_IMAGE

      - name: Deploy staging stack
        run: |
          cd "$DEPLOY_PATH"
          export BACKEND_IMAGE=$BACKEND_IMAGE
          export FRONTEND_IMAGE=$FRONTEND_IMAGE
          docker compose -f $COMPOSE_FILE -f $COMPOSE_STAGING down --timeout 30 || true
          docker compose -f $COMPOSE_FILE -f $COMPOSE_STAGING up -d

      - name: Wait for services
        run: sleep 15

  # ============================================
  # VERIFY STAGING - Health checks
  # ============================================
  verify-staging:
    name: Verify Staging
    runs-on: stage
    needs: [build, deploy-staging]
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Check container status and health
        run: |
          for service in mvp-frontend-staging mvp-backend-staging mvp-postgres-staging mvp-redis-staging; do
            status=$(docker inspect --format='{{.State.Status}}' $service 2>/dev/null || echo "not found")
            if [ "$status" != "running" ]; then
              echo "ERROR: $service is not running (status: $status)"
              docker logs $service --tail 50 2>/dev/null || true
              exit 1
            fi
            echo "OK: $service is running"
          done

          # Wait for Docker healthchecks to complete (services with healthcheck defined)
          echo ""
          echo "Waiting for Docker healthchecks..."
          for service in mvp-frontend-staging mvp-backend-staging mvp-postgres-staging mvp-redis-staging; do
            # Check if service has a healthcheck defined
            has_healthcheck=$(docker inspect --format='{{if .Config.Healthcheck}}true{{else}}false{{end}}' $service 2>/dev/null || echo "false")
            if [ "$has_healthcheck" = "true" ]; then
              for i in 1 2 3 4 5 6 7 8 9 10; do
                health=$(docker inspect --format='{{.State.Health.Status}}' $service 2>/dev/null || echo "unknown")
                if [ "$health" = "healthy" ]; then
                  echo "OK: $service is healthy"
                  break
                elif [ "$health" = "unhealthy" ]; then
                  echo "ERROR: $service is unhealthy"
                  docker logs $service --tail 50 2>/dev/null || true
                  exit 1
                fi
                if [ $i -eq 10 ]; then
                  echo "ERROR: $service health check timed out (status: $health)"
                  docker logs $service --tail 50 2>/dev/null || true
                  exit 1
                fi
                echo "Waiting for $service healthcheck... (attempt $i/10, status: $health)"
                sleep 5
              done
            else
              echo "SKIP: $service has no healthcheck defined"
            fi
          done

      - name: Wait for backend health
        run: |
          for i in 1 2 3 4 5 6; do
            if docker exec mvp-backend-staging curl -sf http://localhost:3001/health > /dev/null 2>&1; then
              echo "OK: Backend health check passed"
              exit 0
            fi
            if [ $i -eq 6 ]; then
              echo "ERROR: Backend health check failed after 6 attempts"
              docker logs mvp-backend-staging --tail 100
              exit 1
            fi
            echo "Attempt $i/6: Backend not ready, waiting 10s..."
            sleep 10
          done

      - name: Check external endpoint
        run: |
          REQUIRED_FEATURES='["admin","auth","onboarding","vehicles","documents","fuel-logs","stations","maintenance","platform","notifications","user-profile","user-preferences","user-export"]'

          for i in 1 2 3 4 5 6; do
            RESPONSE=$(curl -sf https://staging.motovaultpro.com/api/health 2>/dev/null) || {
              echo "Attempt $i/6: Connection failed, waiting 10s..."
              sleep 10
              continue
            }

            # Check status is "healthy"
            STATUS=$(echo "$RESPONSE" | jq -r '.status')
            if [ "$STATUS" != "healthy" ]; then
              echo "Attempt $i/6: Status is '$STATUS', not 'healthy'. Waiting 10s..."
              sleep 10
              continue
            fi

            # Check all required features are present
            MISSING=$(echo "$RESPONSE" | jq -r --argjson required "$REQUIRED_FEATURES" '
              $required - .features | if length > 0 then . else empty end | @json
            ')

            if [ -n "$MISSING" ]; then
              echo "Attempt $i/6: Missing features: $MISSING. Waiting 10s..."
              sleep 10
              continue
            fi

            FEATURE_COUNT=$(echo "$RESPONSE" | jq '.features | length')
            echo "OK: Staging health check passed - status: healthy, features: $FEATURE_COUNT"
            exit 0
          done

          echo "ERROR: Staging health check failed after 6 attempts"
          echo "Last response: $RESPONSE"
          exit 1

  # ============================================
  # NOTIFY - Staging ready for production
  # ============================================
  notify-staging-ready:
    name: Notify Staging Ready
    runs-on: stage
    needs: [build, verify-staging]
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Send staging ready notification
        run: |
          cd "$DEPLOY_PATH"
          chmod +x scripts/ci/notify.sh
          ./scripts/ci/notify.sh staging_ready \
            "Staging verified for commit ${{ needs.build.outputs.short_sha }}. Review at https://staging.motovaultpro.com then trigger production deploy at https://git.motovaultpro.com/egullickson/motovaultpro/actions" \
            ${{ needs.build.outputs.short_sha }}
        env:
          DEPLOY_NOTIFY_EMAIL: ${{ vars.DEPLOY_NOTIFY_EMAIL }}
          RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}

  # ============================================
  # NOTIFY FAILURE - Staging failed
  # ============================================
  notify-staging-failure:
    name: Notify Staging Failure
    runs-on: stage
    needs: [build, deploy-staging, verify-staging]
    if: failure()
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Send failure notification
        run: |
          cd "$DEPLOY_PATH"
          chmod +x scripts/ci/notify.sh
          SHORT_SHA="${{ gitea.sha }}"
          SHORT_SHA="${SHORT_SHA:0:7}"
          ./scripts/ci/notify.sh failure "Staging deployment failed for commit $SHORT_SHA" $SHORT_SHA
        env:
          DEPLOY_NOTIFY_EMAIL: ${{ vars.DEPLOY_NOTIFY_EMAIL }}
          RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
