import type { Website, ScanResult, Report } from '@prisma/client';
import type { ReportPeriod, ReportSummary } from '@wcag-ada/shared';
import { writeFile, mkdir } from 'fs/promises';
import { join } from 'path';
import { appConfig } from '../config';
import { getStorageConfig } from '@wcag-ada/config';
import { nanoid } from 'nanoid';

interface GenerateReportOptions {
  website: Website;
  scanResults: ScanResult[];
  type: 'COMPLIANCE' | 'EXECUTIVE' | 'TECHNICAL' | 'TREND';
  format: 'PDF' | 'HTML' | 'JSON' | 'CSV';
  period: ReportPeriod;
}

interface GenerateReportResult {
  summary: ReportSummary;
  data: any;
  fileUrl?: string;
}

export async function generateReport(
  options: GenerateReportOptions
): Promise<GenerateReportResult> {
  const { website, scanResults, type, format, period } = options;
  
  // Calculate summary statistics
  const summary = calculateReportSummary(scanResults, period);
  
  // Generate report data based on type
  let data: any;
  switch (type) {
    case 'COMPLIANCE':
      data = generateComplianceData(website, scanResults, summary);
      break;
    case 'EXECUTIVE':
      data = generateExecutiveData(website, scanResults, summary);
      break;
    case 'TECHNICAL':
      data = generateTechnicalData(website, scanResults, summary);
      break;
    case 'TREND':
      data = generateTrendData(website, scanResults, summary);
      break;
  }
  
  // Generate file if not JSON format
  let fileUrl: string | undefined;
  if (format !== 'JSON') {
    fileUrl = await generateReportFile(data, format, type);
  }
  
  return {
    summary,
    data,
    fileUrl,
  };
}

function calculateReportSummary(
  scanResults: ScanResult[],
  period: ReportPeriod
): ReportSummary {
  if (scanResults.length === 0) {
    return {
      averageScore: 0,
      totalScans: 0,
      improvementRate: 0,
      criticalIssuesFixed: 0,
      newIssuesFound: 0,
      complianceLevel: { level: 'AA', version: '2.1' },
    };
  }
  
  // Calculate average score
  const scores = scanResults.map(r => (r.summary as any).score || 0);
  const averageScore = scores.reduce((a, b) => a + b, 0) / scores.length;
  
  // Calculate improvement rate
  const firstScore = scores[0];
  const lastScore = scores[scores.length - 1];
  const improvementRate = firstScore > 0 ? ((lastScore - firstScore) / firstScore) * 100 : 0;
  
  // Count issues fixed and new issues
  let criticalIssuesFixed = 0;
  let newIssuesFound = 0;
  
  if (scanResults.length >= 2) {
    const firstScan = scanResults[0];
    const lastScan = scanResults[scanResults.length - 1];
    
    const firstCritical = (firstScan.summary as any).criticalIssues || 0;
    const lastCritical = (lastScan.summary as any).criticalIssues || 0;
    
    criticalIssuesFixed = Math.max(0, firstCritical - lastCritical);
    newIssuesFound = Math.max(0, lastCritical - firstCritical);
  }
  
  // Get compliance level from last scan
  const lastScan = scanResults[scanResults.length - 1];
  const complianceLevel = (lastScan.wcagCompliance as any)?.level || { level: 'AA', version: '2.1' };
  
  return {
    averageScore: Math.round(averageScore * 100) / 100,
    totalScans: scanResults.length,
    improvementRate: Math.round(improvementRate * 100) / 100,
    criticalIssuesFixed,
    newIssuesFound,
    complianceLevel,
  };
}

function generateComplianceData(
  website: Website,
  scanResults: ScanResult[],
  summary: ReportSummary
): any {
  return {
    website: {
      name: website.name,
      url: website.url,
    },
    summary,
    latestScan: scanResults[scanResults.length - 1],
    complianceHistory: scanResults.map(r => ({
      date: r.createdAt,
      score: (r.summary as any).score,
      compliant: (r.wcagCompliance as any).isCompliant,
    })),
  };
}

