# ============================================================================
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Validation
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/joomla/repo_health.yml.template
# VERSION: 09.23.00
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
# ============================================================================

name: "Generic: Repo Health"

defaults:
  run:
    shell: bash

on:
  workflow_dispatch:
    inputs:
      profile:
        description: 'Validation profile: all, scripts, or repo'
        required: true
        default: all
        type: choice
        options:
          - all
          - scripts
          - repo
  pull_request:
  push:

permissions:
  contents: read

env:
  # Scripts governance policy
  SCRIPTS_REQUIRED_DIRS:
  SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate

  # Repo health policy
  REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogitea/workflows/
  REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/
  REPO_DISALLOWED_DIRS:
  REPO_DISALLOWED_FILES: TODO.md,todo.md

  # Extended checks toggles
  EXTENDED_CHECKS: "true"

  # File / directory variables
  DOCS_INDEX: docs/docs-index.md
  SCRIPT_DIR: scripts
  WORKFLOWS_DIR: .mokogitea/workflows
  SHELLCHECK_PATTERN: '*.sh'
  SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml'
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
  access_check:
    name: Access control
    runs-on: ubuntu-latest
    timeout-minutes: 10
    permissions:
      contents: read

    outputs:
      allowed: ${{ steps.perm.outputs.allowed }}
      permission: ${{ steps.perm.outputs.permission }}

    steps:
      - name: Check actor permission (admin only)
        id: perm
        env:
          TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
          REPO: ${{ github.repository }}
          ACTOR: ${{ github.actor }}
        run: |
          set -euo pipefail
          ALLOWED=false
          PERMISSION=unknown
          METHOD=""

          # Hardcoded authorized users — always allowed
          case "$ACTOR" in
            jmiller|gitea-actions[bot])
              ALLOWED=true
              PERMISSION=admin
              METHOD="hardcoded allowlist"
              ;;
            *)
              # Detect platform and check permissions via API
              API_BASE="${GITHUB_API_URL:-${GITEA_API_URL:-https://api.github.com}}"
              RESP=$(curl -sf -H "Authorization: token ${TOKEN}" \
                "${API_BASE}/repos/${REPO}/collaborators/${ACTOR}/permission" 2>/dev/null || echo '{}')
              PERMISSION=$(echo "$RESP" | grep -oP '"permission"\s*:\s*"\K[^"]+' || echo "unknown")
              if [ "$PERMISSION" = "admin" ] || [ "$PERMISSION" = "maintain" ] || [ "$PERMISSION" = "owner" ]; then
                ALLOWED=true
              fi
              METHOD="collaborator API"
              ;;
          esac

          echo "permission=${PERMISSION}" >> "$GITHUB_OUTPUT"
          echo "allowed=${ALLOWED}" >> "$GITHUB_OUTPUT"

          {
            echo "## Access Authorization"
            echo ""
            echo "| Field | Value |"
            echo "|-------|-------|"
            echo "| **Actor** | \`${ACTOR}\` |"
            echo "| **Repository** | \`${REPO}\` |"
            echo "| **Permission** | \`${PERMISSION}\` |"
            echo "| **Method** | ${METHOD} |"
            echo "| **Authorized** | ${ALLOWED} |"
            echo ""
            if [ "$ALLOWED" = "true" ]; then
              echo "${ACTOR} authorized (${METHOD})"
            else
              echo "${ACTOR} is NOT authorized. Requires admin or maintain role."
            fi
          } >> "${GITHUB_STEP_SUMMARY}"

      - name: Deny execution when not permitted
        if: ${{ steps.perm.outputs.allowed != 'true' }}
        run: |
          set -euo pipefail
          printf '%s\n' 'ERROR: Access denied. Admin permission required.' >> "${GITHUB_STEP_SUMMARY}"
          exit 1

  scripts_governance:
    name: Scripts governance
    needs: access_check
    if: ${{ needs.access_check.outputs.allowed == 'true' }}
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          fetch-depth: 0

      - name: Scripts folder checks
        env:
          PROFILE_RAW: ${{ github.event.inputs.profile }}
        run: |
          set -euo pipefail

          profile="${PROFILE_RAW:-all}"
          case "${profile}" in
            all|scripts|repo) ;;
            *)
              printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
              exit 1
              ;;
          esac

          if [ "${profile}" = 'repo' ]; then
            {
              printf '%s\n' '### Scripts governance'
              printf '%s\n' "Profile: ${profile}"
              printf '%s\n' 'Status: SKIPPED'
              printf '%s\n' 'Reason: profile excludes scripts governance'
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
            exit 0
          fi

          if [ ! -d "${SCRIPT_DIR}" ]; then
            {
              printf '%s\n' '### Scripts governance'
              printf '%s\n' 'Status: OK (advisory)'
              printf '%s\n' 'scripts/ directory not present. No scripts governance enforced.'
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
            exit 0
          fi

          if [ -n "${SCRIPTS_REQUIRED_DIRS:-}" ]; then IFS=',' read -r -a required_dirs <<< "${SCRIPTS_REQUIRED_DIRS}"; else required_dirs=(); fi
          IFS=',' read -r -a allowed_dirs <<< "${SCRIPTS_ALLOWED_DIRS}"

          missing_dirs=()
          unapproved_dirs=()

          for d in "${required_dirs[@]}"; do
            req="${d%/}"
            [ ! -d "${req}" ] && missing_dirs+=("${req}/")
          done

          while IFS= read -r d; do
            allowed=false
            for a in "${allowed_dirs[@]}"; do
              a_norm="${a%/}"
              [ "${d%/}" = "${a_norm}" ] && allowed=true
            done
            [ "${allowed}" = false ] && unapproved_dirs+=("${d%/}/")
          done < <(find "${SCRIPT_DIR}" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sed 's#^\./##')

          {
            printf '%s\n' '### Scripts governance'
            printf '%s\n' "Profile: ${profile}"
            printf '%s\n' '| Area | Status | Notes |'
            printf '%s\n' '|---|---|---|'

            if [ "${#missing_dirs[@]}" -gt 0 ]; then
              printf '%s\n' '| Required directories | Warning | Missing required subfolders |'
            else
              printf '%s\n' '| Required directories | OK | All required subfolders present |'
            fi

            if [ "${#unapproved_dirs[@]}" -gt 0 ]; then
              printf '%s\n' '| Directory policy | Warning | Unapproved directories detected |'
            else
              printf '%s\n' '| Directory policy | OK | No unapproved directories |'
            fi

            printf '%s\n' '| Enforcement mode | Advisory | scripts folder is optional |'
            printf '\n'

            if [ "${#missing_dirs[@]}" -gt 0 ]; then
              printf '%s\n' 'Missing required script directories:'
              for m in "${missing_dirs[@]}"; do printf '%s\n' "- ${m}"; done
              printf '\n'
            else
              printf '%s\n' 'Missing required script directories: none.'
              printf '\n'
            fi

            if [ "${#unapproved_dirs[@]}" -gt 0 ]; then
              printf '%s\n' 'Unapproved script directories detected:'
              for m in "${unapproved_dirs[@]}"; do printf '%s\n' "- ${m}"; done
              printf '\n'
            else
              printf '%s\n' 'Unapproved script directories detected: none.'
              printf '\n'
            fi

            printf '%s\n' 'Scripts governance completed in advisory mode.'
            printf '\n'
          } >> "${GITHUB_STEP_SUMMARY}"

  repo_health:
    name: Repository health
    needs: access_check
    if: ${{ needs.access_check.outputs.allowed == 'true' }}
    runs-on: ubuntu-latest
    timeout-minutes: 20
    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          fetch-depth: 0

      - name: Repository health checks
        env:
          PROFILE_RAW: ${{ github.event.inputs.profile }}
        run: |
          set -euo pipefail

          profile="${PROFILE_RAW:-all}"
          case "${profile}" in
            all|scripts|repo) ;;
            *)
              printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
              exit 1
              ;;
          esac

          if [ "${profile}" = 'scripts' ]; then
            {
              printf '%s\n' '### Repository health'
              printf '%s\n' "Profile: ${profile}"
              printf '%s\n' 'Status: SKIPPED'
              printf '%s\n' 'Reason: profile excludes repository health'
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
            exit 0
          fi

          IFS=',' read -r -a required_artifacts <<< "${REPO_REQUIRED_ARTIFACTS}"
          IFS=',' read -r -a optional_files <<< "${REPO_OPTIONAL_FILES}"
          if [ -n "${REPO_DISALLOWED_DIRS:-}" ]; then IFS=',' read -r -a disallowed_dirs <<< "${REPO_DISALLOWED_DIRS}"; else disallowed_dirs=(); fi
          IFS=',' read -r -a disallowed_files <<< "${REPO_DISALLOWED_FILES:-}"

          missing_required=()
          missing_optional=()

          # Source directory: src/ or htdocs/ (either is valid for extension repos)
          SOURCE_DIR=""
          if [ -d "src" ]; then
            SOURCE_DIR="src"
          elif [ -d "htdocs" ]; then
            SOURCE_DIR="htdocs"
          elif [ -d "deploy" ] || [ -d "cli" ] || [ -d "monitoring" ]; then
            # Platform/tooling repos don't need src/
            SOURCE_DIR=""
          else
            missing_required+=("src/ or htdocs/ (source directory required)")
          fi

          for item in "${required_artifacts[@]}"; do
            if printf '%s' "${item}" | grep -q '/$'; then
              d="${item%/}"
              [ ! -d "${d}" ] && missing_required+=("${item}")
            else
              [ ! -f "${item}" ] && missing_required+=("${item}")
            fi
          done

          for f in "${optional_files[@]}"; do
            if printf '%s' "${f}" | grep -q '/$'; then
              d="${f%/}"
              [ ! -d "${d}" ] && missing_optional+=("${f}")
            else
              [ ! -f "${f}" ] && missing_optional+=("${f}")
            fi
          done

          for d in "${disallowed_dirs[@]}"; do
            d_norm="${d%/}"
            [ -d "${d_norm}" ] && missing_required+=("${d_norm}/ (disallowed)")
          done

          for f in "${disallowed_files[@]}"; do
            [ -f "${f}" ] && missing_required+=("${f} (disallowed)")
          done

          git fetch origin --prune

          dev_paths=()
          dev_branches=()

          while IFS= read -r b; do
            name="${b#origin/}"
            if [ "${name}" = 'dev' ]; then
              dev_branches+=("${name}")
            else
              dev_paths+=("${name}")
            fi
          done < <(git branch -r --list 'origin/dev*' | sed 's/^ *//')

          if [ "${#dev_paths[@]}" -eq 0 ] && [ "${#dev_branches[@]}" -eq 0 ]; then
            missing_required+=("dev or dev/* branch")
          fi

          content_warnings=()

          if [ -f 'CHANGELOG.md' ] && ! grep -Eq '^# Changelog' CHANGELOG.md; then
            content_warnings+=("CHANGELOG.md missing '# Changelog' header")
          fi

          if [ -f 'CHANGELOG.md' ] && grep -Eq '^[# ]*Unreleased' CHANGELOG.md; then
            content_warnings+=("CHANGELOG.md contains Unreleased section (review release readiness)")
          fi

          if [ -f 'LICENSE' ] && ! grep -qiE 'GNU GENERAL PUBLIC LICENSE|GPL' LICENSE; then
            content_warnings+=("LICENSE does not look like a GPL text")
          fi

          if [ -f 'README.md' ] && ! grep -qiE 'moko|Moko' README.md; then
            content_warnings+=("README.md missing expected brand keyword")
          fi

          export PROFILE_RAW="${profile}"
          export MISSING_REQUIRED="$(printf '%s\n' "${missing_required[@]:-}")"
          export MISSING_OPTIONAL="$(printf '%s\n' "${missing_optional[@]:-}")"
          export CONTENT_WARNINGS="$(printf '%s\n' "${content_warnings[@]:-}")"

          report_json=$(printf '{"profile":"%s","missing_required":%d,"missing_optional":%d,"content_warnings":%d}'             "$profile" "${#missing_required[@]}" "${#missing_optional[@]}" "${#content_warnings[@]}")

          {
            printf '%s\n' '### Repository health'
            printf '%s\n' "Profile: ${profile}"
            printf '%s\n' '| Metric | Value |'
            printf '%s\n' '|---|---|'
            printf '%s\n' "| Missing required | ${#missing_required[@]} |"
            printf '%s\n' "| Missing optional | ${#missing_optional[@]} |"
            printf '%s\n' "| Content warnings | ${#content_warnings[@]} |"
            printf '\n'

            printf '%s\n' '### Guardrails report (JSON)'
            printf '%s\n' '```json'
            printf '%s\n' "${report_json}"
            printf '%s\n' '```'
            printf '\n'
          } >> "${GITHUB_STEP_SUMMARY}"

          if [ "${#missing_required[@]}" -gt 0 ]; then
            {
              printf '%s\n' '### Missing required repo artifacts'
              for m in "${missing_required[@]}"; do printf '%s\n' "- ${m}"; done
              printf '%s\n' 'ERROR: Guardrails failed. Missing required repository artifacts.'
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
            exit 1
          fi

          if [ "${#missing_optional[@]}" -gt 0 ]; then
            {
              printf '%s\n' '### Missing optional repo artifacts'
              for m in "${missing_optional[@]}"; do printf '%s\n' "- ${m}"; done
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
          fi

          if [ "${#content_warnings[@]}" -gt 0 ]; then
            {
              printf '%s\n' '### Repo content warnings'
              for m in "${content_warnings[@]}"; do printf '%s\n' "- ${m}"; done
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
          fi

          # -- Joomla-specific checks --
          joomla_findings=()

          MANIFEST="$(find . -maxdepth 2 -name '*.xml' -exec grep -l '<extension' {} \; 2>/dev/null | head -1 || true)"
          if [ -z "${MANIFEST}" ]; then
            joomla_findings+=("Joomla XML manifest not found (no *.xml with <extension> tag)")
          else
            if ! grep -qP '<version>' "${MANIFEST}"; then
              joomla_findings+=("XML manifest: <version> tag missing")
            fi
            if ! grep -qP 'type="(component|module|plugin|library|package|template|language)"' "${MANIFEST}"; then
              joomla_findings+=("XML manifest: type attribute missing or invalid")
            fi
            if ! grep -qP '<name>' "${MANIFEST}"; then
              joomla_findings+=("XML manifest: <name> tag missing")
            fi
            if ! grep -qP '<author>' "${MANIFEST}"; then
              joomla_findings+=("XML manifest: <author> tag missing")
            fi
            if ! grep -qP '<namespace' "${MANIFEST}"; then
              joomla_findings+=("XML manifest: <namespace> missing (required for Joomla 5+)")
            fi
          fi

          INI_COUNT="$(find . -name '*.ini' -type f 2>/dev/null | wc -l)"
          if [ "${INI_COUNT}" -eq 0 ]; then
            joomla_findings+=("No .ini language files found")
          fi

          if [ ! -f 'updates.xml' ]; then
            joomla_findings+=("updates.xml missing in root (required for Joomla update server)")
          fi

          if [ -n "${SOURCE_DIR}" ]; then
            INDEX_DIRS=("${SOURCE_DIR}" "${SOURCE_DIR}/admin" "${SOURCE_DIR}/site")
            for dir in "${INDEX_DIRS[@]}"; do
              if [ -d "${dir}" ] && [ ! -f "${dir}/index.html" ]; then
                joomla_findings+=("${dir}/index.html missing (directory listing protection)")
              fi
            done
          fi

          if [ "${#joomla_findings[@]}" -gt 0 ]; then
            {
              printf '%s\n' '### Joomla extension checks'
              printf '%s\n' '| Check | Status |'
              printf '%s\n' '|---|---|'
              for f in "${joomla_findings[@]}"; do
                printf '%s\n' "| ${f} | Warning |"
              done
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
          else
            {
              printf '%s\n' '### Joomla extension checks'
              printf '%s\n' 'All Joomla-specific checks passed.'
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
          fi

          extended_enabled="${EXTENDED_CHECKS:-true}"
          extended_findings=()

          if [ "${extended_enabled}" = 'true' ]; then
            if [ -f '.github/CODEOWNERS' ] || [ -f 'CODEOWNERS' ] || [ -f 'docs/CODEOWNERS' ]; then
              :
            else
              extended_findings+=("CODEOWNERS not found (.github/CODEOWNERS preferred)")
            fi

            if ls "${WORKFLOWS_DIR}"/*.yml >/dev/null 2>&1 || ls "${WORKFLOWS_DIR}"/*.yaml >/dev/null 2>&1; then
              bad_refs="$(grep -RIn --include='*.yml' --include='*.yaml' -E '^[[:space:]]*uses:[[:space:]]*[^#]+@(main|master)\b' "${WORKFLOWS_DIR}" 2>/dev/null || true)"
              if [ -n "${bad_refs}" ]; then
                extended_findings+=("Workflows reference actions @main/@master (pin versions): see log excerpt")
                {
                  printf '%s\n' '### Workflow pinning advisory'
                  printf '%s\n' 'Found uses: entries pinned to main/master:'
                  printf '%s\n' '```'
                  printf '%s\n' "${bad_refs}"
                  printf '%s\n' '```'
                  printf '\n'
                } >> "${GITHUB_STEP_SUMMARY}"
              fi
            fi

            if [ -f "${DOCS_INDEX}" ]; then
              missing_links=""
              while IFS= read -r docline; do
                for link in $(echo "$docline" | grep -oE '\]\([^)]+\)' | sed 's/\](//' | sed 's/)$//' || true); do
                  case "$link" in http://*|https://*|"#"*|mailto:*) continue ;; esac
                  linkpath="${link%%#*}"
                  linkpath="${linkpath%%\?*}"
                  [ -z "$linkpath" ] && continue
                  if [ "${linkpath:0:1}" = "/" ]; then
                    testpath="${linkpath#/}"
                  else
                    testpath="$(dirname "${DOCS_INDEX}")/${linkpath}"
                  fi
                  [ ! -e "$testpath" ] && missing_links="${missing_links}${testpath} "
                done
              done < "${DOCS_INDEX}"
              if [ -n "${missing_links}" ]; then
                extended_findings+=("docs/docs-index.md contains broken relative links")
                {
                  printf '%s\n' '### Docs index link integrity'
                  printf '%s\n' 'Broken relative links:'
                  for bl in ${missing_links}; do
                    printf '%s\n' "- ${bl}"
                  done
                  printf '\n'
                } >> "${GITHUB_STEP_SUMMARY}"
              fi
            fi

            if [ -d "${SCRIPT_DIR}" ]; then
              if ! command -v shellcheck >/dev/null 2>&1; then
                sudo apt-get update -qq
                sudo apt-get install -y shellcheck >/dev/null
              fi

              sc_out=''
              while IFS= read -r shf; do
                [ -z "${shf}" ] && continue
                out_one="$(shellcheck -S warning -x "${shf}" 2>/dev/null || true)"
                if [ -n "${out_one}" ]; then
                  sc_out="${sc_out}${out_one}\n"
                fi
              done < <(find "${SCRIPT_DIR}" -type f -name "${SHELLCHECK_PATTERN}" 2>/dev/null | sort)

              if [ -n "${sc_out}" ]; then
                extended_findings+=("ShellCheck warnings detected (advisory)")
                sc_head="$(printf '%s' "${sc_out}" | head -n 200)"
                {
                  printf '%s\n' '### ShellCheck (advisory)'
                  printf '%s\n' '```'
                  printf '%s\n' "${sc_head}"
                  printf '%s\n' '```'
                  printf '\n'
                } >> "${GITHUB_STEP_SUMMARY}"
              fi
            fi

            spdx_missing=()
            IFS=',' read -r -a spdx_globs <<< "${SPDX_FILE_GLOBS}"
            spdx_args=()
            for g in "${spdx_globs[@]}"; do spdx_args+=("${g}"); done

            while IFS= read -r f; do
              [ -z "${f}" ] && continue
              if ! head -n 40 "${f}" | grep -q 'SPDX-License-Identifier:'; then
                spdx_missing+=("${f}")
              fi
            done < <(git ls-files "${spdx_args[@]}" 2>/dev/null || true)

            if [ "${#spdx_missing[@]}" -gt 0 ]; then
              extended_findings+=("SPDX header missing in some tracked files (advisory)")
              {
                printf '%s\n' '### SPDX header advisory'
                printf '%s\n' 'Files missing SPDX-License-Identifier (first 40 lines scan):'
                for f in "${spdx_missing[@]}"; do printf '%s\n' "- ${f}"; done
                printf '\n'
              } >> "${GITHUB_STEP_SUMMARY}"
            fi

            stale_cutoff_days=180
            stale_branches="$(git for-each-ref --format='%(refname:short) %(committerdate:unix)' refs/remotes/origin 2>/dev/null | awk -v now="$(date +%s)" -v days="${stale_cutoff_days}" '{if (now-$2 > days*86400) print $1}' | head -50)"
            if [ -n "${stale_branches}" ]; then
              extended_findings+=("Stale remote branches detected (advisory)")
              {
                printf '%s\n' '### Git hygiene advisory'
                printf '%s\n' "Branches with last commit older than ${stale_cutoff_days} days (sample up to 50):"
                while IFS= read -r b; do [ -n "${b}" ] && printf '%s\n' "- ${b}"; done <<< "${stale_branches}"
                printf '\n'
              } >> "${GITHUB_STEP_SUMMARY}"
            fi
          fi

          {
            printf '%s\n' '### Guardrails coverage matrix'
            printf '%s\n' '| Domain | Status | Notes |'
            printf '%s\n' '|---|---|---|'
            printf '%s\n' '| Access control | OK | Admin-only execution gate |'
            printf '%s\n' '| Release policy | N/A | Releases handled by MokoGitea |'
            printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |'
            printf '%s\n' '| Repo required artifacts | OK | Required, optional, disallowed enforcement |'
            printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
            if [ "${extended_enabled}" = 'true' ]; then
              if [ "${#extended_findings[@]}" -gt 0 ]; then
                printf '%s\n' '| Extended checks | Warning | See extended findings below |'
              else
                printf '%s\n' '| Extended checks | OK | No findings |'
              fi
            else
              printf '%s\n' '| Extended checks | SKIPPED | EXTENDED_CHECKS disabled |'
            fi
            printf '\n'
          } >> "${GITHUB_STEP_SUMMARY}"

          if [ "${extended_enabled}" = 'true' ] && [ "${#extended_findings[@]}" -gt 0 ]; then
            {
              printf '%s\n' '### Extended findings (advisory)'
              for f in "${extended_findings[@]}"; do printf '%s\n' "- ${f}"; done
              printf '\n'
            } >> "${GITHUB_STEP_SUMMARY}"
          fi

          printf '%s\n' 'Repository health guardrails passed.' >> "${GITHUB_STEP_SUMMARY}"


  site-health:
    name: Site Health
    runs-on: ubuntu-latest
    if: github.event_name == 'workflow_dispatch'
    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'

      - name: Uptime check
        if: env.URLS != ''
        run: |
          echo "$URLS" > /tmp/urls.txt
          php monitoring/uptime-probe.php --urls /tmp/urls.txt --timeout 15 || echo "::warning::Some sites are down"
          rm -f /tmp/urls.txt
        env:
          URLS: ${{ vars.MONITORED_URLS }}

      - name: SSL certificate check
        if: env.DOMAINS != ''
        run: |
          echo "$DOMAINS" > /tmp/domains.txt
          php monitoring/ssl-check.php --domains /tmp/domains.txt --warn-days 30 || echo "::warning::SSL certificates expiring soon"
          rm -f /tmp/domains.txt
        env:
          DOMAINS: ${{ vars.MONITORED_DOMAINS }}

      - name: Summary
        if: always()
        run: |
          echo "### Site Health" >> $GITHUB_STEP_SUMMARY
          echo "Uptime and SSL checks completed." >> $GITHUB_STEP_SUMMARY

  # ═══════════════════════════════════════════════════════════════════════
  # Issue Reporter — file issues for failed gates
  # ═══════════════════════════════════════════════════════════════════════
  report-issues:
    name: "Report Issues"
    runs-on: ubuntu-latest
    needs: [access_check, scripts_governance, repo_health]
    if: >-
      always() &&
      (needs.scripts_governance.result == 'failure' ||
       needs.repo_health.result == 'failure')

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          sparse-checkout: automation/ci-issue-reporter.sh
          sparse-checkout-cone-mode: false

      - name: "File issues for failed gates"
        env:
          GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
          GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
        run: |
          chmod +x automation/ci-issue-reporter.sh
          REPORTER="./automation/ci-issue-reporter.sh"
          WF="Repo Health"

          report_gate() {
            local gate="$1" result="$2" details="$3"
            if [ "$result" = "failure" ]; then
              "$REPORTER" --gate "$gate" --details "$details" --workflow "$WF" --severity error
            fi
          }

          report_gate "Scripts Governance" \
            "${{ needs.scripts_governance.result }}" \
            "Scripts directory policy violations detected. Review required and allowed directories."

          report_gate "Repository Health" \
            "${{ needs.repo_health.result }}" \
            "Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
