import { JSONSchema7 } from 'json-schema';
import { randomUUID } from 'crypto';
import { createTool, createSuccessResult, createErrorResult } from '../../core/tool-framework.js';
import { ToolRegistration, RequestContext } from '../../core/types.js';
import { promises as fs } from 'fs';
import path from 'path';

/**
 * Code Analysis Tools - 12-Factor MCP Implementation
 * 
 * Implements Factor 2: Deterministic Execution with structured outputs
 * Implements Factor 3: Stateless Processes with RequestContext
 * Implements Factor 4: Structured Outputs for LLM consumption
 */

// Input type interfaces
interface AnalyzeCodeQualityInput {
  files?: string[];
  directories?: string[];
  includeHistory?: boolean;
  compareWithBaseline?: boolean;
  maxIssues?: number;
  excludePatterns?: string[];
  customRules?: Array<{
    name: string;
    pattern: string;
    severity: 'error' | 'warning' | 'info';
    category: string;
    message: string;
  }>;
}

interface ReviewCodeInput {
  file: string;
  compareWith?: string;
  includeHistory?: boolean;
  focusAreas?: Array<'security' | 'performance' | 'maintainability' | 'style' | 'testing'>;
}

interface TrackCodeMetricsInput {
  projectId?: string;
  branch?: string;
  commit?: string;
  tags?: string[];
}

interface GetAnalysisHistoryInput {
  limit?: number;
  includeBaseline?: boolean;
}

interface GetCodeReviewsInput {
  fileFilter?: string;
  limit?: number;
}

interface SetMetricsBaselineInput {
  historyId?: string;
  tags?: string[];
}

interface GetMetricsTrendsInput {
  metricPath: string;
  days?: number;
}

interface ManageCustomRulesInput {
  action: 'list' | 'add' | 'update' | 'delete' | 'toggle';
  ruleId?: string;
  rule?: {
    name: string;
    description: string;
    pattern: string;
    severity: 'error' | 'warning' | 'info';
    category: string;
    message: string;
  };
}

/**
 * Analyze code quality with comprehensive metrics and issue detection
 */
