# Internet for Kids - Production Deployment
# Deploys to infra VM at /opt/apps/internetforkids
#
# Features:
# - Docker registry-based deployment (build → push → pull)
# - Health check with automatic rollback on failure
# - Smoke tests against public URLs
# - Deploy-guard audit logging

name: Deploy Internet for Kids

on:
  push:
    branches: [main]
    paths-ignore:
      - '**.md'
      - 'docs/**'
  workflow_dispatch:
    inputs:
      force_deploy:
        description: 'Force deploy even if health checks fail'
        required: false
        default: 'false'

env:
  PROJECT_NAME: "internetforkids"
  REGISTRY: gitea.agiliton.internal:3000
  IMAGE: gitea.agiliton.internal:3000/christian/internetforkids
  REMOTE_HOST: infra.agiliton.internal
  REMOTE_USER: root
  DEPLOY_PATH: /opt/apps/internetforkids
  HEALTH_ENDPOINT: "http://localhost:3006/health"
  PUBLIC_URL: "https://internetforkids.org"
  HEALTH_TIMEOUT: 60

jobs:
  build-and-push:
    name: Build & Push
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

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

      - name: Build and push
        run: |
          DOCKER_BUILDKIT=1 docker build --pull \
            -t ${{ env.IMAGE }}:${{ github.sha }} \
            .
          docker push ${{ env.IMAGE }}:${{ github.sha }}

      - name: Cleanup
        if: always()
        run: docker builder prune -f --filter "until=24h" 2>/dev/null || true

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build-and-push
    outputs:
      previous_image: ${{ steps.deploy.outputs.previous_image }}
    steps:
      - uses: actions/checkout@v4

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh && chmod 700 ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H ${{ env.REMOTE_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Deploy
        id: deploy
        run: |
          # Capture current image digest for rollback
          PREVIOUS=$(ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} \
            "docker inspect --format='{{.Image}}' internetforkids 2>/dev/null || echo 'none'")
          echo "previous_image=$PREVIOUS" >> $GITHUB_OUTPUT
          echo "Previous image: $PREVIOUS"

          # Sync docker-compose.yml and deploy
          scp docker-compose.yml ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }}:${{ env.DEPLOY_PATH }}/docker-compose.yml

          ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} << EOF
            cd /opt/apps/internetforkids
            docker pull ${{ env.IMAGE }}:${{ github.sha }}
            docker tag ${{ env.IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}:latest
            docker compose up -d --force-recreate --remove-orphans
          EOF

          echo "Deployment initiated"

  health-check:
    name: Health Check
    runs-on: ubuntu-latest
    needs: deploy
    steps:
      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh && chmod 700 ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H ${{ env.REMOTE_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Wait for health
        run: |
          echo "Waiting for health (timeout: ${HEALTH_TIMEOUT}s)..."
          ELAPSED=0
          while [ $ELAPSED -lt $HEALTH_TIMEOUT ]; do
            if ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} \
              "curl -sf ${{ env.HEALTH_ENDPOINT }}" >/dev/null 2>&1; then
              echo "Health check passed!"
              exit 0
            fi
            echo "Waiting... ($ELAPSED/${HEALTH_TIMEOUT}s)"
            sleep 10
            ELAPSED=$((ELAPSED + 10))
          done

          echo "::error::Health check timeout after ${HEALTH_TIMEOUT}s"
          ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} \
            "cd ${{ env.DEPLOY_PATH }} && docker compose ps && docker compose logs --tail 20" || true

          if [ "${{ github.event.inputs.force_deploy }}" = "true" ]; then
            echo "::warning::Force deploy — continuing despite health failure"
            exit 0
          fi
          exit 1

  smoke-test:
    name: Smoke Tests
    runs-on: ubuntu-latest
    needs: health-check
    steps:
      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh && chmod 700 ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H ${{ env.REMOTE_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Test key URLs
        run: |
          FAILED=0
          for path in /health /en/ /de/ /fr/; do
            STATUS=$(ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} \
              "curl -so /dev/null -w '%{http_code}' http://localhost:3006${path}" 2>/dev/null || echo "000")
            if [ "$STATUS" = "200" ] || [ "$STATUS" = "302" ]; then
              echo "OK  $path → $STATUS"
            else
              echo "FAIL $path → $STATUS"
              FAILED=$((FAILED + 1))
            fi
          done

          if [ $FAILED -gt 0 ]; then
            echo "::error::$FAILED smoke test(s) failed"
            exit 1
          fi
          echo "All smoke tests passed"

  indexnow:
    name: IndexNow Ping
    runs-on: ubuntu-latest
    needs: [smoke-test]
    steps:
      - name: Notify search engines
        run: |
          KEY="40101d97ec848f6ea016fac347b1a5bc"
          for url in \
            "https://internetforkids.org/" \
            "https://internetforkids.org/en/" \
            "https://internetforkids.org/de/" \
            "https://internetforkids.org/fr/" \
            "https://internetforkids.org/sitemap.xml"; do
            curl -sf "https://api.indexnow.org/indexnow?url=${url}&key=${KEY}" || true
          done
          echo "IndexNow pings sent"

  promote:
    name: Promote to Latest
    runs-on: ubuntu-latest
    needs: [smoke-test]
    steps:
      - name: Login to registry
        run: |
          echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ${{ env.REGISTRY }} -u christian --password-stdin

      - name: Tag and push latest
        run: |
          docker pull ${{ env.IMAGE }}:${{ github.sha }}
          docker tag ${{ env.IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}:latest
          docker push ${{ env.IMAGE }}:latest
          echo "Promoted ${{ github.sha }} to :latest"

  rollback:
    name: Rollback
    runs-on: ubuntu-latest
    needs: [deploy, health-check, smoke-test]
    if: failure() && needs.deploy.outputs.previous_image != 'none' && needs.deploy.outputs.previous_image != ''
    steps:
      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh && chmod 700 ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H ${{ env.REMOTE_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Rollback to previous image
        run: |
          PREVIOUS="${{ needs.deploy.outputs.previous_image }}"
          echo "::warning::Rolling back to image $PREVIOUS"

          ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} << EOF
            cd ${{ env.DEPLOY_PATH }}
            docker tag $PREVIOUS ${{ env.IMAGE }}:latest
            docker compose up -d --force-recreate
            # Push rolled-back image as :latest so Watchtower doesn't re-pull broken
            docker push ${{ env.IMAGE }}:latest
          EOF

      - name: Verify rollback
        run: |
          sleep 10
          if ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} \
            "curl -sf ${{ env.HEALTH_ENDPOINT }}" >/dev/null 2>&1; then
            echo "Rollback successful"
          else
            echo "::error::Rollback may have failed — check manually"
          fi

  audit:
    name: Audit
    runs-on: ubuntu-latest
    needs: [deploy, health-check, smoke-test, promote, rollback]
    if: always()
    steps:
      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh && chmod 700 ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H ${{ env.REMOTE_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Log deployment
        run: |
          STATUS="success"
          [ "${{ needs.health-check.result }}" = "failure" ] && STATUS="failed"
          [ "${{ needs.smoke-test.result }}" = "failure" ] && STATUS="failed"
          [ "${{ needs.rollback.result }}" = "success" ] && STATUS="rolled_back"

          echo "${{ env.PROJECT_NAME }} deployment: $STATUS (sha: ${{ github.sha }})"
          ssh ${{ env.REMOTE_USER }}@${{ env.REMOTE_HOST }} \
            "/opt/scripts/deploy-guard.sh check 'ci-deploy ${{ env.PROJECT_NAME }} $STATUS'" 2>/dev/null || true
