import type { LicitationReviewStatus, ProposalStatus } from "@prisma/client";
import { computeWorkflowGate, ProposalWorkflowStateSchema, type ProposalWorkflowState } from "@/lib/proposals/workflow-state";
import type {
  ComplianceAlertView,
  ComplianceChecklistItem,
  ComplianceDeadlineItem,
  CompliancePanelItem,
  M7Dataset,
  SignaturePolicyStatus,
} from "@/lib/compliance/types";

type ProposalM7Input = {
  id: string;
  title: string;
  status: ProposalStatus;
  sourceLicitationId: string | null;
  workflowDraft: unknown;
  updatedAt: Date;
};

type M3Counters = {
  totalOpenLicitations: number;
  reviewed: number;
  interested: number;
  activeLinked: number;
};

type VerificationDueItem = {
  sourceId: string;
  sourceTitle: string;
  authorityName: string;
  dueAt: string;
  overdue: boolean;
};

const CRITICAL_DEADLINE_HOURS = 72;

function parseWorkflowDraft(value: unknown) {
  const parsed = ProposalWorkflowStateSchema.safeParse(value);
  return parsed.success ? parsed.data : null;
}

function isCriticalRequirement(requirement: ProposalWorkflowState["requirements"][number]) {
  if (requirement.source === "critical_requirement") {
    return true;
  }

  const text = `${requirement.title} ${requirement.description}`.toLowerCase();
  return /\bcritic|alto\b|descalific|inhabilit|sancion/.test(text);
}

function toSignatureStatus(workflow: ProposalWorkflowState): SignaturePolicyStatus {
  const candidate = (workflow as ProposalWorkflowState & { signatureCompliance?: { policyStatus?: SignaturePolicyStatus } }).signatureCompliance;
  return candidate?.policyStatus ?? "requiere_validacion_legal";
}

export function isOperationalProposal(status: ProposalStatus) {
  return status === "DRAFT" || status === "IN_PROGRESS";
}

function toDeadlineStatus(dateIso: string, now: Date) {
  const due = new Date(dateIso);
  if (Number.isNaN(due.getTime())) {
    return null;
  }

  return {
    due,
    overdue: due.getTime() < now.getTime(),
  };
}

function buildChecklistRows(proposals: Array<ProposalM7Input & { workflow: ProposalWorkflowState }>): ComplianceChecklistItem[] {
  return proposals.map((proposal) => {
    const gate = computeWorkflowGate(proposal.workflow);
    const completionRate = gate.mandatoryCount > 0 ? Math.round((gate.resolvedCount / gate.mandatoryCount) * 100) : 0;

    return {
      proposalId: proposal.id,
      proposalTitle: proposal.title,
      mandatoryResolved: gate.resolvedCount,
      mandatoryTotal: gate.mandatoryCount,
      completionRate,
      signaturePolicyStatus: toSignatureStatus(proposal.workflow),
    };
  });
}

function buildProposalDeadlines(proposals: Array<ProposalM7Input & { workflow: ProposalWorkflowState }>, now: Date): ComplianceDeadlineItem[] {
  const rows: ComplianceDeadlineItem[] = [];

  for (const proposal of proposals) {
    for (const milestone of proposal.workflow.milestones) {
      if (!milestone.dateIso) {
        continue;
      }

      const timeline = toDeadlineStatus(milestone.dateIso, now);
      if (!timeline) {
        continue;
      }

      rows.push({
        id: `${proposal.id}-${milestone.id}`,
        proposalId: proposal.id,
        licitationId: proposal.sourceLicitationId,
        title: milestone.title,
        description: milestone.note || `Hito de ${proposal.title}`,
        dueAt: timeline.due.toISOString(),
        source: "milestone",
        status: timeline.overdue ? "overdue" : "upcoming",
      });
    }
  }

  return rows;
}

function buildVerificationDeadlines(items: VerificationDueItem[]): ComplianceDeadlineItem[] {
  return items.map((item) => ({
    id: `verification-${item.sourceId}`,
    proposalId: null,
    licitationId: item.sourceId,
    title: `Verificacion normativa: ${item.sourceTitle}`,
    description: `${item.authorityName} (${item.overdue ? "atrasada" : "programada"})`,
    dueAt: item.dueAt,
    source: "normative_verification",
    status: item.overdue ? "overdue" : "upcoming",
  }));
}

