/**
 * Report Comparison Tool
 * Compare metrics across multiple time periods or reports side-by-side
 */

export interface ComparisonMetric {
  name: string;
  value: number;
  unit: string;
  format: 'number' | 'currency' | 'percentage' | 'time';
}

export interface ComparisonReport {
  id: string;
  name: string;
  period: string;
  metrics: Record<string, ComparisonMetric>;
  timestamp: Date;
}

export interface ComparisonResult {
  id: string;
  reports: ComparisonReport[];
  metrics: string[];
  comparison: Record<string, ComparisonMetricComparison>;
  trends: Record<string, TrendAnalysis>;
  insights: ComparisonInsight[];
  summary: ComparisonSummary;
}

export interface ComparisonMetricComparison {
  name: string;
  values: Array<{ report: string; value: number; formatted: string }>;
  change: number;
  changePercent: number;
  trend: 'up' | 'down' | 'flat';
  bestPerformer: string;
  worstPerformer: string;
}

export interface TrendAnalysis {
  metric: string;
  direction: 'increasing' | 'decreasing' | 'stable';
  velocity: number;
  acceleration: number;
  forecast: number;
  confidence: number;
}

export interface ComparisonInsight {
  type: 'anomaly' | 'trend' | 'correlation' | 'opportunity' | 'risk';
  severity: 'critical' | 'high' | 'medium' | 'low';
  title: string;
  description: string;
  metrics: string[];
  recommendation?: string;
}

export interface ComparisonSummary {
  totalMetrics: number;
  improvingMetrics: number;
  decliningMetrics: number;
  stableMetrics: number;
  overallTrend: 'positive' | 'negative' | 'mixed';
  performanceScore: number;
}

/**
 * Create comparison result
 */
export function createComparisonResult(
  reports: ComparisonReport[],
  metrics: string[]
): ComparisonResult {
  const comparison: Record<string, ComparisonMetricComparison> = {};
  const trends: Record<string, TrendAnalysis> = {};

  for (const metric of metrics) {
    const values = reports
      .map(report => ({
        report: report.name,
        value: report.metrics[metric]?.value || 0,
        formatted: formatMetricValue(report.metrics[metric]),
      }))
      .filter(v => v.value !== undefined);

    if (values.length === 0) continue;

    const change = values[values.length - 1].value - values[0].value;
    const changePercent = values[0].value !== 0 ? (change / values[0].value) * 100 : 0;
    const trend = change > 0 ? 'up' : change < 0 ? 'down' : 'flat';

    const sorted = [...values].sort((a, b) => b.value - a.value);

    comparison[metric] = {
      name: metric,
      values,
      change,
      changePercent,
      trend,
      bestPerformer: sorted[0].report,
      worstPerformer: sorted[sorted.length - 1].report,
    };

    trends[metric] = analyzeTrend(values.map(v => v.value));
  }

  const insights = generateInsights(comparison, trends);
  const summary = generateSummary(comparison);

  return {
    id: `COMP-${Date.now()}`,
    reports,
    metrics,
    comparison,
    trends,
    insights,
    summary,
  };
}

/**
 * Format metric value
 */
function formatMetricValue(metric?: ComparisonMetric): string {
  if (!metric) return 'N/A';

  switch (metric.format) {
    case 'currency':
      return `$${metric.value.toLocaleString('en-US', { maximumFractionDigits: 2 })}`;
    case 'percentage':
      return `${metric.value.toFixed(2)}%`;
    case 'time':
      return `${Math.round(metric.value)}h`;
    default:
      return metric.value.toLocaleString('en-US');
  }
}

/**
 * Analyze trend
 */
function analyzeTrend(values: number[]): TrendAnalysis {
  if (values.length < 2) {
    return {
      metric: '',
      direction: 'stable',
      velocity: 0,
      acceleration: 0,
      forecast: values[0] || 0,
      confidence: 0,
    };
  }

  // Calculate velocity (rate of change)
  const changes = [];
  for (let i = 1; i < values.length; i++) {
    changes.push(values[i] - values[i - 1]);
  }

  const velocity = changes.reduce((a, b) => a + b, 0) / changes.length;

  // Calculate acceleration (rate of change of velocity)
  const accelerations = [];
  for (let i = 1; i < changes.length; i++) {
    accelerations.push(changes[i] - changes[i - 1]);
  }

  const acceleration = accelerations.length > 0 ? accelerations.reduce((a, b) => a + b, 0) / accelerations.length : 0;

  // Determine direction
  let direction: 'increasing' | 'decreasing' | 'stable' = 'stable';
  if (velocity > 0.01) direction = 'increasing';
  if (velocity < -0.01) direction = 'decreasing';

  // Forecast next value
  const forecast = values[values.length - 1] + velocity;

  // Calculate confidence (based on consistency)
  const avgChange = Math.abs(velocity);
  const variance = changes.reduce((sum, change) => sum + Math.pow(change - velocity, 2), 0) / changes.length;
  const stdDev = Math.sqrt(variance);
  const confidence = Math.max(0, Math.min(100, 100 - (stdDev / (avgChange + 1)) * 50));

  return {
    metric: '',
    direction,
    velocity,
    acceleration,
    forecast,
    confidence,
  };
}

