name: Release

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  release:
    if: ${{ github.ref == 'refs/heads/main' }}
    runs-on: ubuntu-latest

    permissions:
      contents: write
      issues: write
      pull-requests: write
      id-token: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          # PAT_TOKEN required: semantic-release pushes version bump commits to main,
          # which needs branch protection bypass. github.token cannot push to protected branches.
          token: ${{ secrets.PAT_TOKEN }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          registry-url: 'https://registry.npmjs.org'

      - name: Setup Bun
        uses: oven-sh/setup-bun@v2
        with:
          bun-version: '1.3.9'

      - name: Install dependencies
        run: |
          bun install --frozen-lockfile
          cd ui && bun install --frozen-lockfile

      - name: Build package
        run: bun run build:all

      - name: Validate (typecheck + lint + format + tests)
        run: bun run validate

      - name: Release
        id: release
        env:
          HUSKY: 0
          # PAT_TOKEN bypasses branch protection so semantic-release can push
          # version bump + CHANGELOG commits directly to main
          GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
          GH_TOKEN: ${{ secrets.PAT_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          set +e
          OUTPUT=$(bunx semantic-release 2>&1)
          STATUS=$?
          set -e
          echo "$OUTPUT"
          # Strip ANSI color codes before matching (semantic-release outputs colored text)
          CLEAN=$(echo "$OUTPUT" | sed 's/\x1b\[[0-9;]*m//g')
          if [[ "$STATUS" -ne 0 ]]; then
            echo "released=false" >> $GITHUB_OUTPUT
            exit "$STATUS"
          fi
          if echo "$CLEAN" | grep -q "Published GitHub release"; then
            echo "released=true" >> $GITHUB_OUTPUT
          else
            echo "released=false" >> $GITHUB_OUTPUT
          fi

      - name: Notify Discord
        if: success() && steps.release.outputs.released == 'true'
        env:
          DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
        run: |
          if [ -z "$DISCORD_WEBHOOK_URL" ]; then
            echo "DISCORD_WEBHOOK_URL not set, skipping"
            exit 0
          fi
          node scripts/send-discord-release.cjs production "$DISCORD_WEBHOOK_URL"

      - name: Cleanup labels and close released issues
        if: success() && steps.release.outputs.released == 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          VERSION=$(jq -r '.version' package.json)
          RELEASE_BODY=$(gh release view "v${VERSION}" --repo "${{ github.repository }}" --json body --jq '.body' 2>/dev/null || echo "")
          PREVIOUS_STABLE_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]" --sort=-v:refname | \
            grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | \
            grep -vx "v${VERSION}" | head -1 || echo "")
          RANGE="${PREVIOUS_STABLE_TAG:+${PREVIOUS_STABLE_TAG}..HEAD~1}"
          if [[ -z "$RANGE" ]]; then
            RANGE="HEAD~50..HEAD~1"
          fi

          COMMIT_TEXT=$(git log $RANGE --pretty=format:"%s%n%b" 2>/dev/null || true)
          PR_CANDIDATES=$(printf '%s\n' "$COMMIT_TEXT" | \
            grep -oE "Merge pull request #[0-9]+|\\(#[0-9]+\\)" | \
            grep -oE "[0-9]+" | sort -u || true)

          PR_TEXT=""
          for PR_NUM in $PR_CANDIDATES; do
            DETAILS=$(gh pr view "$PR_NUM" --repo "${{ github.repository }}" --json title,body --jq '.title + "\n" + (.body // "")' 2>/dev/null || true)
            if [[ -n "$DETAILS" ]]; then
              PR_TEXT="${PR_TEXT}"$'\n'"${DETAILS}"
            fi
          done

          RELEASE_ISSUES_FROM_BODY=$(printf '%s\n' "$RELEASE_BODY" | \
            perl -ne 'if (/(fixes|closes|resolves|refs?)(.*)/i) { print "$2\n"; }' | \
            grep -oE '#[0-9]+' | tr -d '#' || true)
          RELEASE_ISSUES_FROM_COMMITS=$(printf '%s\n' "$COMMIT_TEXT" | \
            perl -ne 'if (/(fixes|closes|resolves|refs?)(.*)/i) { print "$2\n"; }' | \
            grep -oE '#[0-9]+' | tr -d '#' || true)
          RELEASE_ISSUES_FROM_PRS=$(printf '%s\n' "$PR_TEXT" | \
            perl -ne 'if (/(fixes|closes|resolves|refs?)(.*)/i) { print "$2\n"; }' | \
            grep -oE '#[0-9]+' | tr -d '#' || true)
          RELEASE_ISSUES=$(printf '%s\n%s\n%s\n' \
            "$RELEASE_ISSUES_FROM_BODY" \
            "$RELEASE_ISSUES_FROM_COMMITS" \
            "$RELEASE_ISSUES_FROM_PRS" | sort -u || true)

          RESOLVED_ISSUES_FROM_BODY=$(printf '%s\n' "$RELEASE_BODY" | \
            perl -ne 'if (/(fixes|closes|resolves)(.*)/i) { print "$2\n"; }' | \
            grep -oE '#[0-9]+' | tr -d '#' || true)
          RESOLVED_ISSUES_FROM_COMMITS=$(printf '%s\n' "$COMMIT_TEXT" | \
            perl -ne 'if (/(fixes|closes|resolves)(.*)/i) { print "$2\n"; }' | \
            grep -oE '#[0-9]+' | tr -d '#' || true)
          RESOLVED_ISSUES_FROM_PRS=$(printf '%s\n' "$PR_TEXT" | \
            perl -ne 'if (/(fixes|closes|resolves)(.*)/i) { print "$2\n"; }' | \
            grep -oE '#[0-9]+' | tr -d '#' || true)
          RESOLVED_ISSUES=$(printf '%s\n%s\n%s\n' \
            "$RESOLVED_ISSUES_FROM_BODY" \
            "$RESOLVED_ISSUES_FROM_COMMITS" \
            "$RESOLVED_ISSUES_FROM_PRS" | sort -u || true)

          if [[ -z "$RELEASE_ISSUES" ]]; then
            echo "No release-scoped issues found for v${VERSION}"
            exit 0
          fi

          for NUM in $RELEASE_ISSUES; do
            echo "Cleaning release state on issue #$NUM"
            gh issue edit "$NUM" \
              --remove-label "released-dev" \
              --remove-label "pending-release" \
              --repo "${{ github.repository }}" 2>/dev/null || true

            HAS_RELEASED=$(gh issue view "$NUM" --repo "${{ github.repository }}" --json labels --jq '[.labels[].name | select(. == "released")] | length' 2>/dev/null || echo "0")
            if [[ "$HAS_RELEASED" -gt 0 ]] && printf '%s\n' "$RESOLVED_ISSUES" | grep -qx "$NUM"; then
              gh issue close "$NUM" \
                --comment "[bot] Closing issue because this fix/feature is now in stable release (@latest)." \
                --repo "${{ github.repository }}" || true
            fi
          done