function calculateCriticalPending(proposals: Array<ProposalM7Input & { workflow: ProposalWorkflowState }>, deadlines: ComplianceDeadlineItem[], now: Date) {
  const deadlineByProposal = new Map<string, ComplianceDeadlineItem[]>();

  for (const item of deadlines) {
    if (!item.proposalId) {
      continue;
    }

    const existing = deadlineByProposal.get(item.proposalId) ?? [];
    existing.push(item);
    deadlineByProposal.set(item.proposalId, existing);
  }

  let total = 0;

  for (const proposal of proposals) {
    const proposalDeadlines = deadlineByProposal.get(proposal.id) ?? [];
    const hasUrgentDeadline = proposalDeadlines.some((deadline) => {
      const due = new Date(deadline.dueAt);
      if (Number.isNaN(due.getTime())) {
        return false;
      }

      const diffHours = (due.getTime() - now.getTime()) / 3_600_000;
      return diffHours <= CRITICAL_DEADLINE_HOURS;
    });

    if (!hasUrgentDeadline) {
      continue;
    }

    const pendingCriticalRequirements = proposal.workflow.requirements.filter((item) => item.status === "pending" && isCriticalRequirement(item));
    total += pendingCriticalRequirements.length;

    if (toSignatureStatus(proposal.workflow) === "requiere_validacion_legal") {
      total += 1;
    }
  }

  return total;
}

function buildAlerts(args: {
  criticalPending: number;
  deadlines: ComplianceDeadlineItem[];
  checklist: ComplianceChecklistItem[];
  now: Date;
}): ComplianceAlertView[] {
  const alerts: ComplianceAlertView[] = [];

  for (const deadline of args.deadlines) {
    const due = new Date(deadline.dueAt);
    const diffHours = (due.getTime() - args.now.getTime()) / 3_600_000;

    if (deadline.status === "overdue") {
      alerts.push({
        id: `alert-overdue-${deadline.id}`,
        proposalId: deadline.proposalId,
        licitationId: deadline.licitationId,
        title: `Vencido: ${deadline.title}`,
        description: deadline.description,
        severity: "high",
        kind: "deadline_overdue",
        dueAt: deadline.dueAt,
        createdAt: args.now.toISOString(),
      });
      continue;
    }

    if (diffHours <= 72) {
      alerts.push({
        id: `alert-soon-${deadline.id}`,
        proposalId: deadline.proposalId,
        licitationId: deadline.licitationId,
        title: `Vence pronto: ${deadline.title}`,
        description: deadline.description,
        severity: diffHours <= 24 ? "high" : "medium",
        kind: "deadline_soon",
        dueAt: deadline.dueAt,
        createdAt: args.now.toISOString(),
      });
    }
  }

  if (args.criticalPending > 0) {
    alerts.unshift({
      id: "alert-critical-pending",
      proposalId: null,
      licitationId: null,
      title: "Pendientes criticos detectados",
      description: `${args.criticalPending} pendientes combinan severidad alta con plazo inminente o vencido.`,
      severity: "high",
      kind: "critical_requirement_pending",
      dueAt: null,
      createdAt: args.now.toISOString(),
    });
  }

  for (const item of args.checklist) {
    if (item.signaturePolicyStatus === "requiere_validacion_legal") {
      alerts.push({
        id: `alert-signature-${item.proposalId}`,
        proposalId: item.proposalId,
        licitationId: null,
        title: `Firma electronica: validacion legal requerida`,
        description: `La propuesta ${item.proposalTitle} conserva semaforo conservador de firma.`,
        severity: "medium",
        kind: "signature_policy",
        dueAt: null,
        createdAt: args.now.toISOString(),
      });
    }
  }

  return alerts;
}

