# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokoplatform.Automation
# REPO: https://code.mokoconsulting.tech/MokoConsulting/mokoplatform
# PATH: /.gitea/workflows/branch-protection.yml
# BRIEF: Apply standardised branch protection rules to all governed repositories
#
# +========================================================================+
# |                   BRANCH PROTECTION SETUP                              |
# +========================================================================+
# |                                                                        |
# |  Applies protection rules for: main, dev, rc, beta, alpha       |
# |                                                                        |
# |  main  — Require PR, block rejected reviews, no force push             |
# |  dev   — Allow push, no force push, no delete                          |
# |  rc  — Allow push, no force push, no delete                          |
# |  beta — Allow push, no force push, no delete                         |
# |  alpha — Allow push, no force push, no delete                        |
# |                                                                        |
# |  jmiller has override authority on all branches.                       |
# |                                                                        |
# +========================================================================+

name: Branch Protection Setup

on:
  schedule:
    - cron: '0 2 * * 1'  # Weekly Monday 02:00 UTC
  workflow_dispatch:
    inputs:
      dry_run:
        description: 'Preview mode (no changes)'
        required: false
        type: boolean
        default: false
      repos:
        description: 'Comma-separated repo names (empty = all governed repos)'
        required: false
        type: string
        default: ''

env:
  GITEA_URL: https://code.mokoconsulting.tech
  GITEA_ORG: MokoConsulting

permissions:
  contents: read