function generateExecutiveData(
  website: Website,
  scanResults: ScanResult[],
  summary: ReportSummary
): any {
  return {
    website: {
      name: website.name,
      url: website.url,
    },
    summary,
    keyMetrics: {
      currentScore: (scanResults[scanResults.length - 1].summary as any).score,
      improvement: summary.improvementRate,
      totalIssues: (scanResults[scanResults.length - 1].summary as any).violationCount,
      criticalIssues: (scanResults[scanResults.length - 1].summary as any).criticalIssues,
    },
    recommendations: generateRecommendations(scanResults[scanResults.length - 1]),
  };
}

function generateTechnicalData(
  website: Website,
  scanResults: ScanResult[],
  summary: ReportSummary
): any {
  const latestScan = scanResults[scanResults.length - 1];
  return {
    website: {
      name: website.name,
      url: website.url,
    },
    summary,
    violations: latestScan.violations,
    topIssues: getTopIssues(latestScan.violations as any[]),
    fixPriority: generateFixPriority(latestScan.violations as any[]),
  };
}

function generateTrendData(
  website: Website,
  scanResults: ScanResult[],
  summary: ReportSummary
): any {
  return {
    website: {
      name: website.name,
      url: website.url,
    },
    summary,
    trends: scanResults.map(r => ({
      date: r.createdAt,
      score: (r.summary as any).score,
      violations: (r.summary as any).violationCount,
      critical: (r.summary as any).criticalIssues,
      serious: (r.summary as any).seriousIssues,
      moderate: (r.summary as any).moderateIssues,
      minor: (r.summary as any).minorIssues,
    })),
  };
}

function generateRecommendations(scanResult: ScanResult): string[] {
  const violations = scanResult.violations as any[];
  const recommendations: string[] = [];
  
  // Group violations by type and generate recommendations
  const criticalViolations = violations.filter(v => v.impact === 'critical');
  if (criticalViolations.length > 0) {
    recommendations.push('Address critical accessibility violations immediately to reduce legal risk');
  }
  
  // Add more intelligent recommendations based on violation patterns
  
  return recommendations;
}

function getTopIssues(violations: any[]): any[] {
  // Sort by impact and number of occurrences
  return violations
    .sort((a, b) => {
      const impactOrder = { critical: 4, serious: 3, moderate: 2, minor: 1 };
      const aScore = impactOrder[a.impact] * a.nodes.length;
      const bScore = impactOrder[b.impact] * b.nodes.length;
      return bScore - aScore;
    })
    .slice(0, 10);
}

function generateFixPriority(violations: any[]): any[] {
  // Generate prioritized fix list
  return violations
    .map(v => ({
      id: v.id,
      impact: v.impact,
      occurrences: v.nodes.length,
      estimatedTime: estimateFixTime(v),
      priority: calculatePriority(v),
    }))
    .sort((a, b) => b.priority - a.priority);
}

function estimateFixTime(violation: any): number {
  const baseTime = {
    critical: 30,
    serious: 20,
    moderate: 15,
    minor: 10,
  };
  return (baseTime[violation.impact] || 15) * violation.nodes.length;
}

function calculatePriority(violation: any): number {
  const impactScore = { critical: 100, serious: 75, moderate: 50, minor: 25 };
  return (impactScore[violation.impact] || 50) * Math.log(violation.nodes.length + 1);
}

async function generateReportFile(
  data: any,
  format: 'PDF' | 'HTML' | 'CSV',
  type: string
): Promise<string> {
  const storageConfig = getStorageConfig();
  const reportPath = join(storageConfig.local.basePath, storageConfig.local.reports);
  
  // Create report directory if it doesn't exist
  await mkdir(reportPath, { recursive: true });
  
  const filename = `${type.toLowerCase()}_${nanoid()}.${format.toLowerCase()}`;
  const filepath = join(reportPath, filename);
  
  // For now, just save as JSON
  // In production, you would generate actual PDF/HTML/CSV files
  await writeFile(filepath, JSON.stringify(data, null, 2));
  
  // Return relative URL (in production, this would be a CDN URL)
  return `/reports/${filename}`;
}