import { writeFileSync } from 'fs';
import { join } from 'path';
import type { CoverageReport, PackageCoverage, CoverageMetric } from '../types';

export class MarkdownReporter {
  report(coverage: CoverageReport, outputDir: string): void {
    const outputPath = join(outputDir, 'coverage.md');
    const content = this.generateMarkdown(coverage);
    
    writeFileSync(outputPath, content);
    console.log(`Markdown coverage report written to: ${outputPath}`);
  }

  private generateMarkdown(coverage: CoverageReport): string {
    const lines: string[] = [];
    
    // Header
    lines.push('# Coverage Report');
    lines.push('');
    lines.push(`Generated: ${new Date(coverage.timestamp).toLocaleString()}`);
    lines.push('');
    
    // Overall Summary
    lines.push('## Overall Coverage');
    lines.push('');
    lines.push(this.generateSummaryTable(coverage.overall, coverage.config.thresholds));
    lines.push('');
    
    // Package Details
    if (coverage.packages.length > 0) {
      lines.push('## Package Coverage');
      lines.push('');
      lines.push(this.generatePackageTable(coverage));
      lines.push('');
      
      // Detailed package breakdowns
      lines.push('## Package Details');
      lines.push('');
      
      for (const pkg of coverage.packages) {
        lines.push(`### ${pkg.name}`);
        lines.push('');
        lines.push(this.generatePackageDetails(pkg));
        lines.push('');
      }
    }
    
    // Thresholds
    lines.push('## Coverage Thresholds');
    lines.push('');
    lines.push('| Metric | Threshold | Actual | Status |');
    lines.push('|--------|-----------|---------|---------|');
    
    const metrics = ['lines', 'functions', 'branches', 'statements'] as const;
    for (const metric of metrics) {
      const threshold = coverage.config.thresholds[metric];
      const actual = coverage.overall[metric].percentage;
      const status = this.getStatus(actual, threshold);
      
      lines.push(`| ${this.capitalize(metric)} | ${threshold || 'N/A'}% | ${actual.toFixed(1)}% | ${status} |`);
    }
    
    return lines.join('\n');
  }

  private generateSummaryTable(overall: CoverageReport['overall'], thresholds: any): string {
    const lines: string[] = [];
    
    lines.push('| Metric | Coverage | Total | Covered |');
    lines.push('|--------|----------|--------|----------|');
    
    const metrics = ['lines', 'functions', 'branches', 'statements'] as const;
    for (const metric of metrics) {
      const data = overall[metric];
      const icon = this.getIcon(data.percentage, thresholds[metric]);
      
      lines.push(
        `| ${this.capitalize(metric)} | ${data.percentage.toFixed(1)}% ${icon} | ${data.total} | ${data.covered} |`
      );
    }
    
    return lines.join('\n');
  }

  private generatePackageTable(coverage: CoverageReport): string {
    const lines: string[] = [];
    
    lines.push('| Package | Lines | Functions | Branches | Statements |');
    lines.push('|---------|--------|-----------|----------|------------|');
    
    for (const pkg of coverage.packages) {
      lines.push(
        `| ${pkg.name} | ${this.formatMetric(pkg.lines)} | ${this.formatMetric(pkg.functions)} | ${this.formatMetric(pkg.branches)} | ${this.formatMetric(pkg.statements)} |`
      );
    }
    
    lines.push(`| **Overall** | **${this.formatMetric(coverage.overall.lines)}** | **${this.formatMetric(coverage.overall.functions)}** | **${this.formatMetric(coverage.overall.branches)}** | **${this.formatMetric(coverage.overall.statements)}** |`);
    
    return lines.join('\n');
  }

  private generatePackageDetails(pkg: PackageCoverage): string {
    const lines: string[] = [];
    
    // Summary
    lines.push(`**Coverage Summary:**`);
    lines.push(`- Lines: ${pkg.lines.percentage.toFixed(1)}% (${pkg.lines.covered}/${pkg.lines.total})`);
    lines.push(`- Functions: ${pkg.functions.percentage.toFixed(1)}% (${pkg.functions.covered}/${pkg.functions.total})`);
    lines.push(`- Branches: ${pkg.branches.percentage.toFixed(1)}% (${pkg.branches.covered}/${pkg.branches.total})`);
    lines.push(`- Statements: ${pkg.statements.percentage.toFixed(1)}% (${pkg.statements.covered}/${pkg.statements.total})`);
    lines.push('');
    
    // File breakdown (top 10 least covered)
    const sortedFiles = [...pkg.files]
      .sort((a, b) => a.lines.percentage - b.lines.percentage)
      .slice(0, 10);
    
    if (sortedFiles.length > 0) {
      lines.push('**Least Covered Files:**');
      lines.push('');
      lines.push('| File | Lines | Functions | Branches |');
      lines.push('|------|--------|-----------|----------|');
      
      for (const file of sortedFiles) {
        const shortPath = this.shortenPath(file.path);
        lines.push(
          `| ${shortPath} | ${file.lines.percentage.toFixed(1)}% | ${file.functions.percentage.toFixed(1)}% | ${file.branches.percentage.toFixed(1)}% |`
        );
      }
    }
    
    return lines.join('\n');
  }

  private formatMetric(metric: CoverageMetric): string {
    return `${metric.percentage.toFixed(1)}%`;
  }

  private getIcon(percentage: number, threshold?: number): string {
    if (!threshold) return '';
    
    if (percentage >= threshold) return '✅';
    if (percentage >= threshold * 0.9) return '⚠️';
    return '❌';
  }

  private getStatus(percentage: number, threshold?: number): string {
    if (!threshold) return '➖';
    
    if (percentage >= threshold) return '✅ Pass';
    return '❌ Fail';
  }

  private capitalize(str: string): string {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  private shortenPath(path: string): string {
    const parts = path.split('/');
    if (parts.length > 4) {
      return '.../' + parts.slice(-3).join('/');
    }
    return path;
  }
}