/**
 * Generate insights
 */
function generateInsights(
  comparison: Record<string, ComparisonMetricComparison>,
  trends: Record<string, TrendAnalysis>
): ComparisonInsight[] {
  const insights: ComparisonInsight[] = [];

  // Anomaly detection
  for (const [metric, comp] of Object.entries(comparison)) {
    if (Math.abs(comp.changePercent) > 50) {
      insights.push({
        type: 'anomaly',
        severity: Math.abs(comp.changePercent) > 100 ? 'critical' : 'high',
        title: `Significant ${metric} Change`,
        description: `${metric} changed by ${comp.changePercent.toFixed(1)}% between periods`,
        metrics: [metric],
        recommendation: `Investigate the cause of this ${comp.trend === 'up' ? 'increase' : 'decrease'}`,
      });
    }
  }

  // Trend analysis
  for (const [metric, trend] of Object.entries(trends)) {
    if (trend.direction === 'increasing' && trend.confidence > 80) {
      insights.push({
        type: 'trend',
        severity: 'low',
        title: `${metric} Trending Up`,
        description: `${metric} shows a consistent upward trend with high confidence`,
        metrics: [metric],
        recommendation: 'Continue current strategies',
      });
    }

    if (trend.direction === 'decreasing' && trend.confidence > 80) {
      insights.push({
        type: 'trend',
        severity: 'medium',
        title: `${metric} Trending Down`,
        description: `${metric} shows a consistent downward trend with high confidence`,
        metrics: [metric],
        recommendation: 'Review and adjust strategies',
      });
    }
  }

  // Opportunity detection
  for (const [metric, comp] of Object.entries(comparison)) {
    if (comp.trend === 'up' && comp.changePercent > 20) {
      insights.push({
        type: 'opportunity',
        severity: 'low',
        title: `${metric} Growth Opportunity`,
        description: `${metric} is performing well and growing`,
        metrics: [metric],
        recommendation: 'Allocate more resources to capitalize on this growth',
      });
    }
  }

  return insights;
}

/**
 * Generate summary
 */
function generateSummary(comparison: Record<string, ComparisonMetricComparison>): ComparisonSummary {
  const metrics = Object.values(comparison);

  const improvingMetrics = metrics.filter(m => m.trend === 'up').length;
  const decliningMetrics = metrics.filter(m => m.trend === 'down').length;
  const stableMetrics = metrics.filter(m => m.trend === 'flat').length;

  let overallTrend: 'positive' | 'negative' | 'mixed' = 'mixed';
  if (improvingMetrics > decliningMetrics * 1.5) overallTrend = 'positive';
  if (decliningMetrics > improvingMetrics * 1.5) overallTrend = 'negative';

  const performanceScore = Math.round(
    (improvingMetrics / metrics.length) * 100 -
    (decliningMetrics / metrics.length) * 50
  );

  return {
    totalMetrics: metrics.length,
    improvingMetrics,
    decliningMetrics,
    stableMetrics,
    overallTrend,
    performanceScore: Math.max(0, Math.min(100, performanceScore)),
  };
}

/**
 * Compare two reports
 */
export function compareReports(report1: ComparisonReport, report2: ComparisonReport): ComparisonResult {
  const allMetrics = new Set([...Object.keys(report1.metrics), ...Object.keys(report2.metrics)]);

  return createComparisonResult([report1, report2], Array.from(allMetrics));
}

/**
 * Compare multiple reports
 */
export function compareMultipleReports(reports: ComparisonReport[]): ComparisonResult {
  const allMetrics = new Set<string>();
  reports.forEach(report => {
    Object.keys(report.metrics).forEach(metric => allMetrics.add(metric));
  });

  return createComparisonResult(reports, Array.from(allMetrics));
}

/**
 * Get metric comparison chart data
 */
