import type { NormativeAnalysisHistory } from "@prisma/client";
import type { NormativeAnalysisResult } from "@/lib/normative-analysis/analyze";

export type NormativeAnalysisHistoryView = {
  id: string;
  sourceLicitationId: string | null;
  fileName: string;
  documentType: "BASES_LICITACION" | "CONVOCATORIA" | "REGLAMENTO" | "LEY" | "OTRO";
  issuingEntity: string | null;
  methodUsed: "direct" | "ocr";
  numPages: number;
  warnings: string[];
  extractedChars: number;
  analyzedAt: string;
  viabilityScore: number;
  riskLevel: "alto" | "medio" | "bajo";
  confidence: "low" | "medium" | "high";
  result: NormativeAnalysisResult;
};

function parseWarnings(value: unknown) {
  if (!Array.isArray(value)) {
    return [] as string[];
  }

  return value.filter((item): item is string => typeof item === "string" && item.trim().length > 0);
}

function isObject(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

function parseResult(value: unknown): NormativeAnalysisResult {
  if (!isObject(value)) {
    return {
      executiveSummary: "No fue posible recuperar el resultado del analisis.",
      participationViability: {
        score: 0,
        level: "baja",
        rationale: "Sin datos",
      },
      risk: {
        level: "alto",
        description: "Sin datos",
      },
      requiredChecklist: [],
      criticalRequirements: [],
      lockIns: [],
      preparationRecommendations: [],
      officialFormats: [],
      valueForMoney: {
        score: 0,
        signals: [],
        actions: [],
      },
      circularEconomy: {
        applicable: false,
        signals: [],
        actions: [],
      },
      sourceTraceability: [],
      confidence: "low",
    };
  }

  const candidate = value as Partial<NormativeAnalysisResult>;

  return {
    executiveSummary: typeof candidate.executiveSummary === "string" ? candidate.executiveSummary : "Sin resumen disponible.",
    participationViability:
      candidate.participationViability && typeof candidate.participationViability === "object"
        ? {
            score:
              typeof candidate.participationViability.score === "number"
                ? Math.round(candidate.participationViability.score)
                : 0,
            level:
              candidate.participationViability.level === "alta" ||
              candidate.participationViability.level === "media" ||
              candidate.participationViability.level === "baja"
                ? candidate.participationViability.level
                : "baja",
            rationale:
              typeof candidate.participationViability.rationale === "string" ? candidate.participationViability.rationale : "Sin detalle disponible.",
          }
        : {
            score: 0,
            level: "baja",
            rationale: "Sin detalle disponible.",
          },
    risk:
      candidate.risk && typeof candidate.risk === "object"
        ? {
            level: candidate.risk.level === "alto" || candidate.risk.level === "medio" || candidate.risk.level === "bajo" ? candidate.risk.level : "alto",
            description: typeof candidate.risk.description === "string" ? candidate.risk.description : "Sin detalle disponible.",
          }
        : {
            level: "alto",
            description: "Sin detalle disponible.",
          },
    requiredChecklist: Array.isArray(candidate.requiredChecklist)
      ? candidate.requiredChecklist.filter((item): item is NonNullable<NormativeAnalysisResult["requiredChecklist"]>[number] => {
          return isObject(item) && typeof item.title === "string" && typeof item.description === "string";
        })
      : [],
    criticalRequirements: Array.isArray(candidate.criticalRequirements)
      ? candidate.criticalRequirements.filter((item): item is NonNullable<NormativeAnalysisResult["criticalRequirements"]>[number] => {
          return (
            isObject(item) &&
            typeof item.title === "string" &&
            typeof item.description === "string" &&
            (item.severity === "alto" || item.severity === "medio" || item.severity === "bajo")
          );
        })
      : [],
    lockIns: Array.isArray(candidate.lockIns)
      ? candidate.lockIns.filter((item): item is NonNullable<NormativeAnalysisResult["lockIns"]>[number] => {
          return isObject(item) && typeof item.title === "string" && typeof item.impact === "string" && typeof item.recommendation === "string";
        })
      : [],
    preparationRecommendations: Array.isArray(candidate.preparationRecommendations)
      ? candidate.preparationRecommendations.filter((item): item is NonNullable<NormativeAnalysisResult["preparationRecommendations"]>[number] => {
          return (
            isObject(item) &&
            typeof item.title === "string" &&
            typeof item.description === "string" &&
            (item.priority === "alta" || item.priority === "media" || item.priority === "baja")
          );
        })
      : [],
    officialFormats: Array.isArray(candidate.officialFormats)
      ? candidate.officialFormats.filter((item): item is string => typeof item === "string")
      : [],
    valueForMoney:
      candidate.valueForMoney && isObject(candidate.valueForMoney)
        ? {
            score: typeof candidate.valueForMoney.score === "number" ? Math.round(candidate.valueForMoney.score) : 0,
            signals: Array.isArray(candidate.valueForMoney.signals)
              ? candidate.valueForMoney.signals.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
              : [],
            actions: Array.isArray(candidate.valueForMoney.actions)
              ? candidate.valueForMoney.actions.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
              : [],
          }
        : {
            score: 0,
            signals: [],
            actions: [],
          },
    circularEconomy:
      candidate.circularEconomy && isObject(candidate.circularEconomy)
        ? {
            applicable: Boolean(candidate.circularEconomy.applicable),
            signals: Array.isArray(candidate.circularEconomy.signals)
              ? candidate.circularEconomy.signals.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
              : [],
            actions: Array.isArray(candidate.circularEconomy.actions)
              ? candidate.circularEconomy.actions.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
              : [],
          }
        : {
            applicable: false,
            signals: [],
            actions: [],
          },
    sourceTraceability: Array.isArray(candidate.sourceTraceability)
      ? candidate.sourceTraceability.filter((item): item is NonNullable<NormativeAnalysisResult["sourceTraceability"]>[number] => {
          return (
            isObject(item) &&
            typeof item.documentType === "string" &&
            typeof item.sourceLabel === "string" &&
            Array.isArray(item.fields) &&
            item.fields.every((field) => typeof field === "string")
          );
        })
      : [],
    confidence: candidate.confidence === "high" || candidate.confidence === "medium" || candidate.confidence === "low" ? candidate.confidence : "low",
  };
}

export function toNormativeHistoryView(entry: Pick<NormativeAnalysisHistory, "id" | "sourceLicitationId" | "fileName" | "documentType" | "issuingEntity" | "methodUsed" | "numPages" | "warnings" | "extractedChars" | "analyzedAt" | "viabilityScore" | "riskLevel" | "confidence" | "result">): NormativeAnalysisHistoryView {
  return {
    id: entry.id,
    sourceLicitationId: entry.sourceLicitationId,
    fileName: entry.fileName,
    documentType: entry.documentType,
    issuingEntity: entry.issuingEntity,
    methodUsed: entry.methodUsed === "OCR" ? "ocr" : "direct",
    numPages: entry.numPages,
    warnings: parseWarnings(entry.warnings),
    extractedChars: entry.extractedChars,
    analyzedAt: entry.analyzedAt.toISOString(),
    viabilityScore: entry.viabilityScore,
    riskLevel: entry.riskLevel === "ALTO" ? "alto" : entry.riskLevel === "MEDIO" ? "medio" : "bajo",
    confidence: entry.confidence === "HIGH" ? "high" : entry.confidence === "MEDIUM" ? "medium" : "low",
    result: parseResult(entry.result),
  };
}
