# Push to `main` → CI → deploy. Manual "Run workflow" can set reset_postgres_volume=yes to wipe DB volume then deploy.
# On pull_request from `dependabot/github_actions/*`, the `ci` job runs a quick workflow YAML parse only (no npm/docker).
# Domains via GitHub secrets (see .github/DEPLOY-SECRETS.md):
#   PRODUCTION_APP_URL, PRODUCTION_TRACKER_HOST, optional PRODUCTION_DOCS_HOST (+ PRODUCTION_DOCS_URL for canonical links).
name: CI and production deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:
    inputs:
      reset_postgres_volume:
        description: "DESTRUCTIVE — delete all Postgres data, then deploy (only when you mean it)"
        required: true
        default: "no"
        type: choice
        options:
          - "no"
          - "yes"

# Least privilege: workflows only need to read the repo (checkout).
permissions:
  contents: read

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

jobs:
  ci:
    runs-on: ubuntu-latest
    env:
      # Until checkout/setup-node default to Node 24 on the runner (see GitHub changelog).
      FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
    steps:
      - uses: actions/checkout@v5

      # Pure Dependabot GitHub Actions bumps only touch workflows — skip heavy Node/Docker CI
      # so dozens of queued runs do not pile up; npm/docs PRs still get the full pipeline.
      - name: Detect CI mode
        id: mode
        shell: bash
        run: |
          if [[ "${{ github.event_name }}" == "pull_request" ]] && [[ "${{ github.head_ref }}" == dependabot/github_actions/* ]]; then
            echo "mode=actions-only" >> "$GITHUB_OUTPUT"
          else
            echo "mode=full" >> "$GITHUB_OUTPUT"
          fi

      - name: Quick-check workflow YAML (Dependabot actions PRs)
        if: steps.mode.outputs.mode == 'actions-only'
        shell: bash
        run: |
          set -euo pipefail
          ruby -ryaml -e 'Dir.glob(".github/workflows/*.{yml,yaml}").each { |p| YAML.load_file(p); puts "OK #{p}" }'

      - uses: actions/setup-node@v5
        if: steps.mode.outputs.mode == 'full'
        with:
          node-version: "22"
          cache: npm
      - run: npm ci
        if: steps.mode.outputs.mode == 'full'
      - run: npm run lint
        if: steps.mode.outputs.mode == 'full'
      - run: npm run build
        if: steps.mode.outputs.mode == 'full'
      - run: npm run docs:ci
        if: steps.mode.outputs.mode == 'full'
      - run: npm run test:gateway
        if: steps.mode.outputs.mode == 'full'
      # prod compose references env_file: .env — file is gitignored; use template so `compose config` can run in CI.
      - name: Validate Docker Compose merge (Fase 2 + prod)
        if: steps.mode.outputs.mode == 'full'
        run: |
          test -f .env || cp deploy/env.production.template .env
          docker compose -f docker-compose.yml -f docker-compose.v1.yml -f docker-compose.prod.yml config --quiet

  deploy-production:
    needs: ci
    if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
    runs-on: ubuntu-latest
    timeout-minutes: 60
    environment: production
    steps:
      - name: Deploy over SSH
        uses: appleboy/ssh-action@v1.2.5
        with:
          host: ${{ secrets.PRODUCTION_HOST }}
          username: ${{ secrets.PRODUCTION_USER }}
          key: ${{ secrets.PRODUCTION_SSH_KEY }}
          command_timeout: 45m
          script: |
            set -euo pipefail
            export DEBIAN_FRONTEND=noninteractive
            # Clean VPS: need git before clone, Docker before compose.
            if ! command -v git >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
              apt-get update -y
              apt-get install -y ca-certificates curl git
            fi
            if ! command -v docker >/dev/null 2>&1; then
              curl -fsSL https://get.docker.com | sh
            fi
            systemctl enable --now docker
            APP_ROOT=/opt/omnihub/app
            # Private repos need auth; GITHUB_TOKEN is injected per job (expires after the run).
            # Host is github.com (GitHub Enterprise: edit this URL to your server hostname).
            ORIGIN_URL="https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git"
            if [ ! -d "$APP_ROOT/.git" ]; then
              if [ -e "$APP_ROOT" ]; then
                echo "ERROR: $APP_ROOT exists but is not a git repository. Remove it on the server or fix manually." >&2
                exit 1
              fi
              mkdir -p "$(dirname "$APP_ROOT")"
              git clone "$ORIGIN_URL" "$APP_ROOT"
            fi
            cd "$APP_ROOT"
            git remote set-url origin "$ORIGIN_URL"
            git fetch origin
            git checkout main
            PREV_SHA=$(git rev-parse HEAD)
            git reset --hard origin/main
            if [ ! -f .env ]; then
              cp deploy/env.production.template .env
            fi
            export GH_APP_URL="${{ secrets.PRODUCTION_APP_URL }}"
            export GH_TRACKER_HOST="${{ secrets.PRODUCTION_TRACKER_HOST }}"
            export GH_DOCS_HOST="${{ secrets.PRODUCTION_DOCS_HOST }}"
            export GH_DOCS_URL="${{ secrets.PRODUCTION_DOCS_URL }}"
            export GH_SESSION_SECRET="${{ secrets.PRODUCTION_SESSION_SECRET }}"
            export GH_POSTGRES_PASSWORD="${{ secrets.PRODUCTION_POSTGRES_PASSWORD }}"
            export GH_BOOTSTRAP_ADMIN_PASSWORD="${{ secrets.PRODUCTION_BOOTSTRAP_ADMIN_PASSWORD }}"
            export GH_BOOTSTRAP_REOPEN_TOKEN="${{ secrets.PRODUCTION_BOOTSTRAP_REOPEN_TOKEN }}"
            bash deploy/patch-env-github-secrets.sh .env
            bash deploy/build-documentation-static.sh
            export CERTBOT_EMAIL="${{ secrets.PRODUCTION_CERTBOT_EMAIL }}"
            export APP_PUBLIC_URL="${{ secrets.PRODUCTION_APP_URL }}"
            export TRACKER_TLS_DOMAIN="${{ secrets.PRODUCTION_TRACKER_HOST }}"
            bash deploy/ensure-server-deps.sh
            RESET_DB="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.reset_postgres_volume || 'no' }}"
            if [ "$RESET_DB" = "yes" ]; then
              echo ">>> PRODUCTION: wiping Postgres volume (all DB data removed)"
              export CONFIRM_RESET=yes
              bash deploy/reset-postgres-volume.sh
            fi
            if ! bash deploy/remote-deploy.sh; then
              echo ">>> Primary deploy failed; rolling back to ${PREV_SHA} …" >&2
              if bash deploy/rollback-to-revision.sh "$PREV_SHA"; then
                echo ">>> Rollback finished — stack rebuilt from ${PREV_SHA}. This job still fails so the incident is visible in Actions." >&2
              else
                echo ">>> CRITICAL: rollback script failed — fix the server manually." >&2
              fi
              exit 1
            fi