const analyzeCodeQualityTool = createTool<AnalyzeCodeQualityInput, any>({
  name: 'analyze_code_quality',
  description: 'Perform comprehensive code quality analysis with complexity metrics and issue detection',
  category: 'code-analysis',
  inputSchema: {
    type: 'object',
    properties: {
      files: {
        type: 'array',
        items: { type: 'string' },
        description: 'Specific files to analyze'
      },
      directories: {
        type: 'array',
        items: { type: 'string' },
        description: 'Directories to recursively analyze'
      },
      includeHistory: {
        type: 'boolean',
        description: 'Save results to history for trend analysis',
        default: false
      },
      compareWithBaseline: {
        type: 'boolean',
        description: 'Compare results with baseline metrics',
        default: false
      },
      maxIssues: {
        type: 'number',
        description: 'Maximum number of issues to report',
        default: 100
      },
      excludePatterns: {
        type: 'array',
        items: { type: 'string' },
        description: 'Glob patterns to exclude from analysis'
      },
      customRules: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            name: { type: 'string' },
            pattern: { type: 'string' },
            severity: { type: 'string', enum: ['error', 'warning', 'info'] },
            category: { type: 'string' },
            message: { type: 'string' }
          },
          required: ['name', 'pattern', 'severity', 'category', 'message']
        },
        description: 'Custom rules to apply during analysis'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: AnalyzeCodeQualityInput, context: RequestContext) {
    try {
      const projectId = context.projectId || 'default';
      const analysisId = `analysis-${randomUUID()}`;
      const now = Date.now();

      // Collect files to analyze
      let filesToAnalyze: string[] = [];
      
      if (input.files && input.files.length > 0) {
        filesToAnalyze = input.files;
      }
      
      if (input.directories && input.directories.length > 0) {
        for (const dir of input.directories) {
          const dirFiles = await findCodeFiles(dir, input.excludePatterns || []);
          filesToAnalyze.push(...dirFiles);
        }
      }

      if (filesToAnalyze.length === 0) {
        return createErrorResult({
          code: 'VALIDATION_ERROR',
          message: 'No files specified for analysis',
          category: 'validation'
        });
      }

      // Simulate code analysis (in real implementation, this would use actual analysis tools)
      const fileResults = await Promise.all(
        filesToAnalyze.map(async (file) => await analyzeFile(file))
      );

      // Calculate aggregate metrics
      const totalFiles = fileResults.length;
      const averageComplexity = fileResults.reduce((sum, f) => sum + f.complexity, 0) / totalFiles;
      const averageMaintainability = fileResults.reduce((sum, f) => sum + f.maintainability, 0) / totalFiles;
      const totalIssues = fileResults.reduce((sum, f) => sum + f.issues.length, 0);
      const criticalIssues = fileResults.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'critical').length, 0);
      const duplicationPercentage = fileResults.reduce((sum, f) => sum + f.duplication, 0) / totalFiles;

      // Calculate overall score and grade
      const overallScore = Math.max(0, Math.round(100 - (averageComplexity * 5) - (totalIssues * 2) - duplicationPercentage));
      const overallGrade = overallScore >= 90 ? 'A' : overallScore >= 80 ? 'B' : overallScore >= 70 ? 'C' : overallScore >= 60 ? 'D' : 'F';

      // Save analysis result
      const analysisResult = await context.db.run(
        `INSERT INTO code_analysis_results 
         (id, project_id, timestamp, files_analyzed, average_complexity, average_maintainability,
          total_issues, critical_issues, duplication_percentage, overall_score, overall_grade,
          options, recommendations, baseline_comparison, created_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          analysisId,
          projectId,
          now,
          totalFiles,
          averageComplexity,
          averageMaintainability,
          totalIssues,
          criticalIssues,
          duplicationPercentage,
          overallScore,
          overallGrade,
          JSON.stringify(input),
          JSON.stringify(generateRecommendations(fileResults)),
          JSON.stringify({}), // baseline comparison - would be populated if requested
          now
        ]
      );

      if (!analysisResult.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to save analysis result',
          details: { error: analysisResult.error },
          category: 'system'
        });
      }

      // Save file results and issues
      for (const fileResult of fileResults) {
        const fileResultId = `file-${randomUUID()}`;
        
        await context.db.run(
          `INSERT INTO code_analysis_file_results 
           (id, analysis_id, project_id, file_path, file_size, language, last_modified,
            cyclomatic_complexity, cognitive_complexity, halstead_difficulty, halstead_volume, halstead_effort,
            max_complexity, total_complexity, function_complexities,
            maintainability_index, maintainability_rating, line_count, comment_ratio, test_coverage,
            duplication_percentage, duplicate_blocks, duplicated_lines, total_lines,
            total_issues, high_issues, medium_issues, low_issues, code_smells, technical_debt,
            quality_score, quality_grade, created_at)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            fileResultId,
            analysisId,
            projectId,
            fileResult.path,
            fileResult.size,
            fileResult.language,
            fileResult.lastModified,
            fileResult.complexity,
            fileResult.complexity, // cognitive = cyclomatic for simplicity
            0, 0, 0, // halstead metrics
            fileResult.complexity,
            fileResult.complexity,
            JSON.stringify([]), // function complexities
            fileResult.maintainability,
            fileResult.maintainability >= 80 ? 'A' : fileResult.maintainability >= 60 ? 'B' : 'C',
            fileResult.lineCount,
            0, 0, // comment ratio, test coverage
            fileResult.duplication,
            JSON.stringify([]), // duplicate blocks
            0, fileResult.lineCount, // duplicated lines, total lines
            fileResult.issues.length,
            fileResult.issues.filter(i => i.severity === 'high').length,
            fileResult.issues.filter(i => i.severity === 'medium').length,
            fileResult.issues.filter(i => i.severity === 'low').length,
            0, 0, // code smells, technical debt
            overallScore,
            overallGrade,
            now
          ]
        );

        // Save issues
        for (const issue of fileResult.issues) {
          const issueId = `issue-${randomUUID()}`;
          
          await context.db.run(
            `INSERT INTO code_analysis_issues 
             (id, analysis_id, file_result_id, project_id, issue_type, severity, rule, message,
              file_path, line_number, column_number, end_line_number, end_column_number,
              is_fixable, category, suggestion, created_at)
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
            [
              issueId,
              analysisId,
              fileResultId,
              projectId,
              issue.type,
              issue.severity,
              issue.rule,
              issue.message,
              fileResult.path,
              issue.line,
              issue.column,
              issue.endLine || null,
              issue.endColumn || null,
              issue.fixable || false,
              issue.category,
              issue.suggestion || null,
              now
            ]
          );
        }
      }

      // Get baseline comparison if requested
      let baselineComparison = null;
      if (input.compareWithBaseline) {
        const baseline = await context.db.get(
          'SELECT * FROM code_metrics_baselines WHERE project_id = ? ORDER BY created_at DESC LIMIT 1',
          [projectId]
        );

        if (baseline.success && baseline.data) {
          const baselineHistory = await context.db.get(
            'SELECT * FROM code_metrics_history WHERE id = ?',
            [baseline.data.metrics_history_id]
          );

          if (baselineHistory.success && baselineHistory.data) {
            baselineComparison = {
              complexityChange: averageComplexity - baselineHistory.data.average_complexity,
              maintainabilityChange: averageMaintainability - baselineHistory.data.average_maintainability,
              issuesChange: totalIssues - baselineHistory.data.total_issues,
              duplicationChange: duplicationPercentage - baselineHistory.data.duplication_percentage
            };
          }
        }
      }

      return createSuccessResult({
        analysis: {
          id: analysisId,
          projectId,
          timestamp: new Date(now).toISOString(),
          filesAnalyzed: totalFiles,
          summary: {
            averageComplexity,
            averageMaintainability,
            totalIssues,
            criticalIssues,
            duplicationPercentage,
            overallScore,
            overallGrade
          }
        },
        fileResults: fileResults.slice(0, 10), // Return first 10 files for brevity
        baselineComparison,
        recommendations: generateRecommendations(fileResults),
        message: overallScore >= 80 
          ? `✅ Code quality is good (${overallScore}/100)`
          : `⚠️ Code quality needs improvement (${overallScore}/100)`,
        insights: [
          `Analyzed ${totalFiles} files`,
          `Average complexity: ${averageComplexity.toFixed(1)}`,
          `Total issues found: ${totalIssues}`,
          criticalIssues > 0 ? `⚠️ ${criticalIssues} critical issues found` : 'No critical issues'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Code analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Perform AI-powered code review with detailed findings
 */
const reviewCodeTool = createTool<ReviewCodeInput, any>({
  name: 'review_code',
  description: 'AI-powered code review with detailed findings and improvement suggestions',
  category: 'code-analysis',
  inputSchema: {
    type: 'object',
    properties: {
      file: {
        type: 'string',
        description: 'File to review'
      },
      compareWith: {
        type: 'string',
        description: 'Compare with another file (e.g., previous version)'
      },
      includeHistory: {
        type: 'boolean',
        description: 'Save review to history',
        default: false
      },
      focusAreas: {
        type: 'array',
        items: {
          type: 'string',
          enum: ['security', 'performance', 'maintainability', 'style', 'testing']
        },
        description: 'Specific areas to focus on'
      }
    },
    required: ['file'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ReviewCodeInput, context: RequestContext) {
    try {
      const projectId = context.projectId || 'default';
      const reviewId = `review-${randomUUID()}`;
      const now = Date.now();

      // Check if file exists
      try {
        await fs.access(input.file);
      } catch {
        return createErrorResult({
          code: 'VALIDATION_ERROR',
          message: `File not found: ${input.file}`,
          category: 'validation'
        });
      }

      // Analyze the file
      const fileAnalysis = await analyzeFile(input.file);
      
      // Generate findings
      const findings = fileAnalysis.issues.map((issue, index) => ({
        id: `finding-${index}`,
        type: issue.type === 'error' ? 'bug' : issue.type === 'warning' ? 'improvement' : 'style',
        severity: issue.severity,
        title: issue.rule,
        description: issue.message,
        line: issue.line,
        column: issue.column,
        suggestedFix: issue.suggestion
      }));

      // Generate suggestions
      const suggestions = generateCodeSuggestions(fileAnalysis, input.focusAreas);

      // Calculate review score
      const reviewScore = Math.max(0, Math.round(100 - (fileAnalysis.complexity * 5) - (findings.length * 3)));

      // Save review
      const reviewResult = await context.db.run(
        `INSERT INTO code_reviews 
         (id, project_id, file_path, file_hash, file_name, timestamp, overall_score, 
          summary, approved, comparison_data, created_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          reviewId,
          projectId,
          input.file,
          null, // file hash - would be calculated in real implementation
          path.basename(input.file),
          now,
          reviewScore,
          generateReviewSummary(findings, suggestions),
          false, // not approved by default
          JSON.stringify({}), // comparison data
          now
        ]
      );

      if (!reviewResult.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to save review',
          details: { error: reviewResult.error },
          category: 'system'
        });
      }

      // Save findings
      for (const finding of findings) {
        await context.db.run(
          `INSERT INTO code_review_findings 
           (id, review_id, project_id, finding_type, severity, title, description,
            file_path, line_number, column_number, end_line_number, end_column_number,
            suggested_fix, created_at)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            randomUUID(),
            reviewId,
            projectId,
            finding.type,
            finding.severity,
            finding.title,
            finding.description,
            input.file,
            finding.line,
            finding.column,
            null, null, // end line/column
            finding.suggestedFix,
            now
          ]
        );
      }

      // Save suggestions
      for (const suggestion of suggestions) {
        await context.db.run(
          `INSERT INTO code_review_suggestions 
           (id, review_id, project_id, title, description, priority, suggestion_type,
            file_path, line_number, column_number, example, created_at)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            randomUUID(),
            reviewId,
            projectId,
            suggestion.title,
            suggestion.description,
            suggestion.priority,
            suggestion.type,
            input.file,
            suggestion.line || null,
            suggestion.column || null,
            suggestion.example || null,
            now
          ]
        );
      }

      return createSuccessResult({
        review: {
          id: reviewId,
          file: input.file,
          score: reviewScore,
          timestamp: new Date(now).toISOString(),
          summary: generateReviewSummary(findings, suggestions)
        },
        findings: findings.slice(0, 10), // Show first 10 findings
        suggestions: suggestions.slice(0, 5), // Show first 5 suggestions
        message: reviewScore >= 80 
          ? `✅ Code review passed (${reviewScore}/100)`
          : `⚠️ Code review needs attention (${reviewScore}/100)`,
        insights: [
          `Found ${findings.length} issues`,
          `Generated ${suggestions.length} improvement suggestions`,
          `File complexity: ${fileAnalysis.complexity.toFixed(1)}`,
          `Maintainability: ${fileAnalysis.maintainability.toFixed(1)}`
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Code review failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Track code quality metrics over time
 */
const trackCodeMetricsTool = createTool<TrackCodeMetricsInput, any>({
  name: 'track_code_metrics',
  description: 'Track code quality metrics over time with trend analysis',
  category: 'code-analysis',
  inputSchema: {
    type: 'object',
    properties: {
      projectId: {
        type: 'string',
        description: 'Project identifier (defaults to directory name)'
      },
      branch: {
        type: 'string',
        description: 'Git branch name'
      },
      commit: {
        type: 'string',
        description: 'Git commit hash'
      },
      tags: {
        type: 'array',
        items: { type: 'string' },
        description: 'Tags for this metrics snapshot (e.g., "release", "baseline")'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: TrackCodeMetricsInput, context: RequestContext) {
    try {
      const projectId = input.projectId || context.projectId || 'default';
      const historyId = `history-${randomUUID()}`;
      const now = Date.now();

      // Analyze entire project
      const projectFiles = await findCodeFiles('.', [
        'node_modules/**',
        'dist/**',
        'build/**',
        '.git/**',
        '*.test.*',
        '*.spec.*'
      ]);

      const fileAnalyses = await Promise.all(
        projectFiles.map(async (file) => await analyzeFile(file))
      );

      // Calculate project metrics
      const totalFiles = fileAnalyses.length;
      const averageComplexity = fileAnalyses.reduce((sum, f) => sum + f.complexity, 0) / totalFiles;
      const maxComplexity = Math.max(...fileAnalyses.map(f => f.complexity));
      const totalComplexity = fileAnalyses.reduce((sum, f) => sum + f.complexity, 0);
      const averageMaintainability = fileAnalyses.reduce((sum, f) => sum + f.maintainability, 0) / totalFiles;
      const minMaintainability = Math.min(...fileAnalyses.map(f => f.maintainability));
      const duplicationPercentage = fileAnalyses.reduce((sum, f) => sum + f.duplication, 0) / totalFiles;
      
      const totalIssues = fileAnalyses.reduce((sum, f) => sum + f.issues.length, 0);
      const highIssues = fileAnalyses.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'high').length, 0);
      const mediumIssues = fileAnalyses.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'medium').length, 0);
      const lowIssues = fileAnalyses.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'low').length, 0);

      const qualityScore = Math.max(0, Math.round(100 - (averageComplexity * 5) - (totalIssues * 2) - duplicationPercentage));
      const qualityGrade = qualityScore >= 90 ? 'A' : qualityScore >= 80 ? 'B' : qualityScore >= 70 ? 'C' : qualityScore >= 60 ? 'D' : 'F';

      // Save metrics history
      const historyResult = await context.db.run(
        `INSERT INTO code_metrics_history 
         (id, project_id, timestamp, branch, commit_hash, tags,
          average_complexity, max_complexity, total_complexity,
          average_maintainability, min_maintainability, duplication_percentage,
          total_issues, high_issues, medium_issues, low_issues,
          quality_score, quality_grade, raw_metrics, summary_data, created_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          historyId,
          projectId,
          now,
          input.branch || null,
          input.commit || null,
          JSON.stringify(input.tags || []),
          averageComplexity,
          maxComplexity,
          totalComplexity,
          averageMaintainability,
          minMaintainability,
          duplicationPercentage,
          totalIssues,
          highIssues,
          mediumIssues,
          lowIssues,
          qualityScore,
          qualityGrade,
          JSON.stringify({ fileAnalyses }),
          JSON.stringify({
            filesAnalyzed: totalFiles,
            timestamp: now
          }),
          now
        ]
      );

      if (!historyResult.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to save metrics history',
          details: { error: historyResult.error },
          category: 'system'
        });
      }

      // Update baseline if tagged as baseline
      if (input.tags && input.tags.includes('baseline')) {
        // Delete existing baseline
        await context.db.run(
          'DELETE FROM code_metrics_baselines WHERE project_id = ?',
          [projectId]
        );

        // Create new baseline
        await context.db.run(
          `INSERT INTO code_metrics_baselines 
           (id, project_id, metrics_history_id, name, commit_hash, created_at)
           VALUES (?, ?, ?, ?, ?, ?)`,
          [
            `baseline-${randomUUID()}`,
            projectId,
            historyId,
            'baseline',
            input.commit || null,
            now
          ]
        );
      }

      // Calculate trends
      const trends = await calculateTrends(context, projectId);

      return createSuccessResult({
        metrics: {
          id: historyId,
          projectId,
          timestamp: new Date(now).toISOString(),
          branch: input.branch,
          commit: input.commit,
          tags: input.tags || [],
          summary: {
            filesAnalyzed: totalFiles,
            averageComplexity,
            maxComplexity,
            averageMaintainability,
            duplicationPercentage,
            totalIssues,
            highIssues,
            qualityScore,
            qualityGrade
          }
        },
        trends,
        message: `📊 Metrics tracked for ${totalFiles} files`,
        insights: [
          `Quality score: ${qualityScore}/100 (${qualityGrade})`,
          `Average complexity: ${averageComplexity.toFixed(1)}`,
          `Total issues: ${totalIssues} (${highIssues} high priority)`,
          trends.length > 0 ? `Trends available for ${trends.length} metrics` : 'No trend data yet'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Metrics tracking failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Get analysis history
 */
const getAnalysisHistoryTool = createTool<GetAnalysisHistoryInput, any>({
  name: 'get_analysis_history',
  description: 'Get code analysis history with optional baseline comparison',
  category: 'code-analysis',
  inputSchema: {
    type: 'object',
    properties: {
      limit: {
        type: 'number',
        description: 'Maximum number of results to return',
        default: 20
      },
      includeBaseline: {
        type: 'boolean',
        description: 'Include baseline comparison data',
        default: false
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: GetAnalysisHistoryInput, context: RequestContext) {
    try {
      const projectId = context.projectId || 'default';
      const limit = input.limit || 20;

      const results = await context.db.all(
        `SELECT * FROM code_analysis_results 
         WHERE project_id = ? 
         ORDER BY timestamp DESC 
         LIMIT ?`,
        [projectId, limit]
      );

      if (!results.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to fetch analysis history',
          details: { error: results.error },
          category: 'system'
        });
      }

      const formattedResults = results.data.map((r: any) => ({
        id: r.id,
        timestamp: new Date(r.timestamp).toISOString(),
        filesAnalyzed: r.files_analyzed,
        averageComplexity: r.average_complexity,
        averageMaintainability: r.average_maintainability,
        totalIssues: r.total_issues,
        criticalIssues: r.critical_issues,
        duplicationPercentage: r.duplication_percentage,
        overallScore: r.overall_score,
        overallGrade: r.overall_grade,
        recommendations: JSON.parse(r.recommendations || '[]')
      }));

      return createSuccessResult({
        history: formattedResults,
        totalCount: formattedResults.length,
        message: `Found ${formattedResults.length} analysis result(s)`,
        insights: formattedResults.length > 0 ? [
          `Latest score: ${formattedResults[0].overallScore}/100 (${formattedResults[0].overallGrade})`,
          `Average complexity: ${formattedResults[0].averageComplexity.toFixed(1)}`,
          `Total issues: ${formattedResults[0].totalIssues}`
        ] : ['No analysis history available']
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to get analysis history: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Get code reviews
 */
const getCodeReviewsTool = createTool<GetCodeReviewsInput, any>({
  name: 'get_code_reviews',
  description: 'Get code review history with optional file filtering',
  category: 'code-analysis',
  inputSchema: {
    type: 'object',
    properties: {
      fileFilter: {
        type: 'string',
        description: 'Filter reviews by file path pattern'
      },
      limit: {
        type: 'number',
        description: 'Maximum number of results to return',
        default: 20
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: GetCodeReviewsInput, context: RequestContext) {
    try {
      const projectId = context.projectId || 'default';
      const limit = input.limit || 20;

      let query = `
        SELECT r.*, 
        (SELECT COUNT(*) FROM code_review_findings WHERE review_id = r.id) as findings_count,
        (SELECT COUNT(*) FROM code_review_suggestions WHERE review_id = r.id) as suggestions_count
        FROM code_reviews r
        WHERE r.project_id = ?
      `;
      const params: any[] = [projectId];

      if (input.fileFilter) {
        query += ' AND r.file_path LIKE ?';
        params.push(`%${input.fileFilter}%`);
      }

      query += ' ORDER BY r.timestamp DESC LIMIT ?';
      params.push(limit);

      const results = await context.db.all(query, params);

      if (!results.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to fetch code reviews',
          details: { error: results.error },
          category: 'system'
        });
      }

      const formattedResults = results.data.map((r: any) => ({
        id: r.id,
        filePath: r.file_path,
        fileName: r.file_name,
        timestamp: new Date(r.timestamp).toISOString(),
        overallScore: r.overall_score,
        summary: r.summary,
        approved: r.approved,
        findingsCount: r.findings_count,
        suggestionsCount: r.suggestions_count
      }));

      return createSuccessResult({
        reviews: formattedResults,
        totalCount: formattedResults.length,
        message: `Found ${formattedResults.length} code review(s)`,
        insights: formattedResults.length > 0 ? [
          `Latest review score: ${formattedResults[0].overallScore}/100`,
          `Total findings: ${formattedResults.reduce((sum: number, r: any) => sum + r.findingsCount, 0)}`,
          `Total suggestions: ${formattedResults.reduce((sum: number, r: any) => sum + r.suggestionsCount, 0)}`
        ] : ['No code reviews available']
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to get code reviews: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Set metrics baseline
 */
const setMetricsBaselineTool = createTool<SetMetricsBaselineInput, any>({
  name: 'set_metrics_baseline',
  description: 'Set a metrics history entry as the baseline for comparisons',
  category: 'code-analysis',
  inputSchema: {
    type: 'object',
    properties: {
      historyId: {
        type: 'string',
        description: 'Metrics history ID to set as baseline (defaults to latest)'
      },
      tags: {
        type: 'array',
        items: { type: 'string' },
        description: 'Additional tags for the baseline'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: SetMetricsBaselineInput, context: RequestContext) {
    try {
      const projectId = context.projectId || 'default';
      let targetId = input.historyId;

      // Use latest history if no ID specified
      if (!targetId) {
        const latest = await context.db.get(
          'SELECT id FROM code_metrics_history WHERE project_id = ? ORDER BY timestamp DESC LIMIT 1',
          [projectId]
        );

        if (!latest.success || !latest.data) {
          return createErrorResult({
            code: 'RESOURCE_NOT_FOUND',
            message: 'No metrics history available to set as baseline',
            category: 'validation'
          });
        }

        targetId = latest.data.id;
      }

      // Verify history exists
      const historyEntry = await context.db.get(
        'SELECT * FROM code_metrics_history WHERE id = ? AND project_id = ?',
        [targetId, projectId]
      );

      if (!historyEntry.success || !historyEntry.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: `Metrics history ${targetId} not found`,
          category: 'validation'
        });
      }

      // Delete existing baseline
      await context.db.run(
        'DELETE FROM code_metrics_baselines WHERE project_id = ?',
        [projectId]
      );

      // Create new baseline
      const baselineId = `baseline-${randomUUID()}`;
      const result = await context.db.run(
        `INSERT INTO code_metrics_baselines 
         (id, project_id, metrics_history_id, name, commit_hash, created_at)
         VALUES (?, ?, ?, ?, ?, ?)`,
        [
          baselineId,
          projectId,
          targetId,
          'baseline',
          historyEntry.data.commit_hash,
          Date.now()
        ]
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to set baseline',
          details: { error: result.error },
          category: 'system'
        });
      }

      return createSuccessResult({
        baseline: {
          id: baselineId,
          historyId: targetId,
          timestamp: new Date(historyEntry.data.timestamp).toISOString(),
          qualityScore: historyEntry.data.quality_score,
          averageComplexity: historyEntry.data.average_complexity,
          totalIssues: historyEntry.data.total_issues
        },
        message: '✅ Metrics baseline set',
        details: [
          `Quality Score: ${historyEntry.data.quality_score}/100`,
          `Average Complexity: ${historyEntry.data.average_complexity.toFixed(1)}`,
          `Total Issues: ${historyEntry.data.total_issues}`,
          'Future metrics will be compared against this baseline'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to set baseline: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Setup all code analysis tools
 */
export async function setupCodeAnalysisTools(): Promise<ToolRegistration> {
  return {
    module: 'code-analysis',
    tools: [
      analyzeCodeQualityTool,
      reviewCodeTool,
      trackCodeMetricsTool,
      getAnalysisHistoryTool,
      getCodeReviewsTool,
      setMetricsBaselineTool
    ]
  };
}

// Helper functions

async function findCodeFiles(dir: string, excludePatterns: string[]): Promise<string[]> {
  const files: string[] = [];
  const codeExtensions = ['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.cpp', '.c', '.cs', '.php', '.rb', '.go'];
  
  try {
    const entries = await fs.readdir(dir, { withFileTypes: true });
    
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      
      // Skip if matches exclude patterns
      if (excludePatterns.some(pattern => fullPath.includes(pattern.replace('**', '')))) {
        continue;
      }
      
      if (entry.isDirectory()) {
        const subFiles = await findCodeFiles(fullPath, excludePatterns);
        files.push(...subFiles);
      } else if (entry.isFile() && codeExtensions.some(ext => entry.name.endsWith(ext))) {
        files.push(fullPath);
      }
    }
  } catch (error) {
    // Directory doesn't exist or can't be read
  }
  
  return files;
}

async function analyzeFile(filePath: string): Promise<any> {
  try {
    const stats = await fs.stat(filePath);
    const content = await fs.readFile(filePath, 'utf-8');
    const lines = content.split('\n');
    
    // Simulate analysis (in real implementation, use actual analysis tools)
    const complexity = Math.random() * 20 + 1; // 1-21
    const maintainability = Math.random() * 40 + 60; // 60-100
    const duplication = Math.random() * 15; // 0-15%
    
    // Generate some mock issues
    const issues = [];
    const numIssues = Math.floor(Math.random() * 5);
    
    for (let i = 0; i < numIssues; i++) {
      issues.push({
        type: ['error', 'warning', 'info'][Math.floor(Math.random() * 3)],
        severity: ['critical', 'high', 'medium', 'low'][Math.floor(Math.random() * 4)],
        rule: `rule-${i + 1}`,
        message: `Mock issue ${i + 1} in ${path.basename(filePath)}`,
        line: Math.floor(Math.random() * lines.length) + 1,
        column: Math.floor(Math.random() * 80) + 1,
        category: ['security', 'performance', 'maintainability', 'style'][Math.floor(Math.random() * 4)],
        fixable: Math.random() > 0.5
      });
    }
    
    return {
      path: filePath,
      size: stats.size,
      language: getLanguageFromExtension(filePath),
      lastModified: stats.mtime.getTime(),
      lineCount: lines.length,
      complexity,
      maintainability,
      duplication,
      issues
    };
  } catch (error) {
    throw new Error(`Failed to analyze file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

function getLanguageFromExtension(filePath: string): string {
  const ext = path.extname(filePath);
  const languageMap: Record<string, string> = {
    '.js': 'javascript',
    '.jsx': 'javascript',
    '.ts': 'typescript',
    '.tsx': 'typescript',
    '.py': 'python',
    '.java': 'java',
    '.cpp': 'cpp',
    '.c': 'c',
    '.cs': 'csharp',
    '.php': 'php',
    '.rb': 'ruby',
    '.go': 'go'
  };
  
  return languageMap[ext] || 'unknown';
}

function generateRecommendations(fileResults: any[]): string[] {
  const recommendations = [];
  
  const avgComplexity = fileResults.reduce((sum, f) => sum + f.complexity, 0) / fileResults.length;
  if (avgComplexity > 10) {
    recommendations.push('Consider refactoring complex functions to improve maintainability');
  }
  
  const totalIssues = fileResults.reduce((sum, f) => sum + f.issues.length, 0);
  if (totalIssues > 50) {
    recommendations.push('Address code quality issues to improve overall health');
  }
  
  const avgDuplication = fileResults.reduce((sum, f) => sum + f.duplication, 0) / fileResults.length;
  if (avgDuplication > 10) {
    recommendations.push('Reduce code duplication by extracting common functionality');
  }
  
  return recommendations;
}

function generateCodeSuggestions(fileAnalysis: any, focusAreas?: string[]): any[] {
  const suggestions = [];
  
  if (!focusAreas || focusAreas.includes('performance')) {
    if (fileAnalysis.complexity > 15) {
      suggestions.push({
        title: 'Optimize Complex Functions',
        description: 'Consider breaking down complex functions into smaller, more manageable pieces',
        priority: 'high',
        type: 'refactoring',
        line: Math.floor(Math.random() * fileAnalysis.lineCount) + 1,
        column: 1
      });
    }
  }
  
  if (!focusAreas || focusAreas.includes('maintainability')) {
    if (fileAnalysis.maintainability < 70) {
      suggestions.push({
        title: 'Improve Code Documentation',
        description: 'Add comments and documentation to improve code maintainability',
        priority: 'medium',
        type: 'documentation'
      });
    }
  }
  
  return suggestions;
}

function generateReviewSummary(findings: any[], suggestions: any[]): string {
  const highPriorityFindings = findings.filter(f => f.severity === 'high').length;
  const mediumPriorityFindings = findings.filter(f => f.severity === 'medium').length;
  
  let summary = '';
  
  if (highPriorityFindings > 0) {
    summary += `Found ${highPriorityFindings} high-priority issues that should be addressed immediately. `;
  }
  
  if (mediumPriorityFindings > 0) {
    summary += `Found ${mediumPriorityFindings} medium-priority issues that should be addressed soon. `;
  }
  
  if (suggestions.length > 0) {
    summary += `Generated ${suggestions.length} improvement suggestions. `;
  }
  
  if (findings.length === 0 && suggestions.length === 0) {
    summary = 'Code looks good! No significant issues found.';
  }
  
  return summary;
}

async function calculateTrends(context: RequestContext, projectId: string): Promise<any[]> {
  const trends = [];
  
  // Get recent history entries
  const recent = await context.db.all(
    'SELECT * FROM code_metrics_history WHERE project_id = ? ORDER BY timestamp DESC LIMIT 10',
    [projectId]
  );
  
  if (recent.success && recent.data.length >= 2) {
    const latestEntry = recent.data[0];
    const previousEntry = recent.data[1];
    
    const complexityChange = latestEntry.average_complexity - previousEntry.average_complexity;
    const maintainabilityChange = latestEntry.average_maintainability - previousEntry.average_maintainability;
    const issuesChange = latestEntry.total_issues - previousEntry.total_issues;
    
    trends.push({
      metric: 'complexity',
      direction: complexityChange > 0.1 ? 'increasing' : complexityChange < -0.1 ? 'decreasing' : 'stable',
      change: complexityChange,
      percentage: (complexityChange / previousEntry.average_complexity) * 100
    });
    
    trends.push({
      metric: 'maintainability',
      direction: maintainabilityChange > 1 ? 'improving' : maintainabilityChange < -1 ? 'degrading' : 'stable',
      change: maintainabilityChange,
      percentage: (maintainabilityChange / previousEntry.average_maintainability) * 100
    });
    
    trends.push({
      metric: 'issues',
      direction: issuesChange > 0 ? 'increasing' : issuesChange < 0 ? 'decreasing' : 'stable',
      change: issuesChange,
      percentage: previousEntry.total_issues > 0 ? (issuesChange / previousEntry.total_issues) * 100 : 0
    });
  }
  
  return trends;
}