name: PR Checks

on:
  pull_request:
    types: [opened, synchronize, reopened, edited]
    branches:
      - dev
      - main

# Default permissions for all jobs
# Note: Fork PRs won't have write access for security
# Advisory checks use separate workflow (pr-checks-run.yml + pr-checks-comment.yml)
permissions:
  contents: read           # Read repository contents
  pull-requests: write     # Manage PRs (labels, comments) - only works for non-fork PRs
  issues: write           # Manage issues (PRs are issues) - only works for non-fork PRs

jobs:
  # Validate PR title and description
  validate-pr:
    name: Validate PR Format
    runs-on: ubuntu-latest
    # Inherits workflow-level permissions (contents: read, pull-requests: write, issues: write)
    steps:
      - name: Check PR title format
        id: semantic-pr
        continue-on-error: true  # Don't block PR if title format is invalid
        uses: amannn/action-semantic-pull-request@v5
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          types: |
            feat
            fix
            docs
            style
            refactor
            perf
            test
            chore
            ci
            security
            build
          scopes: |
            exchange
            trader
            ai
            api
            ui
            frontend
            backend
            security
            deps
            workflow
            github
            actions
            config
            docker
            build
            release
          requireScope: false

      - name: Comment on invalid PR title
        if: steps.semantic-pr.outcome == 'failure'
        uses: actions/github-script@v7
        continue-on-error: true  # Don't fail for fork PRs
        with:
          script: |
            const prTitle = context.payload.pull_request.title;
            const isFork = context.payload.pull_request.head.repo.full_name !== context.payload.pull_request.base.repo.full_name;

            const comment = [
              '## ⚠️ PR Title Format Suggestion',
              '',
              "Your PR title doesn't follow the Conventional Commits format, but **this won't block your PR from being merged**.",
              '',
              `**Current title:** \`${prTitle}\``,
              '',
              '**Recommended format:** `type(scope): description`',
              '',
              '### Valid types:',
              '`feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `security`, `build`',
              '',
              '### Common scopes (optional):',
              '`exchange`, `trader`, `ai`, `api`, `ui`, `frontend`, `backend`, `security`, `deps`, `workflow`, `github`, `actions`, `config`, `docker`, `build`, `release`',
              '',
              '### Examples:',
              '- `feat(trader): add new trading strategy`',
              '- `fix(api): resolve authentication issue`',
              '- `docs: update README`',
              '- `chore(deps): update dependencies`',
              '- `ci(workflow): improve GitHub Actions`',
              '',
              '**Note:** This is a suggestion to improve consistency. Your PR can still be reviewed and merged.',
              '',
              '---',
              '*This is an automated comment. You can update the PR title anytime.*'
            ].join('\n');

            if (!isFork) {
              try {
                await github.rest.issues.createComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: context.payload.pull_request.number,
                  body: comment
                });
              } catch (error) {
                console.log('Could not post comment (expected for fork PRs):', error.message);
              }
            } else {
              console.log('Fork PR - comment will be posted by pr-checks-comment.yml');
            }

      - name: Check PR size
        uses: actions/github-script@v7
        continue-on-error: true  # Don't fail for fork PRs
        with:
          script: |
            const pr = context.payload.pull_request;
            const additions = pr.additions;
            const deletions = pr.deletions;
            const total = additions + deletions;

            // Check if this is a fork PR
            const isFork = pr.head.repo.full_name !== pr.base.repo.full_name;

            let label = '';
            let comment = '';

            if (total < 300) {
              label = 'size: small';
              comment = '✅ This PR is **small** and easy to review!';
            } else if (total < 1000) {
              label = 'size: medium';
              comment = '⚠️ This PR is **medium** sized. Consider breaking it into smaller PRs if possible.';
            } else {
              label = 'size: large';
              comment = '🚨 This PR is **large** (>' + total + ' lines changed). Please consider breaking it into smaller, focused PRs for easier review.';
            }

            // Only add labels/comments for non-fork PRs (fork PRs don't have write permission)
            if (!isFork) {
              try {
                // Add size label
                await github.rest.issues.addLabels({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: pr.number,
                  labels: [label]
                });

                // Add comment for large PRs
                if (total >= 1000) {
                  await github.rest.issues.createComment({
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    issue_number: pr.number,
                    body: comment
                  });
                }
              } catch (error) {
                console.log('Failed to add label/comment (expected for fork PRs):', error.message);
              }
            } else {
              console.log('Fork PR detected - skipping label/comment (will be handled by pr-checks-comment.yml)');
            }

  # Backend checks (simplified - no TA-Lib required)
  backend-checks:
    name: Backend Code Quality (Go)
    runs-on: ubuntu-latest
    permissions:
      contents: read      # Only need read access for testing
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.21'

      - name: Cache Go modules
        uses: actions/cache@v4
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-go-

      - name: Download dependencies
        run: go mod download

      - name: Run go fmt
        continue-on-error: true  # Don't block PR if formatting issues found
        run: |
          if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
            echo "⚠️ Code formatting issues found. Please run 'go fmt ./...' locally."
            echo ""
            echo "Files needing formatting:"
            gofmt -s -l .
            echo ""
            echo "This is a warning and won't block your PR from being merged."
            exit 1
          else
            echo "✅ All Go files are properly formatted"
          fi

      - name: Run go vet
        run: go vet ./...

      - name: Build
        run: go build -v -o nofx

  # Frontend tests
  frontend-tests:
    name: Frontend Tests (React/TypeScript)
    runs-on: ubuntu-latest
    permissions:
      contents: read      # Only need read access for testing
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'

      - name: Cache Node modules
        uses: actions/cache@v4
        with:
          path: web/node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('web/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Install dependencies
        working-directory: ./web
        run: npm ci

      - name: Build and Type Check
        working-directory: ./web
        run: npm run build
        # Note: build script runs "tsc && vite build" which includes type checking

  # Auto-label based on files changed
  auto-label:
    name: Auto Label PR
    runs-on: ubuntu-latest
    # Only run for non-fork PRs (fork PRs don't have write permission)
    if: github.event.pull_request.head.repo.full_name == github.repository
    permissions:
      contents: read
      pull-requests: write
      issues: write          # Required: PRs are issues, labeler needs to modify issue labels
    steps:
      - uses: actions/labeler@v5
        with:
          configuration-path: .github/labeler.yml
          repo-token: ${{ secrets.GITHUB_TOKEN }}

  # Check for security issues
  security-check:
    name: Security Scan
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write # Required: Upload SARIF results to GitHub Security
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - name: Upload Trivy results
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: 'trivy-results.sarif'

  # Check for secrets in code
  secrets-check:
    name: Check for Secrets
    runs-on: ubuntu-latest
    permissions:
      contents: read      # Only need read access for scanning
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Run TruffleHog OSS
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          base: ${{ github.event.pull_request.base.sha }}
          head: ${{ github.event.pull_request.head.sha }}
          extra_args: --debug --only-verified

  # All checks passed
  all-checks:
    name: All Checks Passed
    runs-on: ubuntu-latest
    needs: [validate-pr, backend-checks, frontend-tests, security-check, secrets-check]
    if: always()
    permissions:
      contents: read      # Only need read access for status checking
    steps:
      - name: Check all jobs
        run: |
          # Note: validate-pr uses continue-on-error, so it won't block even if title format is invalid
          # We only care about actual test failures
          echo "validate-pr: ${{ needs.validate-pr.result }}"
          echo "backend-checks: ${{ needs.backend-checks.result }}"
          echo "frontend-tests: ${{ needs.frontend-tests.result }}"
          echo "security-check: ${{ needs.security-check.result }}"
          echo "secrets-check: ${{ needs.secrets-check.result }}"

          # Check if any critical checks failed (excluding validate-pr which is advisory)
          if [[ "${{ needs.backend-checks.result }}" == "failure" ]] || \
             [[ "${{ needs.frontend-tests.result }}" == "failure" ]] || \
             [[ "${{ needs.security-check.result }}" == "failure" ]] || \
             [[ "${{ needs.secrets-check.result }}" == "failure" ]]; then
            echo "❌ Critical checks failed"
            exit 1
          else
            echo "✅ All critical checks passed!"
            if [[ "${{ needs.validate-pr.result }}" != "success" ]]; then
              echo "ℹ️  Note: PR title format check is advisory only and doesn't block merging"
            fi
          fi
