import chalk from 'chalk';
import { table } from 'table';
import type { CoverageReport, PackageCoverage, CoverageMetric } from '../types';

export class TerminalReporter {
  report(coverage: CoverageReport): void {
    console.log('\n' + chalk.bold.cyan('═'.repeat(60)));
    console.log(chalk.bold.cyan('          Stock Bot Coverage Report'));
    console.log(chalk.bold.cyan('═'.repeat(60)) + '\n');

    // Package-level coverage
    if (coverage.packages.length > 0) {
      this.printPackageTable(coverage);
    }

    // Overall summary
    this.printOverallSummary(coverage);

    // Threshold warnings
    this.printThresholdWarnings(coverage);
  }

  private printPackageTable(coverage: CoverageReport): void {
    const data: any[][] = [
      [
        chalk.bold('Package'),
        chalk.bold('Lines'),
        chalk.bold('Functions'),
        chalk.bold('Branches'),
        chalk.bold('Statements'),
      ],
    ];

    for (const pkg of coverage.packages) {
      data.push([
        chalk.cyan(pkg.name),
        this.formatMetric(pkg.lines, coverage.config.thresholds.lines),
        this.formatMetric(pkg.functions, coverage.config.thresholds.functions),
        this.formatMetric(pkg.branches, coverage.config.thresholds.branches),
        this.formatMetric(pkg.statements, coverage.config.thresholds.statements),
      ]);
    }

    // Add separator
    data.push([
      chalk.gray('─'.repeat(20)),
      chalk.gray('─'.repeat(10)),
      chalk.gray('─'.repeat(10)),
      chalk.gray('─'.repeat(10)),
      chalk.gray('─'.repeat(10)),
    ]);

    // Add overall
    data.push([
      chalk.bold('Overall'),
      this.formatMetric(coverage.overall.lines, coverage.config.thresholds.lines),
      this.formatMetric(coverage.overall.functions, coverage.config.thresholds.functions),
      this.formatMetric(coverage.overall.branches, coverage.config.thresholds.branches),
      this.formatMetric(coverage.overall.statements, coverage.config.thresholds.statements),
    ]);

    const config = {
      border: {
        topBody: '─',
        topJoin: '┬',
        topLeft: '┌',
        topRight: '┐',
        bottomBody: '─',
        bottomJoin: '┴',
        bottomLeft: '└',
        bottomRight: '┘',
        bodyLeft: '│',
        bodyRight: '│',
        bodyJoin: '│',
        joinBody: '─',
        joinLeft: '├',
        joinRight: '┤',
        joinJoin: '┼',
      },
    };

    console.log(table(data, config));
  }

  private formatMetric(metric: CoverageMetric, threshold?: number): string {
    const percentage = metric.percentage.toFixed(1);
    const icon = this.getIcon(metric.percentage, threshold);
    const color = this.getColor(metric.percentage, threshold);
    
    return color(`${percentage}% ${icon}`);
  }

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

  private getColor(percentage: number, threshold?: number): (text: string) => string {
    if (!threshold) return chalk.white;
    
    if (percentage >= threshold) return chalk.green;
    if (percentage >= threshold * 0.9) return chalk.yellow;
    return chalk.red;
  }

  private printOverallSummary(coverage: CoverageReport): void {
    const { packages, config } = coverage;
    const passingPackages = packages.filter(pkg => 
      this.packageMeetsThresholds(pkg, config.thresholds)
    ).length;
    
    const warningPackages = packages.filter(pkg => {
      const meetsThresholds = this.packageMeetsThresholds(pkg, config.thresholds);
      const almostMeets = this.packageAlmostMeetsThresholds(pkg, config.thresholds);
      return !meetsThresholds && almostMeets;
    }).length;
    
    const failingPackages = packages.length - passingPackages - warningPackages;

    console.log(chalk.green(`✓ ${passingPackages} packages meet coverage thresholds`));
    
    if (warningPackages > 0) {
      console.log(chalk.yellow(`⚠ ${warningPackages} packages below threshold`));
    }
    
    if (failingPackages > 0) {
      console.log(chalk.red(`✗ ${failingPackages} packages critically low`));
    }
  }

  private packageMeetsThresholds(pkg: PackageCoverage, thresholds: any): boolean {
    return (
      (!thresholds.lines || pkg.lines.percentage >= thresholds.lines) &&
      (!thresholds.functions || pkg.functions.percentage >= thresholds.functions) &&
      (!thresholds.branches || pkg.branches.percentage >= thresholds.branches) &&
      (!thresholds.statements || pkg.statements.percentage >= thresholds.statements)
    );
  }

  private packageAlmostMeetsThresholds(pkg: PackageCoverage, thresholds: any): boolean {
    return (
      (!thresholds.lines || pkg.lines.percentage >= thresholds.lines * 0.9) &&
      (!thresholds.functions || pkg.functions.percentage >= thresholds.functions * 0.9) &&
      (!thresholds.branches || pkg.branches.percentage >= thresholds.branches * 0.9) &&
      (!thresholds.statements || pkg.statements.percentage >= thresholds.statements * 0.9)
    );
  }

  private printThresholdWarnings(coverage: CoverageReport): void {
    const { overall, config } = coverage;
    const failures: string[] = [];

    if (config.thresholds.lines && overall.lines.percentage < config.thresholds.lines) {
      failures.push(`Lines: ${overall.lines.percentage.toFixed(1)}% < ${config.thresholds.lines}%`);
    }
    if (config.thresholds.functions && overall.functions.percentage < config.thresholds.functions) {
      failures.push(`Functions: ${overall.functions.percentage.toFixed(1)}% < ${config.thresholds.functions}%`);
    }
    if (config.thresholds.branches && overall.branches.percentage < config.thresholds.branches) {
      failures.push(`Branches: ${overall.branches.percentage.toFixed(1)}% < ${config.thresholds.branches}%`);
    }
    if (config.thresholds.statements && overall.statements.percentage < config.thresholds.statements) {
      failures.push(`Statements: ${overall.statements.percentage.toFixed(1)}% < ${config.thresholds.statements}%`);
    }

    if (failures.length > 0) {
      console.log('\n' + chalk.red.bold('Coverage thresholds not met:'));
      failures.forEach(failure => console.log(chalk.red(`  • ${failure}`)));
    }

    console.log('\n' + chalk.gray(`Run 'stock-bot-coverage --reporter html' for detailed report`));
  }
}