name: Pub Homebrew Core

on:
  workflow_call:
    inputs:
      release_tag:
        description: "Existing release tag to publish (vX.Y.Z)"
        required: true
        type: string
      dry_run:
        description: "Patch formula only (no push/PR)"
        required: false
        default: false
        type: boolean
    secrets:
      HOMEBREW_UPSTREAM_PR_TOKEN:
        required: false
      HOMEBREW_CORE_BOT_TOKEN:
        required: false
  workflow_dispatch:
    inputs:
      release_tag:
        description: "Existing release tag to publish (vX.Y.Z)"
        required: true
        type: string
      dry_run:
        description: "Patch formula only (no push/PR)"
        required: false
        default: true
        type: boolean

concurrency:
  group: homebrew-core-${{ github.run_id }}
  cancel-in-progress: false

permissions:
  contents: read

jobs:
  publish-homebrew-core:
    name: Publish Homebrew Core PR
    runs-on: ubuntu-latest
    env:
      UPSTREAM_REPO: Homebrew/homebrew-core
      FORMULA_PATH: Formula/z/construct.rb
      RELEASE_TAG: ${{ inputs.release_tag }}
      DRY_RUN: ${{ inputs.dry_run }}
      BOT_FORK_REPO: ${{ vars.HOMEBREW_CORE_BOT_FORK_REPO }}
      BOT_EMAIL: ${{ vars.HOMEBREW_CORE_BOT_EMAIL }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Validate release tag and version alignment
        id: release_meta
        shell: bash
        run: |
          set -euo pipefail

          semver_pattern='^v[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$'
          if [[ ! "$RELEASE_TAG" =~ $semver_pattern ]]; then
            echo "::error::release_tag must match semver-like format (vX.Y.Z[-suffix])."
            exit 1
          fi

          if ! git rev-parse "refs/tags/${RELEASE_TAG}" >/dev/null 2>&1; then
            git fetch --tags origin
          fi

          tag_version="${RELEASE_TAG#v}"
          cargo_version="$(git show "${RELEASE_TAG}:Cargo.toml" \
            | sed -n 's/^version = "\([^"]*\)"/\1/p' | head -n1)"
          if [[ -z "$cargo_version" ]]; then
            echo "::error::Unable to read Cargo.toml version from tag ${RELEASE_TAG}."
            exit 1
          fi
          if [[ "$cargo_version" != "$tag_version" ]]; then
            echo "::error::Tag ${RELEASE_TAG} does not match Cargo.toml version (${cargo_version})."
            exit 1
          fi

          tarball_url="https://github.com/${GITHUB_REPOSITORY}/archive/refs/tags/${RELEASE_TAG}.tar.gz"
          tarball_sha="$(curl -fsSL "$tarball_url" | sha256sum | awk '{print $1}')"

          {
            echo "tag_version=$tag_version"
            echo "tarball_url=$tarball_url"
            echo "tarball_sha=$tarball_sha"
          } >> "$GITHUB_OUTPUT"

          {
            echo "### Release Metadata"
            echo "- release_tag: \`${RELEASE_TAG}\`"
            echo "- cargo_version: \`${cargo_version}\`"
            echo "- tarball_sha256: \`${tarball_sha}\`"
            echo "- dry_run: ${DRY_RUN}"
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Patch Homebrew formula
        id: patch_formula
        shell: bash
        env:
          HOMEBREW_CORE_BOT_TOKEN: ${{ secrets.HOMEBREW_UPSTREAM_PR_TOKEN || secrets.HOMEBREW_CORE_BOT_TOKEN }}
          GH_TOKEN: ${{ secrets.HOMEBREW_UPSTREAM_PR_TOKEN || secrets.HOMEBREW_CORE_BOT_TOKEN }}
          TARBALL_URL: ${{ steps.release_meta.outputs.tarball_url }}
          TARBALL_SHA: ${{ steps.release_meta.outputs.tarball_sha }}
        run: |
          set -euo pipefail

          tmp_repo="$(mktemp -d)"
          echo "tmp_repo=$tmp_repo" >> "$GITHUB_OUTPUT"

          if [[ "$DRY_RUN" == "true" ]]; then
            git clone --depth=1 "https://github.com/${UPSTREAM_REPO}.git" "$tmp_repo/homebrew-core"
          else
            if [[ -z "${BOT_FORK_REPO}" ]]; then
              echo "::error::Repository variable HOMEBREW_CORE_BOT_FORK_REPO is required when dry_run=false."
              exit 1
            fi
            if [[ -z "${HOMEBREW_CORE_BOT_TOKEN}" ]]; then
              echo "::error::Repository secret HOMEBREW_CORE_BOT_TOKEN is required when dry_run=false."
              exit 1
            fi
            if [[ "$BOT_FORK_REPO" != */* ]]; then
              echo "::error::HOMEBREW_CORE_BOT_FORK_REPO must be in owner/repo format."
              exit 1
            fi
            if ! gh api "repos/${BOT_FORK_REPO}" >/dev/null 2>&1; then
              echo "::error::HOMEBREW_CORE_BOT_TOKEN cannot access ${BOT_FORK_REPO}."
              exit 1
            fi
            gh repo clone "${BOT_FORK_REPO}" "$tmp_repo/homebrew-core" -- --depth=1
          fi

          repo_dir="$tmp_repo/homebrew-core"
          formula_file="$repo_dir/$FORMULA_PATH"
          if [[ ! -f "$formula_file" ]]; then
            echo "::error::Formula file not found: $FORMULA_PATH"
            exit 1
          fi

          if [[ "$DRY_RUN" == "false" ]]; then
            if git -C "$repo_dir" remote get-url upstream >/dev/null 2>&1; then
              git -C "$repo_dir" remote set-url upstream "https://github.com/${UPSTREAM_REPO}.git"
            else
              git -C "$repo_dir" remote add upstream "https://github.com/${UPSTREAM_REPO}.git"
            fi
            if git -C "$repo_dir" ls-remote --exit-code --heads upstream main >/dev/null 2>&1; then
              upstream_ref="main"
            else
              upstream_ref="master"
            fi
            git -C "$repo_dir" fetch --depth=1 upstream "$upstream_ref"
            branch_name="construct-${RELEASE_TAG}-${GITHUB_RUN_ID}"
            git -C "$repo_dir" checkout -B "$branch_name" "upstream/$upstream_ref"
            echo "branch_name=$branch_name" >> "$GITHUB_OUTPUT"
          fi

          tarball_url="${TARBALL_URL}"
          tarball_sha="${TARBALL_SHA}"

          if [[ -z "$tarball_url" || -z "$tarball_sha" ]]; then
            echo "::error::tarball_url or tarball_sha is empty — release_meta step output not propagated."
            exit 1
          fi

          perl -0pi -e "s|^  url \".*\"|  url \"${tarball_url}\"|m" "$formula_file"
          perl -0pi -e "s|^  sha256 \".*\"|  sha256 \"${tarball_sha}\"|m" "$formula_file"
          perl -0pi -e "s|^  license \".*\"|  license \"Apache-2.0 OR MIT\"|m" "$formula_file"

          # Ensure Node.js build dependency is declared so that build.rs can
          # run `npm ci && npm run build` to produce the web frontend assets.
          if ! grep -q 'depends_on "node" => :build' "$formula_file"; then
            perl -0pi -e 's|(  depends_on "rust" => :build\n)|\1  depends_on "node" => :build\n|m' "$formula_file"
          fi

          git -C "$repo_dir" diff -- "$FORMULA_PATH" > "$tmp_repo/formula.diff"
          if [[ ! -s "$tmp_repo/formula.diff" ]]; then
            echo "::error::No formula changes generated. Nothing to publish."
            exit 1
          fi

          {
            echo "### Formula Diff"
            echo '```diff'
            cat "$tmp_repo/formula.diff"
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Push branch and open Homebrew PR
        if: inputs.dry_run == false
        shell: bash
        env:
          GH_TOKEN: ${{ secrets.HOMEBREW_UPSTREAM_PR_TOKEN || secrets.HOMEBREW_CORE_BOT_TOKEN }}
          TMP_REPO: ${{ steps.patch_formula.outputs.tmp_repo }}
          BRANCH_NAME: ${{ steps.patch_formula.outputs.branch_name }}
          TAG_VERSION: ${{ steps.release_meta.outputs.tag_version }}
          TARBALL_URL: ${{ steps.release_meta.outputs.tarball_url }}
          TARBALL_SHA: ${{ steps.release_meta.outputs.tarball_sha }}
        run: |
          set -euo pipefail

          repo_dir="${TMP_REPO}/homebrew-core"
          fork_owner="${BOT_FORK_REPO%%/*}"
          bot_email="${BOT_EMAIL:-${fork_owner}@users.noreply.github.com}"

          # Pre-flight: verify token has push access to the fork
          if ! gh api "repos/${BOT_FORK_REPO}" --jq '.permissions.push' 2>/dev/null | grep -q true; then
            echo "::error::Token lacks push access to ${BOT_FORK_REPO}. Ensure HOMEBREW_CORE_BOT_TOKEN (or HOMEBREW_UPSTREAM_PR_TOKEN) is a PAT with 'Contents: write' scope for ${BOT_FORK_REPO}."
            exit 1
          fi

          git -C "$repo_dir" config user.name "$fork_owner"
          git -C "$repo_dir" config user.email "$bot_email"
          git -C "$repo_dir" add "$FORMULA_PATH"
          git -C "$repo_dir" commit -m "construct ${TAG_VERSION}"
          gh auth setup-git
          git -C "$repo_dir" push --set-upstream origin "$BRANCH_NAME"

          pr_body="Automated formula bump from Construct release workflow.

          - Release tag: ${RELEASE_TAG}
          - Source tarball: ${TARBALL_URL}
          - Source sha256: ${TARBALL_SHA}"

          gh pr create \
            --repo "$UPSTREAM_REPO" \
            --base main \
            --head "${fork_owner}:${BRANCH_NAME}" \
            --title "construct ${TAG_VERSION}" \
            --body "$pr_body"

      - name: Summary
        shell: bash
        run: |
          if [[ "$DRY_RUN" == "true" ]]; then
            echo "Dry run complete: formula diff generated, no push/PR performed."
          else
            echo "Publish complete: branch pushed and PR opened from bot fork."
          fi
