name: Nix Lockfile Fix

on:
  workflow_dispatch:
    inputs:
      pr_number:
        description: 'PR number to fix (leave empty to run on the selected branch)'
        required: false
        type: string
  issue_comment:
    types: [edited]

permissions:
  contents: write
  pull-requests: write

concurrency:
  group: nix-lockfile-fix-${{ github.event.issue.number || github.event.inputs.pr_number || github.ref }}
  cancel-in-progress: false

jobs:
  fix:
    # Run on manual dispatch OR when a task-list checkbox in the sticky
    # lockfile-check comment flips from `[ ]` to `[x]`.
    if: |
      github.event_name == 'workflow_dispatch' ||
      (github.event_name == 'issue_comment'
       && github.event.issue.pull_request != null
       && contains(github.event.comment.body, '[x] **Apply lockfile fix**')
       && !contains(github.event.changes.body.from, '[x] **Apply lockfile fix**'))
    runs-on: ubuntu-latest
    timeout-minutes: 25
    steps:
      - name: Authorize & resolve PR
        id: resolve
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea  # v7.0.1
        with:
          script: |
            // 1. Verify the actor has write access — applies to both checkbox
            //    clicks and manual dispatch.
            const { data: perm } =
              await github.rest.repos.getCollaboratorPermissionLevel({
                owner: context.repo.owner,
                repo: context.repo.repo,
                username: context.actor,
              });
            if (!['admin', 'write', 'maintain'].includes(perm.permission)) {
              core.setFailed(
                `${context.actor} lacks write access (has: ${perm.permission})`
              );
              return;
            }

            // 2. Resolve which ref to check out.
            let prNumber = '';
            if (context.eventName === 'issue_comment') {
              prNumber = String(context.payload.issue.number);
            } else if (context.eventName === 'workflow_dispatch') {
              prNumber = context.payload.inputs.pr_number || '';
            }

            if (!prNumber) {
              core.setOutput('ref', context.ref.replace(/^refs\/heads\//, ''));
              core.setOutput('repo', context.repo.repo);
              core.setOutput('owner', context.repo.owner);
              core.setOutput('pr', '');
              return;
            }

            const { data: pr } = await github.rest.pulls.get({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: Number(prNumber),
            });
            core.setOutput('ref', pr.head.ref);
            core.setOutput('repo', pr.head.repo.name);
            core.setOutput('owner', pr.head.repo.owner.login);
            core.setOutput('pr', String(pr.number));

      # Wipe the sticky lockfile-check comment to a "running" state as soon
      # as the job is authorized, so the user sees their click was picked up
      # before the ~minute of nix build work.
      - name: Mark sticky as running
        if: steps.resolve.outputs.pr != ''
        uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728  # v2.9.1
        with:
          header: nix-lockfile-check
          number: ${{ steps.resolve.outputs.pr }}
          message: |
            ### 🔄 Applying lockfile fix…

            Triggered by @${{ github.actor }} — [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).

      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4
        with:
          repository: ${{ steps.resolve.outputs.owner }}/${{ steps.resolve.outputs.repo }}
          ref: ${{ steps.resolve.outputs.ref }}
          token: ${{ secrets.GITHUB_TOKEN }}
          fetch-depth: 0

      - uses: ./.github/actions/nix-setup

      - name: Apply lockfile hashes
        id: apply
        run: nix run .#fix-lockfiles -- --apply

      - name: Commit & push
        if: steps.apply.outputs.changed == 'true'
        shell: bash
        run: |
          set -euo pipefail
          git config user.name 'github-actions[bot]'
          git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
          git add nix/tui.nix nix/web.nix
          git commit -m "fix(nix): refresh npm lockfile hashes"
          git push

      - name: Update sticky (applied)
        if: steps.apply.outputs.changed == 'true' && steps.resolve.outputs.pr != ''
        uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728  # v2.9.1
        with:
          header: nix-lockfile-check
          number: ${{ steps.resolve.outputs.pr }}
          message: |
            ### ✅ Lockfile fix applied

            Pushed a commit refreshing the npm lockfile hashes — [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).

      - name: Update sticky (already current)
        if: steps.apply.outputs.changed == 'false' && steps.resolve.outputs.pr != ''
        uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728  # v2.9.1
        with:
          header: nix-lockfile-check
          number: ${{ steps.resolve.outputs.pr }}
          message: |
            ### ✅ Lockfile hashes already current

            Nothing to commit — [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).

      - name: Update sticky (failed)
        if: failure() && steps.resolve.outputs.pr != ''
        uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728  # v2.9.1
        with:
          header: nix-lockfile-check
          number: ${{ steps.resolve.outputs.pr }}
          message: |
            ### ❌ Lockfile fix failed

            See the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for logs.