export function getComparisonChartData(result: ComparisonResult, metric: string) {
  const comparison = result.comparison[metric];
  if (!comparison) return null;

  return {
    labels: comparison.values.map(v => v.report),
    datasets: [
      {
        label: metric,
        data: comparison.values.map(v => v.value),
        backgroundColor: comparison.values.map((v, i) =>
          i === result.reports.length - 1 ? '#3b82f6' : '#e5e7eb'
        ),
        borderColor: '#1f2937',
        borderWidth: 1,
      },
    ],
  };
}

/**
 * Export comparison to CSV
 */
export function exportComparisonToCSV(result: ComparisonResult): string {
  const headers = ['Metric', ...result.reports.map(r => r.name), 'Change', 'Change %', 'Trend'];

  const rows = result.metrics.map(metric => {
    const comp = result.comparison[metric];
    return [
      metric,
      ...comp.values.map(v => v.value),
      comp.change.toFixed(2),
      comp.changePercent.toFixed(2),
      comp.trend,
    ];
  });

  const csv = [headers, ...rows].map(row => row.join(',')).join('\n');

  return csv;
}

/**
 * Get comparison summary text
 */
export function getComparisonSummaryText(result: ComparisonResult): string {
  const { summary } = result;

  return `
Comparison Summary
==================

Total Metrics: ${summary.totalMetrics}
Improving: ${summary.improvingMetrics} (${((summary.improvingMetrics / summary.totalMetrics) * 100).toFixed(1)}%)
Declining: ${summary.decliningMetrics} (${((summary.decliningMetrics / summary.totalMetrics) * 100).toFixed(1)}%)
Stable: ${summary.stableMetrics} (${((summary.stableMetrics / summary.totalMetrics) * 100).toFixed(1)}%)

Overall Trend: ${summary.overallTrend.toUpperCase()}
Performance Score: ${summary.performanceScore}/100

Key Insights:
${result.insights.slice(0, 5).map(i => `- ${i.title}: ${i.description}`).join('\n')}
  `.trim();
}

/**
 * Get metric comparison details
 */
export function getMetricComparisonDetails(result: ComparisonResult, metric: string) {
  const comp = result.comparison[metric];
  const trend = result.trends[metric];

  if (!comp) return null;

  return {
    metric,
    values: comp.values,
    change: comp.change,
    changePercent: comp.changePercent,
    trend: comp.trend,
    bestPerformer: comp.bestPerformer,
    worstPerformer: comp.worstPerformer,
    direction: trend.direction,
    velocity: trend.velocity,
    forecast: trend.forecast,
    confidence: trend.confidence,
  };
}

/**
 * Find correlations between metrics
 */
export function findCorrelations(result: ComparisonResult): Array<{
  metric1: string;
  metric2: string;
  correlation: number;
  strength: 'strong' | 'moderate' | 'weak';
}> {
  const metrics = result.metrics;
  const correlations = [];

  for (let i = 0; i < metrics.length; i++) {
    for (let j = i + 1; j < metrics.length; j++) {
      const metric1 = metrics[i];
      const metric2 = metrics[j];

      const values1 = result.reports.map(r => r.metrics[metric1]?.value || 0);
      const values2 = result.reports.map(r => r.metrics[metric2]?.value || 0);

      const correlation = calculateCorrelation(values1, values2);

      if (Math.abs(correlation) > 0.3) {
        const strength = Math.abs(correlation) > 0.7 ? 'strong' : Math.abs(correlation) > 0.5 ? 'moderate' : 'weak';

        correlations.push({
          metric1,
          metric2,
          correlation,
          strength,
        });
      }
    }
  }

  return correlations.sort((a, b) => Math.abs(b.correlation) - Math.abs(a.correlation));
}

/**
 * Calculate Pearson correlation coefficient
 */
function calculateCorrelation(x: number[], y: number[]): number {
  const n = Math.min(x.length, y.length);
  if (n === 0) return 0;

  const meanX = x.slice(0, n).reduce((a, b) => a + b) / n;
  const meanY = y.slice(0, n).reduce((a, b) => a + b) / n;

  let numerator = 0;
  let denomX = 0;
  let denomY = 0;

  for (let i = 0; i < n; i++) {
    const dx = x[i] - meanX;
    const dy = y[i] - meanY;

    numerator += dx * dy;
    denomX += dx * dx;
    denomY += dy * dy;
  }

  const denominator = Math.sqrt(denomX * denomY);

  return denominator === 0 ? 0 : numerator / denominator;
}
