name: "Releasing PR"

on:
  pull_request:
    types: [closed]
    paths-ignore:
      - 'docs/**/*'

# Cancel in‑flight runs for the same PR when a new push arrives.
concurrency:
  group: pr-${{ github.workflow }}-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  finalize:
    name: Finalize Release
    runs-on: [self-hosted]
    permissions:
      contents: write

    if: |
      github.event.pull_request.merged == true &&
      contains(github.event.pull_request.labels.*.name, 'release')

    steps:
      # Extract tag from branch name  (branch = release-X.Y.Z*)
      - name: Extract tag from branch name
        id: get_tag
        uses: actions/github-script@v7
        with:
          script: |
            const branch = context.payload.pull_request.head.ref;
            const m = branch.match(/^release-(\d+\.\d+\.\d+(?:[-\w\.]+)?)$/);
            if (!m) {
              core.setFailed(`Branch '${branch}' does not match 'release-X.Y.Z[-suffix]'`);
              return;
            }
            const tag = `v${m[1]}`;
            core.setOutput('tag', tag);
            console.log(`✅ Tag to publish: ${tag}`);

      # Checkout repo & create / push annotated tag
      - name: Checkout repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Create tag on merge commit
        run: |
          git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }}
          git push -f origin ${{ steps.get_tag.outputs.tag }}

      # Ensure maintenance branch release-X.Y
      - name: Ensure maintenance branch release-X.Y
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GH_PAT }}
          script: |
            const tag = '${{ steps.get_tag.outputs.tag }}';  // e.g. v0.1.3 or v0.1.3-rc3
            const match = tag.match(/^v(\d+)\.(\d+)\.\d+(?:[-\w\.]+)?$/);
            if (!match) {
              core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-suffix'`);
              return;
            }
            const line = `${match[1]}.${match[2]}`;
            const branch = `release-${line}`;

            // Get main branch commit for the tag
            const ref = await github.rest.git.getRef({
              owner: context.repo.owner,
              repo:  context.repo.repo,
              ref:   `tags/${tag}`
            });

            const commitSha = ref.data.object.sha;

            try {
              await github.rest.repos.getBranch({
                owner: context.repo.owner,
                repo: context.repo.repo,
                branch
              });
           
              await github.rest.git.updateRef({
                owner: context.repo.owner,
                repo: context.repo.repo,
                ref: `heads/${branch}`,
                sha: commitSha,
                force: true
              });
              console.log(`🔁 Force-updated '${branch}' to ${commitSha}`);
            } catch (err) {
              if (err.status === 404) {
                await github.rest.git.createRef({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  ref: `refs/heads/${branch}`,
                  sha: commitSha
                });
                console.log(`✅ Created branch '${branch}' at ${commitSha}`);
              } else {
                console.error('Unexpected error --', err);
                core.setFailed(`Unexpected error creating/updating branch: ${err.message}`);
                throw err;
              }
            }

      # Get the latest published release
      - name: Get the latest published release
        id: latest_release
        uses: actions/github-script@v7
        with:
          script: |
            try {
              const rel = await github.rest.repos.getLatestRelease({
                owner: context.repo.owner,
                repo:  context.repo.repo
              });
              core.setOutput('tag', rel.data.tag_name);
            } catch (_) {
              core.setOutput('tag', '');
            }

      # Compare current tag vs latest using semver-utils
      - name: Semver compare
        id: semver
        uses: madhead/semver-utils@v4.3.0
        with:
          version:    ${{ steps.get_tag.outputs.tag }}
          compare-to: ${{ steps.latest_release.outputs.tag }}

      # Derive flags: prerelease?  make_latest?
      - name: Calculate publish flags
        id: flags
        uses: actions/github-script@v7
        with:
          script: |
            const tag = '${{ steps.get_tag.outputs.tag }}';              // v0.31.5-rc.1
            const m = tag.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/);
            if (!m) {
              core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`);
              return;
            }
            const version = m[1] + (m[2] ?? '');                         // 0.31.5-rc.1
            const isRc    = Boolean(m[2]);
            core.setOutput('is_rc',      isRc);
            const outdated = '${{ steps.semver.outputs.comparison-result }}' === '<';
            core.setOutput('make_latest', isRc || outdated ? 'false' : 'legacy');

      # Publish draft release with correct flags
      - name: Publish draft release
        uses: actions/github-script@v7
        with:
          script: |
            const tag = '${{ steps.get_tag.outputs.tag }}';
            const releases = await github.rest.repos.listReleases({
              owner: context.repo.owner,
              repo:  context.repo.repo
            });
            const draft = releases.data.find(r => r.tag_name === tag && r.draft);
            if (!draft) throw new Error(`Draft release for ${tag} not found`);
            await github.rest.repos.updateRelease({
              owner:       context.repo.owner,
              repo:        context.repo.repo,
              release_id:  draft.id,
              draft:       false,
              prerelease:  ${{ steps.flags.outputs.is_rc }},
              make_latest: '${{ steps.flags.outputs.make_latest }}'
            });

            console.log(`🚀 Published release for ${tag}`);
