name: publish
run-name: "${{ format('release {0}', inputs.version || inputs.bump) }}"

on:
  workflow_dispatch:
    inputs:
      bump:
        description: "Bump major, minor, or patch"
        required: true
        type: choice
        default: patch
        options:
          - patch
          - minor
          - major
      version:
        description: "Override version (e.g., 3.0.0-beta.6). Takes precedence over bump."
        required: false
        type: string
      skip_platform:
        description: "Skip platform binary packages"
        required: false
        type: boolean
        default: false

concurrency: ${{ github.workflow }}-${{ github.ref }}

permissions:
  contents: write
  id-token: write
  actions: write

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest

      - name: Install dependencies
        run: bun install
        env:
          BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi"

      - name: Run mock-heavy tests (isolated)
        run: |
          # These files use mock.module() which pollutes module cache
          # Run them in separate processes to prevent cross-file contamination
          bun test src/plugin-handlers
          bun test src/hooks/atlas
          bun test src/features/tmux-subagent

      - name: Run remaining tests
        run: |
          # Run all other tests (mock-heavy ones are re-run but that's acceptable)
          bun test bin script src/cli src/config src/mcp src/index.test.ts \
            src/agents src/tools src/shared \
            src/hooks/anthropic-context-window-limit-recovery \
            src/hooks/claude-code-compatibility \
            src/hooks/context-injection \
            src/hooks/provider-toast \
            src/hooks/session-notification \
            src/hooks/sisyphus \
            src/hooks/todo-continuation-enforcer \
            src/features/background-agent \
            src/features/builtin-commands \
            src/features/builtin-skills \
            src/features/claude-code-session-state \
            src/features/hook-message-injector \
            src/features/opencode-skill-loader \
            src/features/skill-mcp-manager

  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest

      - name: Install dependencies
        run: bun install
        env:
          BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi"

      - name: Type check
        run: bun run typecheck

  publish-main:
    runs-on: ubuntu-latest
    needs: [test, typecheck]
    if: github.repository == 'code-yeongyu/oh-my-opencode'
    outputs:
      version: ${{ steps.version.outputs.version }}
      dist_tag: ${{ steps.version.outputs.dist_tag }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - run: git fetch --force --tags

      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest

      - uses: actions/setup-node@v4
        with:
          node-version: "24"
          registry-url: "https://registry.npmjs.org"

      - name: Install dependencies
        run: bun install
        env:
          BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi"

      - name: Calculate version
        id: version
        run: |
          VERSION="${{ inputs.version }}"
          if [ -z "$VERSION" ]; then
            PREV=$(curl -s https://registry.npmjs.org/oh-my-opencode/latest | jq -r '.version // "0.0.0"')
            BASE="${PREV%%-*}"
            IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE"
            case "${{ inputs.bump }}" in
              major) VERSION="$((MAJOR+1)).0.0" ;;
              minor) VERSION="${MAJOR}.$((MINOR+1)).0" ;;
              *) VERSION="${MAJOR}.${MINOR}.$((PATCH+1))" ;;
            esac
          fi
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          
          if [[ "$VERSION" == *"-"* ]]; then
            DIST_TAG=$(echo "$VERSION" | cut -d'-' -f2 | cut -d'.' -f1)
            echo "dist_tag=${DIST_TAG:-next}" >> $GITHUB_OUTPUT
          else
            echo "dist_tag=" >> $GITHUB_OUTPUT
          fi
          
          echo "Version: $VERSION"

      - name: Check if already published
        id: check
        run: |
          VERSION="${{ steps.version.outputs.version }}"
          STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode/${VERSION}")
          if [ "$STATUS" = "200" ]; then
            echo "skip=true" >> $GITHUB_OUTPUT
            echo "✓ oh-my-opencode@${VERSION} already published"
          else
            echo "skip=false" >> $GITHUB_OUTPUT
          fi

      - name: Update version
        if: steps.check.outputs.skip != 'true'
        run: |
          VERSION="${{ steps.version.outputs.version }}"
          jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json
          
          for platform in darwin-arm64 darwin-x64 linux-x64 linux-arm64 linux-x64-musl linux-arm64-musl windows-x64; do
            jq --arg v "$VERSION" '.version = $v' "packages/${platform}/package.json" > tmp.json
            mv tmp.json "packages/${platform}/package.json"
          done
          
          jq --arg v "$VERSION" '.optionalDependencies = (.optionalDependencies | to_entries | map(.value = $v) | from_entries)' package.json > tmp.json && mv tmp.json package.json

      - name: Build main package
        if: steps.check.outputs.skip != 'true'
        run: |
          bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi
          bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi
          bunx tsc --emitDeclarationOnly
          bun run build:schema

      - name: Publish main package
        if: steps.check.outputs.skip != 'true'
        run: |
          TAG_ARG=""
          if [ -n "${{ steps.version.outputs.dist_tag }}" ]; then
            TAG_ARG="--tag ${{ steps.version.outputs.dist_tag }}"
          fi
          npm publish --access public --provenance $TAG_ARG
        env:
          NPM_CONFIG_PROVENANCE: true

      - name: Git commit and tag
        if: steps.check.outputs.skip != 'true'
        run: |
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git config user.name "github-actions[bot]"
          git add package.json assets/oh-my-opencode.schema.json packages/*/package.json || true
          git diff --cached --quiet || git commit -m "release: v${{ steps.version.outputs.version }}"
          git tag -f "v${{ steps.version.outputs.version }}"
          git push origin --tags --force
          git push origin HEAD || echo "Branch push failed (non-critical)"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  trigger-platform:
    runs-on: ubuntu-latest
    needs: publish-main
    if: inputs.skip_platform != true
    steps:
      - name: Trigger platform publish workflow
        run: |
          gh workflow run publish-platform.yml \
            --repo ${{ github.repository }} \
            --ref ${{ github.ref }} \
            -f version=${{ needs.publish-main.outputs.version }} \
            -f dist_tag=${{ needs.publish-main.outputs.dist_tag }}
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  release:
    runs-on: ubuntu-latest
    needs: publish-main
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Generate changelog
        id: changelog
        run: |
          VERSION="${{ needs.publish-main.outputs.version }}"
          
          PREV_TAG=""
          if [[ "$VERSION" == *"-beta."* ]]; then
            BASE="${VERSION%-beta.*}"
            NUM="${VERSION##*-beta.}"
            PREV_NUM=$((NUM - 1))
            if [ $PREV_NUM -ge 1 ]; then
              PREV_TAG="${BASE}-beta.${PREV_NUM}"
              git rev-parse "v${PREV_TAG}" >/dev/null 2>&1 || PREV_TAG=""
            fi
          fi
          
          if [ -z "$PREV_TAG" ]; then
            PREV_TAG=$(curl -s https://registry.npmjs.org/oh-my-opencode/latest | jq -r '.version // "0.0.0"')
          fi
          
          echo "Comparing v${PREV_TAG}..v${VERSION}"
          
          # Get all commits between tags
          COMMITS=$(git log "v${PREV_TAG}..v${VERSION}" --format="%s" 2>/dev/null || echo "")
          
          # Initialize sections
          FEATURES=""
          FIXES=""
          REFACTOR=""
          DOCS=""
          OTHER=""
          
          while IFS= read -r commit; do
            [ -z "$commit" ] && continue
            # Skip chore, ci, release, test commits
            [[ "$commit" =~ ^(chore|ci|release|test|ignore) ]] && continue
            
            if [[ "$commit" =~ ^feat ]]; then
              # Extract scope and message: feat(scope): message -> **scope**: message
              if [[ "$commit" =~ ^feat\(([^)]+)\):\ (.+)$ ]]; then
                FEATURES="${FEATURES}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}"
              else
                MSG="${commit#feat: }"
                FEATURES="${FEATURES}\n- ${MSG}"
              fi
            elif [[ "$commit" =~ ^fix ]]; then
              if [[ "$commit" =~ ^fix\(([^)]+)\):\ (.+)$ ]]; then
                FIXES="${FIXES}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}"
              else
                MSG="${commit#fix: }"
                FIXES="${FIXES}\n- ${MSG}"
              fi
            elif [[ "$commit" =~ ^refactor ]]; then
              if [[ "$commit" =~ ^refactor\(([^)]+)\):\ (.+)$ ]]; then
                REFACTOR="${REFACTOR}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}"
              else
                MSG="${commit#refactor: }"
                REFACTOR="${REFACTOR}\n- ${MSG}"
              fi
            elif [[ "$commit" =~ ^docs ]]; then
              if [[ "$commit" =~ ^docs\(([^)]+)\):\ (.+)$ ]]; then
                DOCS="${DOCS}\n- **${BASH_REMATCH[1]}**: ${BASH_REMATCH[2]}"
              else
                MSG="${commit#docs: }"
                DOCS="${DOCS}\n- ${MSG}"
              fi
            else
              OTHER="${OTHER}\n- ${commit}"
            fi
          done <<< "$COMMITS"
          
          # Build release notes
          {
            echo "## What's Changed"
            echo ""
            if [ -n "$FEATURES" ]; then
              echo "### Features"
              echo -e "$FEATURES"
              echo ""
            fi
            if [ -n "$FIXES" ]; then
              echo "### Bug Fixes"
              echo -e "$FIXES"
              echo ""
            fi
            if [ -n "$REFACTOR" ]; then
              echo "### Refactoring"
              echo -e "$REFACTOR"
              echo ""
            fi
            if [ -n "$DOCS" ]; then
              echo "### Documentation"
              echo -e "$DOCS"
              echo ""
            fi
            if [ -n "$OTHER" ]; then
              echo "### Other Changes"
              echo -e "$OTHER"
              echo ""
            fi
            echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/v${PREV_TAG}...v${VERSION}"
          } > /tmp/changelog.md
          
          cat /tmp/changelog.md

      - name: Create GitHub release
        run: |
          VERSION="${{ needs.publish-main.outputs.version }}"
          gh release view "v${VERSION}" >/dev/null 2>&1 || \
            gh release create "v${VERSION}" --title "v${VERSION}" --notes-file /tmp/changelog.md
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Delete draft release
        run: gh release delete next --yes 2>/dev/null || true
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Merge to master
        continue-on-error: true
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          VERSION="${{ needs.publish-main.outputs.version }}"
          git stash --include-untracked || true
          git checkout master
          git reset --hard "v${VERSION}"
          git push -f origin master || echo "::warning::Failed to push to master"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
