import type { AuditReport, AuditLLMResponse, ModuleAuditResult, ScenarioResult, ModuleType } from './types';
import { MODULE_LABELS } from './types';

interface RawLLMOutput {
  results?: AuditLLMResponse[];
  [key: string]: unknown;
}

export function parseLLMResponse(
  rawText: string,
  scenarioIds: string[],
): AuditLLMResponse[] {
  let parsed: RawLLMOutput = {};
  try {
    parsed = JSON.parse(rawText);
  } catch {
    const jsonMatch = rawText.match(/```json\s*([\s\S]*?)\s*```/) ||
                     rawText.match(/```\s*([\s\S]*?)\s*```/) ||
                     rawText.match(/{[\s\S]*}/);
    if (jsonMatch) {
      try {
        parsed = JSON.parse(jsonMatch[jsonMatch.length - 1]);
      } catch {
        throw new Error('Could not parse LLM response as JSON');
      }
    } else {
      throw new Error('Could not extract JSON from LLM response');
    }
  }
  const results = parsed.results as AuditLLMResponse[] | undefined;
  if (!results || !Array.isArray(results)) {
    throw new Error('LLM response does not contain a "results" array');
  }
  const byId = new Map(results.map(r => [r.scenarioId, r]));
  const ordered: AuditLLMResponse[] = [];
  for (const id of scenarioIds) {
    const found = byId.get(id);
    if (found) {
      ordered.push(found);
    } else {
      ordered.push({
        scenarioId: id,
        verdict: 'FAIL',
        checks: [{
          name: 'Response completeness',
          status: 'FAIL',
          expected: 'Scenario in response',
          actual: 'Missing from response',
          explanation: `Scenario "${id}" was not found in LLM response`,
        }],
        summary: `MISSING from LLM response`,
      });
    }
  }
  return ordered;
}

export function buildAuditReport(
  llmResults: AuditLLMResponse[],
  scenarioMap: Map<string, { module: ModuleType; moduleLabel: string }>,
  provider: string,
  model: string,
  rawResponse?: string,
): AuditReport {
  const moduleMap = new Map<ModuleType, { passed: number; warnings: number; failed: number; results: ScenarioResult[] }>();
  for (const r of llmResults) {
    const info = scenarioMap.get(r.scenarioId) ?? { module: 'galpao' as ModuleType, moduleLabel: 'Galpão' };
    if (!moduleMap.has(info.module)) {
      moduleMap.set(info.module, { passed: 0, warnings: 0, failed: 0, results: [] });
    }
    const m = moduleMap.get(info.module)!;
    const verdict = r.verdict ?? 'FAIL';
    if (verdict === 'PASS') m.passed++;
    else if (verdict === 'WARN') m.warnings++;
    else m.failed++;
    m.results.push({
      scenarioId: r.scenarioId,
      verdict,
      checks: r.checks ?? [],
      summary: r.summary ?? '',
      calculation_steps: r.calculation_steps,
      llmNotes: r.llmNotes,
      enunciado_problema: r.enunciado_problema,
      tabelas_nbr_consultadas: r.tabelas_nbr_consultadas,
      resultado_app: r.resultado_app,
      desvio_percentual: r.desvio_percentual,
    });
  }
  const modules: ModuleAuditResult[] = [];
  let totalPassed = 0, totalWarnings = 0, totalFailed = 0;
  for (const [module, data] of moduleMap.entries()) {
    modules.push({
      module,
      moduleLabel: MODULE_LABELS[module]?.['pt-BR'] ?? module,
      totalScenarios: data.results.length,
      passed: data.passed,
      warnings: data.warnings,
      failed: data.failed,
      scenarios: data.results,
    });
    totalPassed += data.passed;
    totalWarnings += data.warnings;
    totalFailed += data.failed;
  }
  return {
    id: `audit-${Date.now()}`,
    provider,
    model,
    timestamp: Date.now(),
    totalScenarios: llmResults.length,
    totalPassed,
    totalWarnings,
    totalFailed,
    modules,
    rawResponse,
  };
}
