name: Deploy

on:
  push:
    branches: [main]
  release:
    types: [published]

concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: true

env:
  NODE_VERSION: "20"
  PNPM_VERSION: "9"

jobs:
  detect-environment:
    name: Detect Environment
    runs-on: ubuntu-latest
    outputs:
      environment: ${{ steps.detect.outputs.environment }}
      tag: ${{ steps.tag.outputs.tag }}
    steps:
      - name: Detect deployment target
        id: detect
        run: |
          if [ "${{ github.event_name }}" = "release" ]; then
            echo "environment=production" >> $GITHUB_OUTPUT
          else
            echo "environment=staging" >> $GITHUB_OUTPUT
          fi
      - name: Calculate tag
        id: tag
        run: |
          if [ "${{ steps.detect.outputs.environment }}" = "production" ]; then
            echo "tag=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
          else
            echo "tag=${{ github.sha }}" >> $GITHUB_OUTPUT
          fi

  terraform-apply:
    name: Terraform Apply
    runs-on: ubuntu-latest
    needs: detect-environment
    environment: ${{ needs.detect-environment.outputs.environment }}
    steps:
      - uses: actions/checkout@v4
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.5"
      - name: Terraform Init
        working-directory: infra/environments/${{ needs.detect-environment.outputs.environment }}
        run: terraform init -backend-config="bucket=shieldai-${{ needs.detect-environment.outputs.environment }}-terraform-state"
      - name: Terraform Plan
        id: plan
        working-directory: infra/environments/${{ needs.detect-environment.outputs.environment }}
        run: |
          terraform plan \
            -var="hibp_api_key=${{ secrets.HIBP_API_KEY }}" \
            -var="resend_api_key=${{ secrets.RESEND_API_KEY }}" \
            -var="sentry_dsn=${{ secrets.SENTRY_DSN }}" \
            -var="datadog_api_key=${{ secrets.DATADOG_API_KEY }}" \
            -no-color | tee /tmp/terraform-plan.out
      - name: Terraform Apply
        working-directory: infra/environments/${{ needs.detect-environment.outputs.environment }}
        run: |
          terraform apply -auto-approve \
            -var="hibp_api_key=${{ secrets.HIBP_API_KEY }}" \
            -var="resend_api_key=${{ secrets.RESEND_API_KEY }}" \
            -var="sentry_dsn=${{ secrets.SENTRY_DSN }}" \
            -var="datadog_api_key=${{ secrets.DATADOG_API_KEY }}"
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: us-east-1

  build-and-push:
    name: Build and Push Docker Images
    runs-on: ubuntu-latest
    needs: [detect-environment]
    environment: ${{ needs.detect-environment.outputs.environment }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: api
            dockerfile: packages/api/Dockerfile
          - name: darkwatch
            dockerfile: services/darkwatch/Dockerfile
          - name: spamshield
            dockerfile: services/spamshield/Dockerfile
          - name: voiceprint
            dockerfile: services/voiceprint/Dockerfile
    steps:
      - uses: actions/checkout@v4
      - name: Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Calculate image tag
        id: tag
        run: echo "tag=${{ needs.detect-environment.outputs.tag }}" >> $GITHUB_OUTPUT
      - name: Build and push ${{ matrix.name }}
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ${{ matrix.dockerfile }}
          push: true
          tags: |
            ghcr.io/${{ github.repository_owner }}/shieldai-${{ matrix.name }}:${{ steps.tag.outputs.tag }}
            ghcr.io/${{ github.repository_owner }}/shieldai-${{ matrix.name }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy-ecs:
    name: Deploy to ECS
    runs-on: ubuntu-latest
    needs: [detect-environment, terraform-apply, build-and-push]
    environment: ${{ needs.detect-environment.outputs.environment }}
    strategy:
      fail-fast: false
      matrix:
        service: [api, darkwatch, spamshield, voiceprint]
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Update ECS Service
        run: |
          IMAGE="ghcr.io/${{ github.repository_owner }}/shieldai-${{ matrix.service }}:${{ needs.detect-environment.outputs.tag }}"
          CLUSTER="shieldai-${{ needs.detect-environment.outputs.environment }}"
          SERVICE="${{ matrix.service }}"

          TASK_DEF=$(aws ecs describe-task-definition \
            --task-definition "${CLUSTER}-${SERVICE}" \
            --query 'taskDefinition' --output json)

          NEW_TASK_DEF=$(echo "$TASK_DEF" | jq \
            --arg image "$IMAGE" \
            '.containerDefinitions[0].image = $image')

          NEW_TASK_DEF_ARN=$(echo "$NEW_TASK_DEF" | \
            aws ecs register-task-definition \
            --family "${CLUSTER}-${SERVICE}" \
            --cli-input-json - \
            --query 'taskDefinition.taskDefinitionArn' --output text)

          aws ecs update-service \
            --cluster "$CLUSTER" \
            --service "${CLUSTER}-${SERVICE}" \
            --task-definition "$NEW_TASK_DEF_ARN" \
            --force-new-deployment

          echo "Deployed $IMAGE to $SERVICE"

  health-check:
    name: Post-Deploy Health Check
    runs-on: ubuntu-latest
    needs: [detect-environment, deploy-ecs]
    environment: ${{ needs.detect-environment.outputs.environment }}
    steps:
      - name: Configure AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Wait for deployment
        run: sleep 30
      - name: Health Check
        id: health
        run: |
          ENV="${{ needs.detect-environment.outputs.environment }}"
          CLUSTER="shieldai-${ENV}"

          ALB_DNS=$(aws elbv2 describe-load-balancers \
            --query "LoadBalancers[?contains(LoadBalancerName, '${CLUSTER}-alb')].DNSName" \
            --output text)

          if [ -z "$ALB_DNS" ]; then
            echo "Health check failed: ALB DNS not found"
            exit 1
          fi

          echo "ALB DNS: $ALB_DNS"

          FAILED=0
          for service in api darkwatch spamshield voiceprint; do
            HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
              "https://${ALB_DNS}/health" || true)

            if [ "$HTTP_CODE" = "200" ]; then
              echo "Health check passed: $service"
            else
              echo "Health check failed: $service (HTTP $HTTP_CODE)"
              FAILED=1
            fi
          done

          if [ "$FAILED" -eq 1 ]; then
            exit 1
          fi

  rollback:
    name: Rollback on Failure
    runs-on: ubuntu-latest
    needs: [detect-environment, deploy-ecs, health-check]
    environment: ${{ needs.detect-environment.outputs.environment }}
    if: failure() && needs.health-check.result == 'failure'
    strategy:
      fail-fast: false
      matrix:
        service: [api, darkwatch, spamshield, voiceprint]
    steps:
      - name: Configure AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Rollback ECS Service
        run: |
          CLUSTER="shieldai-${{ needs.detect-environment.outputs.environment }}"
          SERVICE="${{ matrix.service }}"

          aws ecs update-service \
            --cluster "$CLUSTER" \
            --service "${CLUSTER}-${SERVICE}" \
            --rollback \
            --no-cli-auto-prompt

          echo "Rolled back $SERVICE"