function buildPanelRows(dataset: {
  activeLicitations: number;
  completionRate: number;
  criticalPending: number;
  upcoming7Days: number;
  reviewed: number;
  interested: number;
}) {
  const panel: CompliancePanelItem[] = [
    {
      id: "panel-active",
      label: "Licitaciones activas",
      value: String(dataset.activeLicitations),
      tone: dataset.activeLicitations > 0 ? "success" : "neutral",
    },
    {
      id: "panel-completion",
      label: "Completitud obligatoria",
      value: `${dataset.completionRate}%`,
      tone: dataset.completionRate >= 70 ? "success" : dataset.completionRate >= 40 ? "warning" : "danger",
    },
    {
      id: "panel-critical",
      label: "Pendientes criticos",
      value: String(dataset.criticalPending),
      tone: dataset.criticalPending > 0 ? "danger" : "success",
    },
    {
      id: "panel-upcoming",
      label: "Proximos 7 dias",
      value: String(dataset.upcoming7Days),
      tone: dataset.upcoming7Days > 0 ? "warning" : "neutral",
    },
    {
      id: "panel-consulted",
      label: "M3 Consultadas",
      value: String(dataset.reviewed),
      tone: "neutral",
    },
    {
      id: "panel-interested",
      label: "M3 Me interesa",
      value: String(dataset.interested),
      tone: "neutral",
    },
  ];

  return panel;
}

export function computeM3Counters(args: {
  totalOpenLicitations: number;
  preferences: Array<{ status: LicitationReviewStatus }>;
  activeLinked: number;
}): M3Counters {
  const reviewed = args.preferences.filter((item) => item.status === "REVIEWED").length;
  const interested = args.preferences.filter((item) => item.status === "INTERESTED").length;

  return {
    totalOpenLicitations: Math.max(0, args.totalOpenLicitations),
    reviewed,
    interested,
    activeLinked: Math.max(0, args.activeLinked),
  };
}

export function buildM7Dataset(args: {
  proposals: ProposalM7Input[];
  m3: M3Counters;
  dueVerifications: VerificationDueItem[];
  externalAlerts?: ComplianceAlertView[];
  now?: Date;
}): M7Dataset {
  const now = args.now ?? new Date();
  const horizon = new Date(now);
  horizon.setUTCDate(horizon.getUTCDate() + 7);

  const activeProposals = args.proposals
    .filter((proposal) => isOperationalProposal(proposal.status))
    .map((proposal) => ({
      ...proposal,
      workflow: parseWorkflowDraft(proposal.workflowDraft),
    }))
    .filter((proposal): proposal is ProposalM7Input & { workflow: ProposalWorkflowState } => Boolean(proposal.workflow));

  const checklist = buildChecklistRows(activeProposals);
  const proposalDeadlines = buildProposalDeadlines(activeProposals, now);
  const verificationDeadlines = buildVerificationDeadlines(args.dueVerifications);
  const allDeadlines = [...proposalDeadlines, ...verificationDeadlines].sort((left, right) => new Date(left.dueAt).getTime() - new Date(right.dueAt).getTime());

  const mandatoryResolved = checklist.reduce((sum, item) => sum + item.mandatoryResolved, 0);
  const mandatoryTotal = checklist.reduce((sum, item) => sum + item.mandatoryTotal, 0);
  const completionRate = mandatoryTotal > 0 ? Math.round((mandatoryResolved / mandatoryTotal) * 100) : 0;
  const upcoming7Days = allDeadlines.filter((item) => {
    const dueAt = new Date(item.dueAt);
    return !Number.isNaN(dueAt.getTime()) && dueAt <= horizon;
  }).length;

  const criticalPending = calculateCriticalPending(activeProposals, allDeadlines, now);
  const generatedAlerts = buildAlerts({
    criticalPending,
    deadlines: allDeadlines,
    checklist,
    now,
  });
  const alerts = [...generatedAlerts, ...(args.externalAlerts ?? [])];

  const reviewed = args.m3.reviewed;
  const interested = args.m3.interested;
  const knownStatus = reviewed + interested;
  const estimatedNew = Math.max(0, args.m3.totalOpenLicitations - knownStatus);

  return {
    generatedAt: now.toISOString(),
    kpis: {
      activeLicitations: activeProposals.length,
      completionRate,
      criticalPending,
      upcoming7Days,
    },
    m3States: {
      consulted: reviewed,
      interested,
      active: args.m3.activeLinked,
      new: estimatedNew,
    },
    tabs: {
      plazos: allDeadlines,
      alertas: alerts,
      checklist,
      panelKpi: buildPanelRows({
        activeLicitations: activeProposals.length,
        completionRate,
        criticalPending,
        upcoming7Days,
        reviewed,
        interested,
      }),
    },
  };
}
