---
name: Smart Bidirectional Sync

'on':
  issues:
    types: [labeled, closed, reopened]

# Prevent sync loops with debouncing
concurrency:
  group: smart-sync-${{ github.event.issue.number }}
  cancel-in-progress: true  # Cancel pending runs (debouncing effect)

jobs:
  determine-direction:
    runs-on: ubuntu-latest
    timeout-minutes: 3
    permissions:
      contents: read
      issues: read
      id-token: write

    outputs:
      should_sync: ${{ steps.check.outputs.should_sync }}
      direction: ${{ steps.check.outputs.direction }}
      issue_number: ${{ steps.check.outputs.issue_number }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Check Workflow Kill Switch
        run: |
            if [ -f ".github/WORKFLOW_KILLSWITCH" ]; then
              STATUS=$(grep "STATUS:" .github/WORKFLOW_KILLSWITCH | awk '{print $2}')
              if [ "$STATUS" = "DISABLED" ]; then
                echo "🛑 Workflows disabled by kill switch"
                exit 0
              fi
            fi
      - name: Determine Sync Direction
        id: check
        run: |
          # Check which event triggered this workflow
          if [ "${{ github.event_name }}" = "issues" ]; then
            # Issue event → sync to project board
            echo "direction=issue-to-project" >> $GITHUB_OUTPUT
            echo "issue_number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT

            # Only sync on status label changes or state changes
            if [[ "${{ github.event.action }}" == "labeled" && "${{ github.event.label.name }}" == status:* ]] || \
               [ "${{ github.event.action }}" = "closed" ] || \
               [ "${{ github.event.action }}" = "reopened" ]; then
              echo "should_sync=true" >> $GITHUB_OUTPUT
              echo "✅ Will sync: Issue #${{ github.event.issue.number }} → Project Board"
            else
              echo "should_sync=false" >> $GITHUB_OUTPUT
              echo "⏭️ Skipping: Not a status change or state change"
            fi

          else
            echo "should_sync=false" >> $GITHUB_OUTPUT
            echo "⚠️ Unknown event type"
          fi

  rate-limit-check:
    needs: determine-direction
    if: needs.determine-direction.outputs.should_sync == 'true'
    runs-on: ubuntu-latest
    timeout-minutes: 2
    permissions:
      contents: read

    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    outputs:
      can_proceed: ${{ steps.limits.outputs.can_proceed }}

    steps:
      - name: Check Rate Limits (Circuit Breaker)
        id: limits
        run: |
          echo "🔍 Checking GitHub API rate limits..."

          # Get rate limit status
          core_remaining=$(gh api rate_limit --jq '.resources.core.remaining')
          core_limit=$(gh api rate_limit --jq '.resources.core.limit')
          graphql_remaining=$(gh api rate_limit --jq '.resources.graphql.remaining')
          graphql_limit=$(gh api rate_limit --jq '.resources.graphql.limit')

          echo "📊 Rate Limits:"
          echo "  REST API: $core_remaining/$core_limit"
          echo "  GraphQL: $graphql_remaining/$graphql_limit"

          # Require at least 50 remaining for sync operations
          if [ "$core_remaining" -lt 50 ] || [ "$graphql_remaining" -lt 50 ]; then
            echo "can_proceed=false" >> $GITHUB_OUTPUT
            echo "⚠️ Rate limits too low. Skipping sync to prevent violations."
            exit 0
          fi

          echo "can_proceed=true" >> $GITHUB_OUTPUT
          echo "✅ Rate limits sufficient for sync operation"

  # 10-second debounce delay
  debounce:
    needs: [determine-direction, rate-limit-check]
    if: |
      needs.determine-direction.outputs.should_sync == 'true' &&
      needs.rate-limit-check.outputs.can_proceed == 'true'
    runs-on: ubuntu-latest
    timeout-minutes: 1

    steps:
      - name: Debounce Delay
        run: |
          echo "⏱️ Applying 10-second debounce..."
          sleep 10
          echo "✅ Debounce complete. Proceeding with sync."

  sync-issue-to-project:
    needs: [determine-direction, rate-limit-check, debounce]
    if: |
      needs.determine-direction.outputs.direction == 'issue-to-project' &&
      needs.rate-limit-check.outputs.can_proceed == 'true'
    runs-on: ubuntu-latest
    timeout-minutes: 5
    permissions:
      contents: read
      issues: read
      id-token: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Sync Issue to Project Board
        env:
          GH_TOKEN: ${{ secrets.PROJECTS_TOKEN }}
          ISSUE_TITLE: ${{ github.event.issue.title }}
        run: |
          echo "# Issue → Project Board Sync"
          echo "**Issue**: #${{ github.event.issue.number }} \"$ISSUE_TITLE\""
          echo "**State**: ${{ github.event.issue.state }}"
          echo "**Action**: ${{ github.event.action }}"

          # Step 1: Check if in Project
          PROJECT_ITEM=$(gh api graphql -f query='
            query {
              repository(owner: "alirezarezvani", name: "claude-skills") {
                issue(number: ${{ github.event.issue.number }}) {
                  projectItems(first: 10) {
                    nodes {
                      id
                      project { number }
                    }
                  }
                }
              }
            }
          ' --jq '.data.repository.issue.projectItems.nodes[] | select(.project.number == 9) | .id')

          if [ -z "$PROJECT_ITEM" ]; then
            echo "Adding to project..."
            gh project item-add 9 --owner alirezarezvani --url ${{ github.event.issue.html_url }}
            sleep 2

            PROJECT_ITEM=$(gh api graphql -f query='
              query {
                repository(owner: "alirezarezvani", name: "claude-skills") {
                  issue(number: ${{ github.event.issue.number }}) {
                    projectItems(first: 10) {
                      nodes {
                        id
                        project { number }
                      }
                    }
                  }
                }
              }
            ' --jq '.data.repository.issue.projectItems.nodes[] | select(.project.number == 9) | .id')
          fi

          echo "Project Item ID: $PROJECT_ITEM"

          # Step 2: Determine Target Status
          LABELS=$(gh issue view ${{ github.event.issue.number }} --json labels --jq '[.labels[].name] | join(",")')
          ISSUE_STATE="${{ github.event.issue.state }}"

          # Priority order: closed state > status labels > default
          if [ "$ISSUE_STATE" = "closed" ]; then
            TARGET_STATUS="Done"
          elif echo "$LABELS" | grep -q "status: done"; then
            TARGET_STATUS="Done"
          elif echo "$LABELS" | grep -q "status: in-review"; then
            TARGET_STATUS="In Review"
          elif echo "$LABELS" | grep -q "status: in-progress"; then
            TARGET_STATUS="In Progress"
          elif echo "$LABELS" | grep -q "status: ready"; then
            TARGET_STATUS="Ready"
          elif echo "$LABELS" | grep -q "status: backlog"; then
            TARGET_STATUS="Backlog"
          elif echo "$LABELS" | grep -q "status: triage"; then
            TARGET_STATUS="To triage"
          else
            TARGET_STATUS=$([ "$ISSUE_STATE" = "open" ] && echo "To triage" || echo "Done")
          fi

          echo "Target Status: $TARGET_STATUS"

          # Step 3: Get Project IDs
          PROJECT_DATA=$(gh api graphql -f query='
            query {
              user(login: "alirezarezvani") {
                projectV2(number: 9) {
                  id
                  fields(first: 20) {
                    nodes {
                      ... on ProjectV2SingleSelectField {
                        id
                        name
                        options {
                          id
                          name
                        }
                      }
                    }
                  }
                }
              }
            }
          ')

          PROJECT_ID=$(echo "$PROJECT_DATA" | jq -r '.data.user.projectV2.id')
          STATUS_FIELD_ID=$(echo "$PROJECT_DATA" | \
            jq -r '.data.user.projectV2.fields.nodes[] | select(.name == "Status") | .id')
          STATUS_OPTION_ID=$(echo "$PROJECT_DATA" | jq -r --arg status "$TARGET_STATUS" \
            '.data.user.projectV2.fields.nodes[] | select(.name == "Status") | .options[] | select(.name == $status) | .id')

          # Step 4: Update Project Board
          if [ -n "$PROJECT_ITEM" ] && [ -n "$STATUS_OPTION_ID" ]; then
            gh api graphql -f query='
              mutation {
                updateProjectV2ItemFieldValue(
                  input: {
                    projectId: "'"$PROJECT_ID"'"
                    itemId: "'"$PROJECT_ITEM"'"
                    fieldId: "'"$STATUS_FIELD_ID"'"
                    value: { singleSelectOptionId: "'"$STATUS_OPTION_ID"'" }
                  }
                ) {
                  projectV2Item { id }
                }
              }
            '
            echo "✅ Project board updated to: $TARGET_STATUS"
          else
            echo "⚠️ Could not update (missing IDs)"
          fi

  sync-project-to-issue:
    needs: [determine-direction, rate-limit-check, debounce]
    if: |
      needs.determine-direction.outputs.direction == 'project-to-issue' &&
      needs.rate-limit-check.outputs.can_proceed == 'true'
    runs-on: ubuntu-latest
    timeout-minutes: 5
    permissions:
      contents: read
      issues: write
      id-token: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Sync Project Board to Issue
        env:
          GH_TOKEN: ${{ secrets.PROJECTS_TOKEN }}
          ISSUE_TITLE: ${{ github.event.issue.title }}
        run: |
          echo "# Project Board → Issue Sync"
          echo "**Project Item**: ${{ github.event.projects_v2_item.node_id }}"
          echo "**Content**: ${{ github.event.projects_v2_item.content_node_id }}"
          echo "**Changed By**: @${{ github.event.sender.login }}"

          # Step 1: Get Issue Number
          CONTENT_ID="${{ github.event.projects_v2_item.content_node_id }}"

          ISSUE_DATA=$(gh api graphql -f query='
            query {
              node(id: "${{ github.event.projects_v2_item.node_id }}") {
                ... on ProjectV2Item {
                  content {
                    ... on Issue {
                      number
                      url
                      state
                      title
                    }
                  }
                }
              }
            }
          ')

          ISSUE_NUMBER=$(echo "$ISSUE_DATA" | jq -r '.data.node.content.number')

          if [ -z "$ISSUE_NUMBER" ] || [ "$ISSUE_NUMBER" = "null" ]; then
            echo "⏭️ Not an issue (might be PR or other content)"
            exit 0
          fi

          echo "Issue Number: $ISSUE_NUMBER"

          # Step 2: Get Project Status
          STATUS=$(gh api graphql -f query='
            query {
              node(id: "${{ github.event.projects_v2_item.node_id }}") {
                ... on ProjectV2Item {
                  fieldValues(first: 20) {
                    nodes {
                      ... on ProjectV2ItemFieldSingleSelectValue {
                        name
                        field {
                          ... on ProjectV2SingleSelectField {
                            name
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          ' --jq '.data.node.fieldValues.nodes[] | select(.field.name == "Status") | .name')

          if [ -z "$STATUS" ]; then
            echo "⏭️ No status field found"
            exit 0
          fi

          echo "Project Status: $STATUS"

          # Step 3: Map Status to Label
          case "$STATUS" in
            "To triage") NEW_LABEL="status: triage" ;;
            "Backlog") NEW_LABEL="status: backlog" ;;
            "Ready") NEW_LABEL="status: ready" ;;
            "In Progress") NEW_LABEL="status: in-progress" ;;
            "In Review") NEW_LABEL="status: in-review" ;;
            "Done") NEW_LABEL="status: done" ;;
            *)
              echo "⏭️ Unknown status: $STATUS"
              exit 0
              ;;
          esac

          echo "Target Label: $NEW_LABEL"

          # Step 4: Update Issue Labels
          CURRENT_LABELS=$(gh issue view $ISSUE_NUMBER --json labels --jq '[.labels[].name] | join(",")')

          # Remove all status: labels
          for label in "status: triage" "status: backlog" "status: ready" "status: in-progress" "status: in-review" "status: done"; do
            if echo "$CURRENT_LABELS" | grep -q "$label"; then
              gh issue edit $ISSUE_NUMBER --remove-label "$label" 2>/dev/null || true
            fi
          done

          # Add new status label
          gh issue edit $ISSUE_NUMBER --add-label "$NEW_LABEL"
          echo "✅ Label updated to: $NEW_LABEL"

          # Step 5: Handle Issue State
          CURRENT_STATE=$(gh issue view $ISSUE_NUMBER --json state --jq '.state')

          if [ "$STATUS" = "Done" ] && [ "$CURRENT_STATE" = "OPEN" ]; then
            gh issue close $ISSUE_NUMBER --reason completed
            echo "✅ Issue closed (moved to Done)"
          elif [ "$STATUS" != "Done" ] && [ "$CURRENT_STATE" = "CLOSED" ]; then
            gh issue reopen $ISSUE_NUMBER
            echo "✅ Issue reopened (moved from Done)"
          fi

          echo "✅ Sync complete: Issue #$ISSUE_NUMBER updated to $STATUS"