jobs:
  protect:
    name: Apply Branch Protection Rules
    runs-on: ubuntu-latest

    steps:
      - name: Determine target repos
        id: repos
        env:
          GA_TOKEN: ${{ secrets.GA_TOKEN }}
        run: |
          API="${GITEA_URL}/api/v1"

          # Platform/standards/infra repos to exclude
          EXCLUDE="gitea-org-config org-profile gitea-private .mokogitea-private MokoStandards mokoplatform MokoTesting"
          EXCLUDE="$EXCLUDE MokoStandards-Template-Client MokoStandards-Template-Dolibarr MokoStandards-Template-Generic MokoStandards-Template-Joomla MokoDoliProjTemplate"

          if [ -n "${{ inputs.repos }}" ]; then
            # User-specified repos
            REPOS=$(echo "${{ inputs.repos }}" | tr ',' ' ')
          else
            # Fetch all org repos
            PAGE=1
            REPOS=""
            while true; do
              BATCH=$(curl -sS \
                -H "Authorization: token ${GA_TOKEN}" \
                "${API}/orgs/${GITEA_ORG}/repos?page=${PAGE}&limit=50" \
                | jq -r '.[].name // empty')
              [ -z "$BATCH" ] && break
              REPOS="$REPOS $BATCH"
              PAGE=$((PAGE + 1))
            done

            # Filter out excluded repos
            FILTERED=""
            for REPO in $REPOS; do
              SKIP=false
              for EX in $EXCLUDE; do
                if [ "$REPO" = "$EX" ]; then
                  SKIP=true
                  break
                fi
              done
              if [ "$SKIP" = "false" ]; then
                FILTERED="$FILTERED $REPO"
              fi
            done
            REPOS="$FILTERED"
          fi

          echo "repos=$REPOS" >> "$GITHUB_OUTPUT"
          COUNT=$(echo "$REPOS" | wc -w)
          echo "📋 Target repos (${COUNT}): $REPOS"

      - name: Apply protection rules
        env:
          GA_TOKEN: ${{ secrets.GA_TOKEN }}
          DRY_RUN: ${{ inputs.dry_run || 'false' }}
        run: |
          API="${GITEA_URL}/api/v1"
          REPOS="${{ steps.repos.outputs.repos }}"

          SUCCESS=0
          FAILED=0
          SKIPPED=0

          # ── Rule definitions ──────────────────────────────────────
          # Only the CI bot (jmiller token) can push directly.
          # All human contributors must use PRs.
          # Force push disabled on all branches.

          RULE_MAIN='{
            "rule_name": "main",
            "enable_push": true,
            "enable_push_whitelist": true,
            "push_whitelist_usernames": ["jmiller"],
            "enable_force_push": false,
            "enable_force_push_allowlist": false,
            "force_push_allowlist_usernames": [],
            "enable_merge_whitelist": false,
            "required_approvals": 0,
            "dismiss_stale_approvals": true,
            "block_on_rejected_reviews": true,
            "block_on_outdated_branch": false,
            "priority": 1
          }'

          RULE_DEV='{
            "rule_name": "dev",
            "enable_push": true,
            "enable_push_whitelist": true,
            "push_whitelist_usernames": ["jmiller"],
            "enable_force_push": false,
            "enable_force_push_allowlist": false,
            "force_push_allowlist_usernames": [],
            "enable_merge_whitelist": false,
            "required_approvals": 0,
            "block_on_rejected_reviews": false,
            "priority": 2
          }'

          RULE_RC='{
            "rule_name": "rc",
            "enable_push": true,
            "enable_push_whitelist": true,
            "push_whitelist_usernames": ["jmiller"],
            "enable_force_push": false,
            "enable_force_push_allowlist": false,
            "force_push_allowlist_usernames": [],
            "enable_merge_whitelist": false,
            "required_approvals": 0,
            "block_on_rejected_reviews": false,
            "priority": 3
          }'

          RULE_BETA='{
            "rule_name": "beta",
            "enable_push": true,
            "enable_push_whitelist": true,
            "push_whitelist_usernames": ["jmiller"],
            "enable_force_push": false,
            "enable_force_push_allowlist": false,
            "force_push_allowlist_usernames": [],
            "enable_merge_whitelist": false,
            "required_approvals": 0,
            "block_on_rejected_reviews": false,
            "priority": 4
          }'

          RULE_ALPHA='{
            "rule_name": "alpha",
            "enable_push": true,
            "enable_push_whitelist": true,
            "push_whitelist_usernames": ["jmiller"],
            "enable_force_push": false,
            "enable_force_push_allowlist": false,
            "force_push_allowlist_usernames": [],
            "enable_merge_whitelist": false,
            "required_approvals": 0,
            "block_on_rejected_reviews": false,
            "priority": 5
          }'

          RULES=("$RULE_MAIN" "$RULE_DEV" "$RULE_RC" "$RULE_BETA" "$RULE_ALPHA")
          RULE_NAMES=("main" "dev" "rc" "beta" "alpha")

          # ── Apply rules to each repo ──────────────────────────────
          for REPO in $REPOS; do
            echo ""
            echo "═══ ${REPO} ═══"

            for i in "${!RULES[@]}"; do
              RULE="${RULES[$i]}"
              NAME="${RULE_NAMES[$i]}"

              if [ "$DRY_RUN" = "true" ]; then
                echo "  [DRY RUN] Would apply rule: ${NAME}"
                SKIPPED=$((SKIPPED + 1))
                continue
              fi

              # Delete existing rule if present (idempotent recreate)
              ENCODED_NAME=$(echo "$NAME" | sed 's|/|%2F|g')
              curl -sS -o /dev/null -w "" \
                -X DELETE \
                -H "Authorization: token ${GA_TOKEN}" \
                "${API}/repos/${GITEA_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true

              # Create rule
              RESPONSE=$(curl -sS -w "\n%{http_code}" \
                -X POST \
                -H "Authorization: token ${GA_TOKEN}" \
                -H "Content-Type: application/json" \
                -d "$RULE" \
                "${API}/repos/${GITEA_ORG}/${REPO}/branch_protections")

              HTTP=$(echo "$RESPONSE" | tail -1)
              BODY=$(echo "$RESPONSE" | sed '$d')

              if [ "$HTTP" = "201" ]; then
                echo "  ✅ ${NAME}"
                SUCCESS=$((SUCCESS + 1))
              else
                echo "  ❌ ${NAME} (HTTP ${HTTP}): $(echo "$BODY" | jq -r '.message // .' 2>/dev/null | head -1)"
                FAILED=$((FAILED + 1))
              fi
            done
          done

          # ── Summary ───────────────────────────────────────────────
          echo ""
          echo "════════════════════════════════════════"
          echo "  ✅ Success: ${SUCCESS}"
          echo "  ❌ Failed:  ${FAILED}"
          echo "  ⏭️  Skipped: ${SKIPPED}"
          echo "════════════════════════════════════════"

          if [ "$FAILED" -gt 0 ]; then
            echo "::warning::${FAILED} rule(s) failed to apply"
          fi
