name: ThemeFactory Verify

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      scope:
        description: Verification scope
        required: true
        default: canary
        type: choice
        options:
          - canary
          - all-themes
  schedule:
    - cron: "17 3 * * 1"

permissions:
  contents: read

concurrency:
  group: themefactory-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

env:
  PYTHONUNBUFFERED: "1"

jobs:
  plan:
    name: Plan verification
    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
    runs-on: themefactory-ci
    outputs:
      theme_matrix: ${{ steps.plan.outputs.theme_matrix }}
      themes: ${{ steps.plan.outputs.themes }}
      runtime_infra_changed: ${{ steps.plan.outputs.runtime_infra_changed }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Determine verification plan
        id: plan
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p .theme-ci
          if [[ "${{ github.event_name }}" == schedule ]]; then
            python3 tools/theme_ci.py ci-plan --base HEAD^ --head HEAD --mode scheduled --all-themes --out .theme-ci/ci-plan.json
          elif [[ "${{ github.event_name }}" == pull_request ]]; then
            EXTRA=()
            [[ "${{ contains(github.event.pull_request.labels.*.name, 'themefactory-all') }}" == true ]] && EXTRA+=(--all-themes)
            python3 tools/theme_ci.py ci-plan --base "${{ github.event.pull_request.base.sha }}" --head "${{ github.sha }}" --mode pr "${EXTRA[@]}" --out .theme-ci/ci-plan.json
          elif [[ "${{ github.event_name }}" == workflow_dispatch ]]; then
            git fetch origin main --quiet
            EXTRA=()
            [[ "${{ inputs.scope }}" == all-themes ]] && EXTRA+=(--all-themes)
            python3 tools/theme_ci.py ci-plan --base origin/main --head "${{ github.sha }}" --mode pr "${EXTRA[@]}" --out .theme-ci/ci-plan.json
          else
            BASE="${{ github.event.before }}"
            [[ -z "$BASE" || "$BASE" =~ ^0+$ ]] && BASE="HEAD^"
            python3 tools/theme_ci.py ci-plan --base "$BASE" --head "${{ github.sha }}" --mode release --out .theme-ci/ci-plan.json
          fi
          python3 - <<'PY' >> "$GITHUB_OUTPUT"
          import json
          p=json.load(open('.theme-ci/ci-plan.json'))
          compact=lambda x: json.dumps(x,separators=(',',':'))
          print(f"theme_matrix={compact(p['theme_matrix'])}")
          print(f"themes={compact(p['themes'])}")
          print(f"runtime_infra_changed={'true' if p.get('runtime_infra_changed') else 'false'}")
          PY
          {
            echo '### Verification plan'
            echo '```json'
            cat .theme-ci/ci-plan.json
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

  global-static:
    name: Repository verification contract
    needs: [plan]
    runs-on: themefactory-ci
    steps:
      - uses: actions/checkout@v4
      - name: Repository and workflow invariants
        run: |
          set -euo pipefail
          mkdir -p .theme-ci/receipts
          python3 tools/theme_ci.py global-static --out .theme-ci/receipts/repo-static.json
          {
            echo '### Repository verification receipt'
            echo '```json'
            cat .theme-ci/receipts/repo-static.json
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

  runtime-engine-selftest:
    name: Runtime verifier RED/GREEN canary
    needs: [plan, global-static]
    if: needs.global-static.result == 'success' && needs.plan.outputs.runtime_infra_changed == 'true' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
    runs-on: themefactory-runtime
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
      - name: Prove release-critical guards GREEN and RED
        env:
          THEMEFACTORY_CONTAINER_ENGINE: docker
        run: |
          set -euo pipefail
          python3 tests/runtime/guard_selftest.py
          {
            echo '### Runtime verifier RED/GREEN proof'
            echo '```json'
            cat .theme-ci/guard-selftests.json
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

  theme-verify:
    name: Theme · ${{ matrix.theme }}
    needs: [plan, global-static]
    if: needs.global-static.result == 'success' && needs.plan.outputs.themes != '[]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
    strategy:
      fail-fast: false
      max-parallel: 3
      matrix:
        include: ${{ fromJSON(needs.plan.outputs.theme_matrix) }}
    runs-on: themefactory-runtime
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v4
      - name: Static + semantic runtime + exact aggregation
        env:
          THEMEFACTORY_CONTAINER_ENGINE: docker
        shell: bash
        run: |
          set -euo pipefail
          MODE=pr
          [[ "${{ github.event_name }}" == push ]] && MODE=release
          [[ "${{ github.event_name }}" == schedule ]] && MODE=scheduled
          python3 tools/theme_ci.py verify "${{ matrix.theme }}" \
            --mode "$MODE" \
            --engine docker \
            --workdir ".theme-ci/${{ matrix.theme }}"
          {
            echo '### Final theme receipt: ${{ matrix.theme }}'
            echo '```json'
            cat ".theme-ci/${{ matrix.theme }}/final.json"
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

  full-gate:
    name: Full gate
    needs: [plan, global-static, runtime-engine-selftest, theme-verify]
    if: always()
    runs-on: themefactory-ci
    steps:
      - name: Fail closed on any required stage
        shell: bash
        run: |
          set -euo pipefail
          [[ "${{ needs.plan.result }}" == success ]]
          [[ "${{ needs.global-static.result }}" == success ]]
          if [[ "${{ needs.plan.outputs.runtime_infra_changed }}" == true ]]; then
            [[ "${{ needs.runtime-engine-selftest.result }}" == success ]]
          fi
          if [[ "${{ needs.plan.outputs.themes }}" != '[]' ]]; then
            [[ "${{ needs.theme-verify.result }}" == success ]]
          fi
