name: Automated Code Review

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write
  checks: read

jobs:
  automated-review:
    name: AI-Assisted Code Review
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: frontends/nextjs
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Cache Bun dependencies
        uses: actions/cache@v4
        with:
          key: bun-deps-${{ runner.os }}-${{ hashFiles('bun.lock') }}
          path: |
            frontends/nextjs/node_modules
            ~/.bun
          restore-keys: bun-deps-${{ runner.os }}-

      - name: Install dependencies
        run: bun install --frozen-lockfile

      - name: Generate Prisma Client
        run: bun run db:generate
        env:
          DATABASE_URL: file:./dev.db

      - name: Run linter for review
        id: lint
        run: |
          bun run lint > lint-output.txt 2>&1 || echo "LINT_FAILED=true" >> $GITHUB_OUTPUT
          cat lint-output.txt
        continue-on-error: true

      - name: Analyze code changes
        id: analyze
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            
            // Get PR diff
            const { data: files } = await github.rest.pulls.listFiles({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number,
            });
            
            let issues = [];
            let warnings = [];
            let suggestions = [];
            
            // Analyze each file
            for (const file of files) {
              const patch = file.patch || '';
              const filename = file.filename;
              
              // Check for security issues
              if (patch.match(/eval\s*\(/)) {
                issues.push(`⚠️ **Security**: Use of \`eval()\` found in ${filename}`);
              }
              if (patch.match(/innerHTML\s*=/)) {
                warnings.push(`⚠️ **Security**: Direct \`innerHTML\` usage in ${filename}. Consider using safer alternatives.`);
              }
              if (patch.match(/dangerouslySetInnerHTML/)) {
                warnings.push(`⚠️ **Security**: \`dangerouslySetInnerHTML\` usage in ${filename}. Ensure content is sanitized.`);
              }
              
              // Check for code quality
              if (patch.match(/console\.(log|debug|info)/)) {
                warnings.push(`🔍 **Code Quality**: Console statements found in ${filename}. Remove before merging.`);
              }
              if (patch.match(/debugger/)) {
                issues.push(`🐛 **Debug Code**: Debugger statement found in ${filename}. Remove before merging.`);
              }
              if (patch.match(/(:\s*any\b|\bany\s*[>;,\)])/)) {
                suggestions.push(`💡 **Type Safety**: Consider replacing \`any\` types with specific types in ${filename}`);
              }
              
              // Check for best practices
              if (filename.endsWith('.tsx') || filename.endsWith('.jsx')) {
                if (patch.match(/useEffect.*\[\]/) && !patch.includes('// eslint-disable')) {
                  suggestions.push(`💡 **React**: Empty dependency array in useEffect in ${filename}. Verify if intentional.`);
                }
              }
              
              // Check for large files
              if (file.additions > 500) {
                warnings.push(`📏 **File Size**: ${filename} has ${file.additions} additions. Consider breaking into smaller files.`);
              }
            }
            
            // Read lint output if exists
            let lintIssues = '';
            try {
              lintIssues = fs.readFileSync('lint-output.txt', 'utf8');
            } catch (e) {
              // File doesn't exist
            }
            
            // Determine if auto-approve is appropriate
            const hasBlockingIssues = issues.length > 0 || lintIssues.includes('error');
            
            return {
              issues,
              warnings,
              suggestions,
              lintIssues,
              hasBlockingIssues,
              fileCount: files.length,
              totalAdditions: files.reduce((sum, f) => sum + f.additions, 0),
              totalDeletions: files.reduce((sum, f) => sum + f.deletions, 0)
            };

      - name: Post review comment
        uses: actions/github-script@v7
        with:
          script: |
            const analysis = JSON.parse('${{ steps.analyze.outputs.result }}');
            
            let comment = '## 🤖 Automated Code Review\n\n';
            comment += `**Changes Summary:**\n`;
            comment += `- Files changed: ${analysis.fileCount}\n`;
            comment += `- Lines added: ${analysis.totalAdditions}\n`;
            comment += `- Lines deleted: ${analysis.totalDeletions}\n\n`;
            
            if (analysis.issues.length > 0) {
              comment += '### ❌ Blocking Issues\n\n';
              analysis.issues.forEach(issue => comment += `- ${issue}\n`);
              comment += '\n';
            }
            
            if (analysis.warnings.length > 0) {
              comment += '### ⚠️ Warnings\n\n';
              analysis.warnings.forEach(warning => comment += `- ${warning}\n`);
              comment += '\n';
            }
            
            if (analysis.suggestions.length > 0) {
              comment += '### 💡 Suggestions\n\n';
              analysis.suggestions.forEach(suggestion => comment += `- ${suggestion}\n`);
              comment += '\n';
            }
            
            if (analysis.lintIssues && analysis.lintIssues.includes('error')) {
              comment += '### 🔴 Linting Errors\n\n';
              comment += '```\n' + analysis.lintIssues + '\n```\n\n';
            }
            
            if (analysis.hasBlockingIssues) {
              comment += '---\n';
              comment += '### ❌ Review Status: **CHANGES REQUESTED**\n\n';
              comment += 'Please address the blocking issues above before this PR can be approved.\n';
            } else {
              comment += '---\n';
              comment += '### ✅ Review Status: **APPROVED**\n\n';
              comment += 'No blocking issues found! This PR looks good to merge after CI checks pass.\n';
            }
            
            // Check if we already commented
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
            });
            
            const botComment = comments.find(c => 
              c.user.type === 'Bot' && c.body.includes('Automated Code Review')
            );
            
            if (botComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: botComment.id,
                body: comment
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: comment
              });
            }

      - name: Add labels based on review
        uses: actions/github-script@v7
        with:
          script: |
            const analysis = JSON.parse('${{ steps.analyze.outputs.result }}');
            
            let labels = [];
            
            if (analysis.hasBlockingIssues) {
              labels.push('needs-changes');
            } else {
              labels.push('ready-for-review');
            }
            
            if (analysis.warnings.length > 0) {
              labels.push('has-warnings');
            }
            
            if (analysis.totalAdditions > 500) {
              labels.push('large-pr');
            }
            
            // Remove conflicting labels first
            try {
              await github.rest.issues.removeLabel({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                name: 'needs-changes'
              });
            } catch (e) {
              // Label doesn't exist
            }
            
            try {
              await github.rest.issues.removeLabel({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                name: 'ready-for-review'
              });
            } catch (e) {
              // Label doesn't exist
            }
            
            // Add new labels
            for (const label of labels) {
              try {
                await github.rest.issues.addLabels({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: context.issue.number,
                  labels: [label]
                });
              } catch (e) {
                console.log(`Label ${label} might not exist, skipping...`);
              }
            }

      - name: Auto-approve if no issues
        if: steps.analyze.outputs.result && !fromJSON(steps.analyze.outputs.result).hasBlockingIssues
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            await github.rest.pulls.createReview({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number,
              event: 'APPROVE',
              body: '✅ Automated review passed! No blocking issues found. This PR is approved pending successful CI checks.'
            });
