"use client";

import Link from "next/link";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { computeWorkflowCompletionPercent, computeWorkflowGate, type ProposalWorkflowState, type ProposalWorkflowGate } from "@/lib/proposals/workflow-state";
import { buildDefaultWorkflowDraft } from "@/lib/proposals/workflow-default";
import type { WorkflowMilestoneSeed, WorkflowRequirementCategory, WorkflowRequirementSeed, WorkflowTechnicalSectionSeed } from "@/lib/proposals/workflow";
import { getSignaturePolicyStatusLabel, getSignaturePolicyTone } from "@/lib/compliance/signature-policy";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";

type ProposalDocumentView = {
  id: string;
  fileName: string;
  mimeType: string;
  sizeBytes: number;
  createdAt: string;
};

type ProposalWorkflowViewProps = {
  proposal: {
    id: string;
    title: string;
    issuingEntity: string;
    summary: string;
    status: "DRAFT" | "IN_PROGRESS" | "SUBMITTED" | "ARCHIVED";
    sourceLicitationId: string | null;
    updatedAt: string;
    documents: ProposalDocumentView[];
  };
  linkedSource:
    | {
        id: string;
        title: string;
        description: string;
        issuingEntity: string | null;
        procedureType: string;
        stateName: string;
        municipalityName: string;
        sourceUrl: string | null;
        documentLinks: Array<{ name: string; url: string; type: string | null }>;
        milestones: WorkflowMilestoneSeed[];
      }
    | null;
  normativeContext:
    | {
        id: string;
        analyzedAt: string;
        executiveSummary: string;
        confidence: "low" | "medium" | "high";
        requirementSeeds: WorkflowRequirementSeed[];
        technicalSeeds: WorkflowTechnicalSectionSeed[];
      }
    | null;
  autoExtractOnLoad?: boolean;
};

type WorkflowDraft = ProposalWorkflowState;
type RequirementStatus = WorkflowDraft["requirements"][number]["status"];
type RequirementDraft = WorkflowDraft["requirements"][number];
type EconomicItemDraft = WorkflowDraft["economicItems"][number];

type ApiPayload = {
  ok?: boolean;
  error?: string;
  proposal?: {
    id: string;
    status: "DRAFT" | "IN_PROGRESS" | "SUBMITTED" | "ARCHIVED";
    currentStep?: number;
    completionPercent?: number;
    readyForSubmissionAt?: string | null;
    documents: ProposalDocumentView[];
  };
  workflow?: WorkflowDraft | null;
  gate?: ProposalWorkflowGate | null;
  analysis?: {
    source?: "module4_history" | "uploaded_pdf";
    engine?: string | null;
    model?: string | null;
    warnings?: string[];
    bundle?: {
      sources?: Array<{ sourceId?: string; fileName: string; documentType: string; historyId?: string | null }>;
      conflicts?: Array<{ title: string; field: string }>;
    };
  };
};

const STEPS = ["Info", "Docs", "Tecnica", "Economica", "Validacion", "Fechas"] as const;
const IVA_RATE = 0.16;

function newId(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}

function formatCurrency(value: number) {
  return value.toLocaleString("es-MX", {
    style: "currency",
    currency: "MXN",
    maximumFractionDigits: 2,
  });
}

function formatDateTime(value: string | null) {
  if (!value) {
    return "Sin fecha";
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return "Sin fecha";
  }

  return parsed.toLocaleString("es-MX", {
    year: "numeric",
    month: "long",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  });
}

function isoToLocalInput(value: string | null) {
  if (!value) {
    return "";
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return "";
  }

  const offset = parsed.getTimezoneOffset() * 60_000;
  return new Date(parsed.getTime() - offset).toISOString().slice(0, 16);
}

function localInputToIso(value: string) {
  if (!value.trim()) {
    return null;
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed.toISOString();
}

function categoryLabel(value: WorkflowRequirementCategory) {
  if (value === "administrativo") {
    return "Administrativo";
  }

  if (value === "legal") {
    return "Legal";
  }

  if (value === "tecnico") {
    return "Tecnico";
  }

  if (value === "economico") {
    return "Economico";
  }

  return "General";
}

function sourceLabel(value: WorkflowRequirementSeed["source"]) {
  if (value === "official_format") {
    return "Formato oficial";
  }

  if (value === "required_checklist") {
    return "Checklist IA";
  }

  if (value === "critical_requirement") {
    return "Critico IA";
  }

  return "Candado IA";
}

function toStatusLabel(status: RequirementStatus) {
  if (status === "completed") {
    return "Completo";
  }

  if (status === "na") {
    return "No aplica";
  }

  return "Pendiente";
}

function createBaseDraft(props: ProposalWorkflowViewProps): WorkflowDraft {
  return buildDefaultWorkflowDraft({
    proposal: {
      title: props.proposal.title,
      issuingEntity: props.proposal.issuingEntity,
      summary: props.proposal.summary,
      status: props.proposal.status,
    },
    linkedSource: props.linkedSource
      ? {
          title: props.linkedSource.title,
          description: props.linkedSource.description,
          issuingEntity: props.linkedSource.issuingEntity,
          procedureType: props.linkedSource.procedureType,
          stateName: props.linkedSource.stateName,
          municipalityName: props.linkedSource.municipalityName,
          sourceUrl: props.linkedSource.sourceUrl,
          milestones: props.linkedSource.milestones,
        }
      : null,
    requirementSeeds: props.normativeContext?.requirementSeeds ?? [],
    technicalSectionSeeds: props.normativeContext?.technicalSeeds ?? [],
  });
}

function computeEconomicTotals(items: EconomicItemDraft[]) {
  const subtotal = items.reduce((acc, item) => acc + Math.max(0, item.quantity) * Math.max(0, item.unitPrice), 0);
  const iva = subtotal * IVA_RATE;
  const total = subtotal + iva;

  return { subtotal, iva, total };
}

function byCategory(requirements: RequirementDraft[]) {
  const order: WorkflowRequirementCategory[] = ["administrativo", "legal", "tecnico", "economico", "general"];
  return order
    .map((category) => ({
      category,
      items: requirements.filter((item) => item.category === category),
    }))
    .filter((bucket) => bucket.items.length > 0);
}

function requirementTone(status: RequirementStatus) {
  if (status === "completed") {
    return "border-[#b9e6cd] bg-[#eaf9f1]";
  }

  if (status === "na") {
    return "border-[#f0deb0] bg-[#fff8e9]";
  }

  return "border-[#d8e1ef] bg-white";
}

function hasRequirementEvidence(item: RequirementDraft) {
  return item.evidences.length > 0;
}

function isRequirementResolved(item: RequirementDraft) {
  return item.status !== "pending" && (item.status === "na" || hasRequirementEvidence(item));
}

function milestoneSourceLabel(source: WorkflowDraft["milestones"][number]["source"]) {
  if (source === "ai") {
    return "IA";
  }

  if (source === "licitation") {
    return "Portal";
  }

  return "Manual";
}

function getMilestoneTimelineTone(dateIso: string | null) {
  if (!dateIso) {
    return {
      dot: "bg-[#d6a441]",
      badge: "border-[#f0deb0] bg-[#fff8e9] text-[#8d6308]",
      label: "Sin fecha",
    };
  }

  const time = new Date(dateIso).getTime();
  if (Number.isNaN(time)) {
    return {
      dot: "bg-[#d6a441]",
      badge: "border-[#f0deb0] bg-[#fff8e9] text-[#8d6308]",
      label: "Sin fecha",
    };
  }

  const now = Date.now();
  const diff = time - now;
  const hours = diff / 3_600_000;

  if (hours < 0) {
    return {
      dot: "bg-[#d55668]",
      badge: "border-[#f1c7ce] bg-[#fff1f4] text-[#b23f50]",
      label: "Vencido",
    };
  }

  if (hours <= 24) {
    return {
      dot: "bg-[#e0aa1f]",
      badge: "border-[#f0deb0] bg-[#fff8e9] text-[#8d6308]",
      label: "Hoy",
    };
  }

  return {
    dot: "bg-[#2f79d6]",
    badge: "border-[#c6d8f4] bg-[#ebf3ff] text-[#284f88]",
    label: "Programado",
  };
}

export function ProposalWorkflowView(props: ProposalWorkflowViewProps) {
  const requirementInputRefs = useRef<Record<string, HTMLInputElement | null>>({});
  const aiFileInputRef = useRef<HTMLInputElement | null>(null);
  const autoExtractAttemptedRef = useRef(false);
  const baseDraft = useMemo(() => createBaseDraft(props), [props]);
  const [workflow, setWorkflow] = useState<WorkflowDraft>(baseDraft);
  const [proposalStatus, setProposalStatus] = useState(props.proposal.status);
  const [documents, setDocuments] = useState<ProposalDocumentView[]>(props.proposal.documents);
  const [workflowLoaded, setWorkflowLoaded] = useState(false);
  const [isLoadingWorkflow, setIsLoadingWorkflow] = useState(true);
  const [isSyncingWorkflow, setIsSyncingWorkflow] = useState(false);
  const [lastSavedAt, setLastSavedAt] = useState<string | null>(null);
  const [workflowRevision, setWorkflowRevision] = useState(0);
  const [isSavingInfo, setIsSavingInfo] = useState(false);
  const [isSavingReady, setIsSavingReady] = useState(false);
  const [uploadingRequirementId, setUploadingRequirementId] = useState<string | null>(null);
  const [draggingRequirementId, setDraggingRequirementId] = useState<string | null>(null);
  const [isExtractingAi, setIsExtractingAi] = useState(false);
  const [pdfLoadingKind, setPdfLoadingKind] = useState<"technical" | "economic" | "summary" | null>(null);
  const [message, setMessage] = useState<string | null>(null);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [lastExtractionAnalysis, setLastExtractionAnalysis] = useState<ApiPayload["analysis"] | null>(null);
  const [newSectionTitle, setNewSectionTitle] = useState("");
  const [newMilestoneTitle, setNewMilestoneTitle] = useState("");
  const [newConcept, setNewConcept] = useState({
    concept: "",
    unit: "pieza",
    quantity: 1,
    unitPrice: 0,
  });

  useEffect(() => {
    let isMounted = true;

    async function loadWorkflow() {
      setIsLoadingWorkflow(true);
      setWorkflowLoaded(false);
      setErrorMessage(null);

      try {
        const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}/workflow`);
        const payload = (await response.json().catch(() => ({}))) as ApiPayload;

        if (!response.ok || !payload.ok) {
          throw new Error(payload.error ?? "No fue posible cargar el flujo de trabajo.");
        }

        if (!isMounted) {
          return;
        }

        setProposalStatus(payload.proposal?.status ?? props.proposal.status);
        setDocuments(payload.proposal?.documents ?? props.proposal.documents);
        setWorkflow(payload.workflow ?? baseDraft);
      } catch (error) {
        if (!isMounted) {
          return;
        }

        setWorkflow(baseDraft);
        setErrorMessage(error instanceof Error ? error.message : "No fue posible cargar el flujo de trabajo.");
      } finally {
        if (isMounted) {
          setIsLoadingWorkflow(false);
          setWorkflowLoaded(true);
          setWorkflowRevision(0);
        }
      }
    }

    loadWorkflow();
    return () => {
      isMounted = false;
    };
  }, [baseDraft, props.proposal.documents, props.proposal.id, props.proposal.status]);

  useEffect(() => {
    autoExtractAttemptedRef.current = false;
  }, [props.proposal.id]);

  const persistWorkflowState = useCallback(async (nextWorkflow: WorkflowDraft) => {
    setIsSyncingWorkflow(true);

    try {
      const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}/workflow`, {
        method: "PATCH",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          workflow: nextWorkflow,
        }),
      });
      const payload = (await response.json().catch(() => ({}))) as ApiPayload;
      if (!response.ok || !payload.ok) {
        throw new Error(payload.error ?? "No fue posible guardar el flujo de trabajo.");
      }

      if (payload.proposal?.status) {
        setProposalStatus(payload.proposal.status);
      }
      setLastSavedAt(new Date().toISOString());
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "No fue posible guardar el flujo de trabajo.");
    } finally {
      setIsSyncingWorkflow(false);
    }
  }, [props.proposal.id]);

  function updateWorkflow(updater: (previous: WorkflowDraft) => WorkflowDraft) {
    setWorkflow((previous) => updater(previous));
    setWorkflowRevision((previous) => previous + 1);
  }

  useEffect(() => {
    if (!workflowLoaded || workflowRevision <= 0) {
      return;
    }

    const timer = setTimeout(() => {
      void persistWorkflowState(workflow);
    }, 700);

    return () => clearTimeout(timer);
  }, [workflow, workflowLoaded, workflowRevision, persistWorkflowState]);

  const groupedRequirements = useMemo(() => byCategory(workflow.requirements), [workflow.requirements]);
  const economicTotals = useMemo(() => computeEconomicTotals(workflow.economicItems), [workflow.economicItems]);
  const documentsById = useMemo(() => new Map(documents.map((item) => [item.id, item])), [documents]);
  const sortedMilestones = useMemo(
    () =>
      [...workflow.milestones].sort((a, b) => {
        if (!a.dateIso && !b.dateIso) {
          return a.title.localeCompare(b.title, "es-MX");
        }
        if (!a.dateIso) {
          return 1;
        }
        if (!b.dateIso) {
          return -1;
        }
        return new Date(a.dateIso).getTime() - new Date(b.dateIso).getTime();
      }),
    [workflow.milestones],
  );

  const gate = useMemo(() => computeWorkflowGate(workflow), [workflow]);

  const stepCompletion = useMemo(
    () => [gate.infoReady, gate.docsReady, gate.technicalReady, gate.economicReady, gate.allReady, gate.datesReady],
    [gate],
  );
  const completionPercent = useMemo(() => computeWorkflowCompletionPercent(workflow), [workflow]);

  async function patchProposal(body: Record<string, unknown>) {
    const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    const payload = (await response.json().catch(() => ({}))) as ApiPayload;
    if (!response.ok || !payload.ok || !payload.proposal) {
      throw new Error(payload.error ?? "No fue posible actualizar la propuesta.");
    }

    setProposalStatus(payload.proposal.status);
    if (payload.proposal.documents) {
      setDocuments(payload.proposal.documents);
    }
  }

  async function handleSaveInfo() {
    setIsSavingInfo(true);
    setErrorMessage(null);
    setMessage(null);

    try {
      await patchProposal({
        title: workflow.info.title.trim(),
        issuingEntity: workflow.info.issuingEntity.trim(),
        summary: workflow.info.description.trim(),
      });
      setMessage("Informacion guardada.");
      await persistWorkflowState(workflow);
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "No fue posible guardar la informacion.");
    } finally {
      setIsSavingInfo(false);
    }
  }

  async function handleRequirementUpload(requirementId: string, file: File | null) {
    if (!file) {
      return;
    }

    setUploadingRequirementId(requirementId);
    setErrorMessage(null);
    setMessage(null);

    try {
      const previousDocumentIds = new Set(documents.map((item) => item.id));
      const formData = new FormData();
      formData.append("file", file);

      const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}/documents`, {
        method: "POST",
        body: formData,
      });

      const payload = (await response.json().catch(() => ({}))) as ApiPayload;
      if (!response.ok || !payload.ok || !payload.proposal) {
        throw new Error(payload.error ?? "No fue posible subir el documento.");
      }

      const nextDocuments = payload.proposal.documents;
      const uploadedDocument =
        nextDocuments.find((item) => !previousDocumentIds.has(item.id)) ??
        nextDocuments.find((item) => item.fileName === file.name) ??
        null;

      if (!uploadedDocument) {
        throw new Error("El archivo se subio, pero no se pudo vincular al requisito.");
      }

      setDocuments(nextDocuments);
      setProposalStatus(payload.proposal.status);
      updateWorkflow((previous) => ({
        ...previous,
        requirements: previous.requirements.map((entry) => {
          if (entry.id !== requirementId) {
            return entry;
          }

          const alreadyLinked = entry.evidences.some((evidence) => evidence.documentId === uploadedDocument.id);
          const nextEvidences = alreadyLinked
            ? entry.evidences
            : [
                {
                  id: newId("evidence"),
                  documentId: uploadedDocument.id,
                  fileName: uploadedDocument.fileName,
                  uploadedAtIso: uploadedDocument.createdAt,
                },
                ...entry.evidences,
              ];

          return {
            ...entry,
            status: entry.status === "na" ? "na" : "completed",
            evidences: nextEvidences,
          };
        }),
      }));
      setMessage(`Archivo vinculado: ${uploadedDocument.fileName}`);
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "No fue posible subir el documento.");
    } finally {
      setUploadingRequirementId(null);
      const input = requirementInputRefs.current[requirementId];
      if (input) {
        input.value = "";
      }
    }
  }

  function removeRequirementEvidence(requirementId: string, evidenceId: string) {
    updateWorkflow((previous) => ({
      ...previous,
      requirements: previous.requirements.map((entry) => {
        if (entry.id !== requirementId) {
          return entry;
        }

        const nextEvidences = entry.evidences.filter((evidence) => evidence.id !== evidenceId);
        return {
          ...entry,
          status: entry.status === "completed" && nextEvidences.length === 0 ? "pending" : entry.status,
          evidences: nextEvidences,
        };
      }),
    }));
  }

  async function handleMarkReady() {
    setIsSavingReady(true);
    setErrorMessage(null);
    setMessage(null);

    try {
      const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}/workflow/mark-ready`, {
        method: "POST",
      });
      const payload = (await response.json().catch(() => ({}))) as ApiPayload;
      if (!response.ok || !payload.ok || !payload.proposal) {
        throw new Error(payload.error ?? "No fue posible marcar la propuesta.");
      }

      setProposalStatus(payload.proposal.status);

      updateWorkflow((previous) => ({
        ...previous,
        readyMarked: true,
        step: 6,
      }));
      setMessage("Propuesta marcada como Lista para Envio.");
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "No fue posible marcar la propuesta.");
    } finally {
      setIsSavingReady(false);
    }
  }

  const handleExtractWithAi = useCallback(async (files: File[] | null) => {
    setIsExtractingAi(true);
    setErrorMessage(null);
    setMessage(null);

    try {
      const formData = new FormData();
      if (files && files.length > 0) {
        for (const file of files.slice(0, 3)) {
          formData.append("files", file);
        }
      }
      formData.append("documentType", "BASES_LICITACION");
      if (workflow.info.issuingEntity.trim()) {
        formData.append("issuingEntity", workflow.info.issuingEntity.trim());
      }

      const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}/workflow/extract`, {
        method: "POST",
        body: formData,
      });
      const payload = (await response.json().catch(() => ({}))) as ApiPayload;
      if (!response.ok || !payload.ok || !payload.workflow || !payload.proposal) {
        throw new Error(payload.error ?? "No fue posible extraer requisitos con IA.");
      }

      setWorkflow(payload.workflow);
      setProposalStatus(payload.proposal.status);
      setWorkflowRevision(0);
      setLastExtractionAnalysis(payload.analysis ?? null);
      const bundleSummary =
        payload.analysis?.bundle?.sources && payload.analysis.bundle.sources.length > 1
          ? ` (${payload.analysis.bundle.sources.length} documentos fusionados)`
          : "";
      setMessage(
        payload.analysis?.source === "uploaded_pdf"
          ? `Extraccion IA completada con PDF cargado${bundleSummary}.`
          : `Extraccion IA completada con analisis previo de Modulo 4${bundleSummary}.`,
      );
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "No fue posible extraer requisitos con IA.");
    } finally {
      setIsExtractingAi(false);
      if (aiFileInputRef.current) {
        aiFileInputRef.current.value = "";
      }
    }
  }, [props.proposal.id, workflow.info.issuingEntity]);

  useEffect(() => {
    if (!props.autoExtractOnLoad || !props.normativeContext) {
      return;
    }

    if (!workflowLoaded || isLoadingWorkflow || isExtractingAi || autoExtractAttemptedRef.current) {
      return;
    }

    autoExtractAttemptedRef.current = true;
    void handleExtractWithAi(null);
  }, [handleExtractWithAi, isExtractingAi, isLoadingWorkflow, props.autoExtractOnLoad, props.normativeContext, workflowLoaded]);

  async function handleDownloadPdf(kind: "technical" | "economic" | "summary") {
    setPdfLoadingKind(kind);
    setErrorMessage(null);
    setMessage(null);

    try {
      const response = await fetch(`/api/proposals/${encodeURIComponent(props.proposal.id)}/pdf/${kind}`);
      if (!response.ok) {
        const payload = (await response.json().catch(() => ({}))) as { error?: string };
        throw new Error(payload.error ?? "No fue posible generar el PDF.");
      }

      const blob = await response.blob();
      const downloadUrl = window.URL.createObjectURL(blob);
      const disposition = response.headers.get("content-disposition") ?? "";
      const fileNameMatch = disposition.match(/filename="([^"]+)"/i);
      const fileName = fileNameMatch?.[1] ?? `${kind}.pdf`;

      const anchor = document.createElement("a");
      anchor.href = downloadUrl;
      anchor.download = fileName;
      document.body.appendChild(anchor);
      anchor.click();
      document.body.removeChild(anchor);
      window.URL.revokeObjectURL(downloadUrl);

      setMessage("PDF generado correctamente.");
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "No fue posible generar el PDF.");
    } finally {
      setPdfLoadingKind(null);
    }
  }

  const hasMissingContinuityContext = !props.linkedSource && !props.normativeContext;

  return (
    <div className="space-y-5">
      <section className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <p className="text-sm font-semibold uppercase tracking-[0.08em] text-[#60718f]">Gestion de Licitacion</p>
          <h1 className="text-4xl font-semibold text-[#14274b] [font-family:var(--font-display)]">{workflow.info.title || "Nueva propuesta"}</h1>
          <p className="mt-1 text-base text-[#5f7090]">
            Estado: <span className="font-semibold">{proposalStatus}</span> · {completionPercent}% completado
          </p>
          <p className="text-xs text-[#6a7895]">
            {isLoadingWorkflow ? "Cargando flujo..." : isSyncingWorkflow ? "Guardando cambios..." : lastSavedAt ? `Guardado: ${formatDateTime(lastSavedAt)}` : "Sincronizado"}
          </p>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <LinkButton href="/gestion-licitaciones" label="Volver al listado" />
          {props.linkedSource?.sourceUrl ? <LinkButton href={props.linkedSource.sourceUrl} label="Fuente original" external /> : null}
        </div>
      </section>

      <div className="h-2 w-full overflow-hidden rounded-full bg-[#d7dfec]">
        <div className="h-full bg-[#1f3f84]" style={{ width: `${completionPercent}%` }} />
      </div>

      <ol className="grid gap-2 md:grid-cols-6">
        {STEPS.map((label, index) => {
          const stepNumber = index + 1;
          const isCurrent = workflow.step === stepNumber;
          const isComplete = stepCompletion[index];
          return (
            <li key={label}>
              <button
                type="button"
                className={`w-full rounded-xl border px-2 py-3 text-left transition ${
                  isCurrent
                    ? "border-[#1f3f84] bg-[#eaf1ff]"
                    : isComplete
                      ? "border-[#b9e6cd] bg-[#eaf9f1]"
                      : "border-[#d8e1ef] bg-white"
                }`}
                onClick={() =>
                  updateWorkflow((previous) => ({
                    ...previous,
                    step: stepNumber,
                  }))
                }
              >
                <p className="text-xs font-semibold text-[#627390]">Paso {stepNumber}</p>
                <p className="mt-1 text-sm font-semibold text-[#172a4f]">{label}</p>
              </button>
            </li>
          );
        })}
      </ol>

      {errorMessage ? <p className="rounded-xl border border-[#f1c7ce] bg-[#fff1f4] px-3 py-2 text-sm text-[#b23f50]">{errorMessage}</p> : null}
      {message ? <p className="rounded-xl border border-[#b9e6cd] bg-[#eaf9f1] px-3 py-2 text-sm text-[#1f8b63]">{message}</p> : null}
      {hasMissingContinuityContext ? (
        <p className="rounded-xl border border-[#f0deb0] bg-[#fff8e9] px-3 py-2 text-sm text-[#8d6308]">
          Advertencia de continuidad: esta propuesta no tiene contexto activo de M4, para mantener trazabilidad usa extraccion con PDF o vincula `sourceLicitationId`.
        </p>
      ) : null}
      {lastExtractionAnalysis ? (
        <Card className="border-[#d5e2f5] bg-[#f5f9ff]">
          <CardContent className="space-y-2 p-4 text-sm text-[#35507a]">
            <p className="font-semibold text-[#1d3a67]">Trazabilidad de extraccion (por que este archivo)</p>
            <p>Fuente usada: {lastExtractionAnalysis.source === "uploaded_pdf" ? "PDF cargado" : "Historial M4 vinculado"}.</p>
            {lastExtractionAnalysis.bundle?.sources?.length ? (
              <div className="flex flex-wrap gap-2">
                {lastExtractionAnalysis.bundle.sources.map((source, index) => (
                  <span key={`${source.fileName}-${index}`} className="rounded-full border border-[#c9d9f0] bg-white px-2 py-0.5 text-xs">
                    {source.fileName} ({source.documentType})
                  </span>
                ))}
              </div>
            ) : null}
            {lastExtractionAnalysis.warnings && lastExtractionAnalysis.warnings.length > 0 ? (
              <p className="text-xs text-[#6b7f9f]">Notas: {lastExtractionAnalysis.warnings.slice(0, 2).join(" | ")}</p>
            ) : null}
          </CardContent>
        </Card>
      ) : null}

      {isLoadingWorkflow ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="p-5">
            <p className="text-sm text-[#5f7090]">Cargando informacion del flujo de trabajo...</p>
          </CardContent>
        </Card>
      ) : null}

      {!isLoadingWorkflow && workflow.step === 1 ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="space-y-4 p-5">
            <header className="space-y-1">
              <p className="text-3xl font-semibold text-[#14274b] [font-family:var(--font-display)]">Informacion General de la Licitacion</p>
              <p className="text-sm text-[#5f7090]">Verifica y completa los datos base de la convocatoria.</p>
            </header>

            <div className="grid gap-3 md:grid-cols-2">
              <label className="space-y-1 text-sm font-semibold text-[#33415c] md:col-span-2">
                Titulo de la licitacion
                <input
                  value={workflow.info.title}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, title: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c] md:col-span-2">
                Entidad contratante
                <input
                  value={workflow.info.issuingEntity}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, issuingEntity: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c]">
                Tipo de licitacion
                <input
                  value={workflow.info.procedureType}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, procedureType: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c]">
                Jurisdiccion
                <input
                  value={workflow.info.jurisdiction}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, jurisdiction: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c]">
                Estado
                <input
                  value={workflow.info.state}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, state: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c]">
                Municipio
                <input
                  value={workflow.info.municipality}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, municipality: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c] md:col-span-2">
                Sector
                <input
                  value={workflow.info.sector}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, sector: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c] md:col-span-2">
                Descripcion del objeto
                <textarea
                  value={workflow.info.description}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, description: event.target.value },
                    }))
                  }
                  rows={4}
                  className="w-full rounded-lg border border-[#cfd8e6] px-3 py-2 text-sm"
                />
              </label>

              <label className="space-y-1 text-sm font-semibold text-[#33415c] md:col-span-2">
                URL de convocatoria
                <input
                  value={workflow.info.convocatoriaUrl}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      info: { ...previous.info, convocatoriaUrl: event.target.value },
                    }))
                  }
                  className="h-10 w-full rounded-lg border border-[#cfd8e6] px-3 text-sm"
                />
              </label>
            </div>

            <div className="flex justify-between">
              <Button variant="secondary" onClick={() => updateWorkflow((previous) => ({ ...previous, step: Math.max(1, previous.step - 1) }))}>
                Anterior
              </Button>
              <div className="flex gap-2">
                <Button onClick={() => void handleSaveInfo()} disabled={isSavingInfo}>
                  {isSavingInfo ? "Guardando..." : "Guardar Informacion"}
                </Button>
                <Button
                  onClick={() =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      step: Math.min(6, previous.step + 1),
                    }))
                  }
                >
                  Siguiente
                </Button>
              </div>
            </div>
          </CardContent>
        </Card>
      ) : null}

      {!isLoadingWorkflow && workflow.step === 2 ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="space-y-4 p-5">
            <header className="space-y-1">
              <p className="text-3xl font-semibold text-[#14274b] [font-family:var(--font-display)]">Checklist de Documentacion Requerida</p>
              <p className="text-sm text-[#5f7090]">
                {props.normativeContext
                  ? `Requisitos extraidos con IA (${props.normativeContext.confidence}). Sube evidencia en cada requisito para marcarlo completo.`
                  : "No hay analisis IA vinculado; completa los requisitos manualmente y sube evidencia por requisito."}
              </p>
            </header>

            {props.normativeContext?.executiveSummary ? (
              <p className="rounded-xl border border-[#c6d8f4] bg-[#ebf3ff] px-3 py-2 text-sm text-[#284f88]">{props.normativeContext.executiveSummary}</p>
            ) : null}

            <div className="flex flex-wrap gap-2 rounded-xl border border-[#d8e1ef] bg-[#f8fbff] p-3">
              <Button size="sm" variant="secondary" onClick={() => void handleExtractWithAi(null)} disabled={isExtractingAi}>
                {isExtractingAi ? "Extrayendo..." : "Actualizar requisitos y fechas con IA"}
              </Button>
              <Button size="sm" variant="secondary" onClick={() => aiFileInputRef.current?.click()} disabled={isExtractingAi}>
                {isExtractingAi ? "Procesando..." : "Subir hasta 3 PDFs y extraer con IA"}
              </Button>
              <input
                ref={aiFileInputRef}
                type="file"
                className="hidden"
                accept=".pdf,application/pdf"
                multiple
                onChange={(event) => {
                  const files = event.target.files ? Array.from(event.target.files) : [];
                  void handleExtractWithAi(files.length > 0 ? files : null);
                }}
              />
            </div>

            <section className="space-y-4">
              {groupedRequirements.length === 0 ? (
                <p className="rounded-xl border border-[#f0deb0] bg-[#fff8e9] px-3 py-2 text-sm text-[#8d6308]">
                  Sin requisitos detectados automaticamente. Sube un documento en M4 o agrega controles manuales.
                </p>
              ) : (
                groupedRequirements.map((bucket) => (
                  <div key={bucket.category} className="space-y-2">
                    <p className="text-sm font-semibold uppercase tracking-[0.08em] text-[#60718f]">{categoryLabel(bucket.category)}</p>
                    {bucket.items.map((item) => {
                      const linkedEvidences = item.evidences
                        .map((evidence) => {
                          const linkedDocument = documentsById.get(evidence.documentId);
                          return {
                            ...evidence,
                            fileName: linkedDocument?.fileName ?? evidence.fileName,
                            uploadedAtIso: linkedDocument?.createdAt ?? evidence.uploadedAtIso,
                          };
                        })
                        .filter((evidence) => evidence.fileName.trim().length > 0);
                      const needsEvidence = item.status !== "na" && linkedEvidences.length === 0;
                      const showDropzone = item.status === "pending" || needsEvidence;
                      const isDragging = draggingRequirementId === item.id;
                      const isUploadingThis = uploadingRequirementId === item.id;

                      return (
                        <article key={item.id} className={`rounded-xl border p-3 ${requirementTone(item.status)}`}>
                          <div className="flex flex-wrap items-start justify-between gap-3">
                            <div className="space-y-1">
                              <p className="text-sm font-semibold text-[#1b2f54]">{item.title}</p>
                              <p className="text-xs text-[#5f7090]">{item.description}</p>
                              <p className="text-xs font-semibold text-[#4e6488]">{sourceLabel(item.source)}</p>
                            </div>
                            <div className="min-w-[220px] space-y-2">
                              <select
                                value={item.status}
                                onChange={(event) => {
                                  const value = event.target.value as RequirementStatus;
                                  updateWorkflow((previous) => ({
                                    ...previous,
                                    requirements: previous.requirements.map((entry) =>
                                      entry.id === item.id
                                        ? {
                                            ...entry,
                                            status: value,
                                          }
                                        : entry,
                                    ),
                                  }));
                                }}
                                className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2 text-sm"
                              >
                                <option value="pending">Pendiente</option>
                                <option value="completed">Completo</option>
                                <option value="na">No aplica</option>
                              </select>
                              <input
                                value={item.note}
                                onChange={(event) =>
                                  updateWorkflow((previous) => ({
                                    ...previous,
                                    requirements: previous.requirements.map((entry) =>
                                      entry.id === item.id
                                        ? {
                                            ...entry,
                                            note: event.target.value,
                                          }
                                        : entry,
                                    ),
                                  }))
                                }
                                className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2 text-xs"
                                placeholder={item.status === "na" ? "Motivo de no aplica" : "Nota opcional"}
                              />
                            </div>
                          </div>

                          <div className="mt-3 space-y-2">
                            {linkedEvidences.length === 0 ? (
                              <p className="text-xs font-semibold text-[#8d6308]">Sin evidencia adjunta para este requisito.</p>
                            ) : (
                              <ul className="space-y-2">
                                {linkedEvidences.map((evidence) => (
                                  <li key={evidence.id} className="flex items-center justify-between gap-2 rounded-lg border border-[#d8e2ef] bg-white px-3 py-2 text-xs">
                                    <div>
                                      <p className="font-semibold text-[#1b2f54]">{evidence.fileName}</p>
                                      <p className="text-[#627391]">{formatDateTime(evidence.uploadedAtIso)}</p>
                                    </div>
                                    <button
                                      type="button"
                                      className="font-semibold text-[#b23f50]"
                                      onClick={() => {
                                        removeRequirementEvidence(item.id, evidence.id);
                                      }}
                                    >
                                      Quitar
                                    </button>
                                  </li>
                                ))}
                              </ul>
                            )}

                            <div
                              className={`rounded-xl border-2 border-dashed px-3 py-3 transition ${
                                isDragging
                                  ? "border-[#1f3f84] bg-[#ebf3ff]"
                                  : showDropzone
                                    ? "border-[#93a9d4] bg-[#f4f8ff]"
                                    : "border-[#d8e1ef] bg-[#fbfdff]"
                              }`}
                              onDragOver={(event) => {
                                event.preventDefault();
                                setDraggingRequirementId(item.id);
                              }}
                              onDragLeave={() => {
                                setDraggingRequirementId((previous) => (previous === item.id ? null : previous));
                              }}
                              onDrop={(event) => {
                                event.preventDefault();
                                setDraggingRequirementId(null);
                                const droppedFile = event.dataTransfer.files?.[0] ?? null;
                                void handleRequirementUpload(item.id, droppedFile);
                              }}
                            >
                              <p className="text-xs font-semibold text-[#33415c]">
                                {showDropzone
                                  ? "Archivo pendiente: arrastra aqui o usa el boton para subir evidencia de este requisito."
                                  : "Puedes adjuntar evidencia adicional para este requisito."}
                              </p>
                              <div className="mt-2 flex flex-wrap items-center gap-2">
                                <Button
                                  size="sm"
                                  onClick={() => requirementInputRefs.current[item.id]?.click()}
                                  disabled={uploadingRequirementId !== null && uploadingRequirementId !== item.id}
                                >
                                  {isUploadingThis ? "Subiendo..." : showDropzone ? "Subir archivo pendiente" : "Agregar otro archivo"}
                                </Button>
                                <input
                                  ref={(node) => {
                                    requirementInputRefs.current[item.id] = node;
                                  }}
                                  type="file"
                                  className="hidden"
                                  accept=".pdf,.doc,.docx,.xlsx,.jpg,.jpeg,.png"
                                  onChange={(event) => {
                                    const file = event.target.files?.[0] ?? null;
                                    void handleRequirementUpload(item.id, file);
                                  }}
                                />
                                {showDropzone ? <p className="text-xs text-[#627391]">Tambien puedes usar drag & drop.</p> : null}
                              </div>
                            </div>
                          </div>
                        </article>
                      );
                    })}
                  </div>
                ))
              )}
            </section>

            <div className="flex justify-between">
              <Button variant="secondary" onClick={() => updateWorkflow((previous) => ({ ...previous, step: 1 }))}>
                Anterior
              </Button>
              <Button onClick={() => updateWorkflow((previous) => ({ ...previous, step: 3 }))}>Siguiente</Button>
            </div>
          </CardContent>
        </Card>
      ) : null}

      {!isLoadingWorkflow && workflow.step === 3 ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="space-y-4 p-5">
            <header className="space-y-1">
              <p className="text-3xl font-semibold text-[#14274b] [font-family:var(--font-display)]">Generador de Propuesta Tecnica</p>
              <p className="text-sm text-[#5f7090]">
                {workflow.technicalSections.filter((item) => item.completed).length} de {workflow.technicalSections.length} secciones completadas
              </p>
            </header>

            <div className="space-y-2">
              {workflow.technicalSections.map((section) => (
                <article key={section.id} className="rounded-xl border border-[#d8e1ef] bg-white p-3">
                  <div className="flex flex-wrap items-center justify-between gap-2">
                    <div>
                      <p className="text-sm font-semibold text-[#1b2f54]">{section.title}</p>
                      <p className="text-xs text-[#5f7090]">{section.description}</p>
                    </div>
                    <label className="inline-flex items-center gap-2 text-sm font-semibold text-[#33415c]">
                      <input
                        type="checkbox"
                        checked={section.completed}
                        onChange={(event) =>
                          updateWorkflow((previous) => ({
                            ...previous,
                            technicalSections: previous.technicalSections.map((item) =>
                              item.id === section.id
                                ? {
                                    ...item,
                                    completed: event.target.checked,
                                  }
                                : item,
                            ),
                          }))
                        }
                      />
                      {section.completed ? "Completada" : "Pendiente"}
                    </label>
                  </div>
                </article>
              ))}
            </div>

            <div className="rounded-xl border border-[#d8e1ef] bg-[#f8fbff] p-3">
              <p className="text-sm font-semibold text-[#223a64]">Agregar nueva seccion</p>
              <div className="mt-2 flex flex-wrap gap-2">
                <input
                  value={newSectionTitle}
                  onChange={(event) => setNewSectionTitle(event.target.value)}
                  className="h-10 min-w-[220px] flex-1 rounded-lg border border-[#cfd8e6] px-3 text-sm"
                  placeholder="Titulo de la seccion"
                />
                <Button
                  onClick={() => {
                    const title = newSectionTitle.trim();
                    if (!title) {
                      return;
                    }

                    updateWorkflow((previous) => ({
                      ...previous,
                      technicalSections: [
                        ...previous.technicalSections,
                        {
                          id: newId("section"),
                          title,
                          description: "Seccion agregada manualmente.",
                          completed: false,
                        },
                      ],
                    }));
                    setNewSectionTitle("");
                  }}
                >
                  Agregar
                </Button>
                <Button variant="secondary" onClick={() => void handleDownloadPdf("technical")} disabled={pdfLoadingKind !== null}>
                  {pdfLoadingKind === "technical" ? "Generando..." : "Generar PDF Propuesta Tecnica"}
                </Button>
              </div>
            </div>

            <div className="flex justify-between">
              <Button variant="secondary" onClick={() => updateWorkflow((previous) => ({ ...previous, step: 2 }))}>
                Anterior
              </Button>
              <Button onClick={() => updateWorkflow((previous) => ({ ...previous, step: 4 }))}>Siguiente</Button>
            </div>
          </CardContent>
        </Card>
      ) : null}

      {!isLoadingWorkflow && workflow.step === 4 ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="space-y-4 p-5">
            <header className="space-y-1">
              <p className="text-3xl font-semibold text-[#14274b] [font-family:var(--font-display)]">Generador de Propuesta Economica</p>
              <p className="text-sm text-[#5f7090]">El sistema calcula subtotal, IVA y total automaticamente.</p>
            </header>

            <div className="overflow-x-auto rounded-xl border border-[#d8e1ef] bg-white">
              <table className="min-w-full text-sm">
                <thead className="bg-[#f4f7fc] text-left text-[#33415c]">
                  <tr>
                    <th className="px-3 py-2">Concepto</th>
                    <th className="px-3 py-2">Unidad</th>
                    <th className="px-3 py-2">Cantidad</th>
                    <th className="px-3 py-2">P. Unitario</th>
                    <th className="px-3 py-2">Subtotal</th>
                    <th className="px-3 py-2" />
                  </tr>
                </thead>
                <tbody>
                  {workflow.economicItems.map((item) => {
                    const lineTotal = item.quantity * item.unitPrice;
                    return (
                      <tr key={item.id} className="border-t border-[#e4eaf4]">
                        <td className="px-3 py-2">
                          <input
                            value={item.concept}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                economicItems: previous.economicItems.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        concept: event.target.value,
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2"
                          />
                        </td>
                        <td className="px-3 py-2">
                          <input
                            value={item.unit}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                economicItems: previous.economicItems.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        unit: event.target.value,
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2"
                          />
                        </td>
                        <td className="px-3 py-2">
                          <input
                            type="number"
                            min={0}
                            value={item.quantity}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                economicItems: previous.economicItems.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        quantity: Number(event.target.value),
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2"
                          />
                        </td>
                        <td className="px-3 py-2">
                          <input
                            type="number"
                            min={0}
                            value={item.unitPrice}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                economicItems: previous.economicItems.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        unitPrice: Number(event.target.value),
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2"
                          />
                        </td>
                        <td className="px-3 py-2 font-semibold text-[#20345a]">{formatCurrency(lineTotal)}</td>
                        <td className="px-3 py-2 text-right">
                          <button
                            type="button"
                            className="text-xs font-semibold text-[#b23f50]"
                            onClick={() =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                economicItems: previous.economicItems.filter((entry) => entry.id !== item.id),
                              }))
                            }
                          >
                            Eliminar
                          </button>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>

            <div className="rounded-xl border border-[#d8e1ef] bg-[#f8fbff] p-3">
              <p className="text-sm font-semibold text-[#223a64]">Agregar concepto</p>
              <div className="mt-2 grid gap-2 md:grid-cols-4">
                <input
                  value={newConcept.concept}
                  onChange={(event) => setNewConcept((previous) => ({ ...previous, concept: event.target.value }))}
                  className="h-10 rounded-lg border border-[#cfd8e6] px-3 text-sm md:col-span-2"
                  placeholder="Descripcion del bien o servicio"
                />
                <input
                  value={newConcept.unit}
                  onChange={(event) => setNewConcept((previous) => ({ ...previous, unit: event.target.value }))}
                  className="h-10 rounded-lg border border-[#cfd8e6] px-3 text-sm"
                  placeholder="Unidad"
                />
                <input
                  type="number"
                  min={1}
                  value={newConcept.quantity}
                  onChange={(event) => setNewConcept((previous) => ({ ...previous, quantity: Number(event.target.value) }))}
                  className="h-10 rounded-lg border border-[#cfd8e6] px-3 text-sm"
                  placeholder="Cantidad"
                />
                <input
                  type="number"
                  min={0}
                  value={newConcept.unitPrice}
                  onChange={(event) => setNewConcept((previous) => ({ ...previous, unitPrice: Number(event.target.value) }))}
                  className="h-10 rounded-lg border border-[#cfd8e6] px-3 text-sm md:col-span-3"
                  placeholder="Precio unitario (MXN)"
                />
                <Button
                  onClick={() => {
                    if (!newConcept.concept.trim()) {
                      return;
                    }

                    updateWorkflow((previous) => ({
                      ...previous,
                      economicItems: [
                        ...previous.economicItems,
                        {
                          id: newId("economic"),
                          concept: newConcept.concept.trim(),
                          unit: newConcept.unit.trim() || "pieza",
                          quantity: Math.max(1, Math.round(newConcept.quantity)),
                          unitPrice: Math.max(0, newConcept.unitPrice),
                        },
                      ],
                    }));
                    setNewConcept({
                      concept: "",
                      unit: "pieza",
                      quantity: 1,
                      unitPrice: 0,
                    });
                  }}
                >
                  Agregar
                </Button>
              </div>
            </div>

            <div className="rounded-xl border border-[#d8e1ef] bg-white p-3 text-sm">
              <p className="flex items-center justify-between">
                <span>Subtotal</span>
                <span className="font-semibold">{formatCurrency(economicTotals.subtotal)}</span>
              </p>
              <p className="mt-1 flex items-center justify-between">
                <span>IVA (16%)</span>
                <span className="font-semibold">{formatCurrency(economicTotals.iva)}</span>
              </p>
              <p className="mt-2 flex items-center justify-between text-lg font-semibold text-[#1b2f54]">
                <span>Total</span>
                <span>{formatCurrency(economicTotals.total)}</span>
              </p>
            </div>

            <div className="flex justify-between">
              <Button variant="secondary" onClick={() => updateWorkflow((previous) => ({ ...previous, step: 3 }))}>
                Anterior
              </Button>
              <div className="flex gap-2">
                <Button variant="secondary" onClick={() => void handleDownloadPdf("economic")} disabled={pdfLoadingKind !== null}>
                  {pdfLoadingKind === "economic" ? "Generando..." : "Generar PDF Propuesta Economica"}
                </Button>
                <Button onClick={() => updateWorkflow((previous) => ({ ...previous, step: 5 }))}>Siguiente</Button>
              </div>
            </div>
          </CardContent>
        </Card>
      ) : null}

      {!isLoadingWorkflow && workflow.step === 5 ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="space-y-4 p-5">
            <header className="space-y-1">
              <p className="text-3xl font-semibold text-[#14274b] [font-family:var(--font-display)]">Checklist Final de Validacion</p>
              <p className="text-sm text-[#5f7090]">Solo cuando todo este completo podras marcar la propuesta como lista para envio.</p>
            </header>

            <div className="rounded-xl border border-[#d8e1ef] bg-[#f8fbff] p-3 text-sm text-[#324669]">
              <p>
                Requisitos obligatorios: <span className="font-semibold">{gate.resolvedCount}</span> / <span className="font-semibold">{gate.mandatoryCount}</span>
              </p>
              <p>Secciones tecnicas completas: {gate.technicalReady ? "Si" : "No"}</p>
              <p>Propuesta economica completa: {gate.economicReady ? "Si" : "No"}</p>
              <p>Fechas cargadas: {gate.datesReady ? "Si" : "No"}</p>
              <p>Firma electronica validada: {gate.signatureReady ? "Si" : "No"}</p>
            </div>

            <section className="space-y-2">
              {workflow.requirements.map((item) => {
                const resolved = isRequirementResolved(item);
                const evidenceCount = item.evidences.length;
                return (
                  <div key={item.id} className="flex items-center justify-between rounded-lg border border-[#d8e1ef] bg-white px-3 py-2 text-sm">
                    <p className={!resolved ? "text-[#1b2f54]" : "text-[#5f7090]"}>{item.title}</p>
                    <span className={`font-semibold ${resolved ? "text-[#1f8b63]" : "text-[#b23f50]"}`}>
                      {resolved ? `${toStatusLabel(item.status)} · ${item.status === "na" ? "Sin archivo" : `${evidenceCount} archivo(s)`}` : "Pendiente de archivo"}
                    </span>
                  </div>
                );
              })}
            </section>

            <section className="rounded-xl border border-[#d8e1ef] bg-white p-3">
              <div className="flex flex-wrap items-start justify-between gap-3">
                <div>
                  <p className="text-base font-semibold text-[#1b2f54]">Cumplimiento de firma electronica</p>
                  <p className="text-sm text-[#5f7090]">{workflow.signatureCompliance.policyName}</p>
                  <p className="text-xs text-[#627391]">{workflow.signatureCompliance.jurisdictionLabel}</p>
                </div>
                <span className={`inline-flex rounded-full border px-3 py-1 text-sm font-semibold ${getSignaturePolicyTone(workflow.signatureCompliance.policyStatus)}`}>
                  {getSignaturePolicyStatusLabel(workflow.signatureCompliance.policyStatus)}
                </span>
              </div>

              {workflow.signatureCompliance.minimumEvidence.length > 0 ? (
                <ul className="mt-3 space-y-1 text-sm text-[#4f6588]">
                  {workflow.signatureCompliance.minimumEvidence.map((item, index) => (
                    <li key={`${item}-${index}`} className="rounded-lg border border-[#e1e8f3] bg-[#f8fbff] px-3 py-2">
                      {item}
                    </li>
                  ))}
                </ul>
              ) : (
                <p className="mt-3 text-sm text-[#5f7090]">No hay evidencia minima configurada.</p>
              )}

              {workflow.signatureCompliance.notes ? <p className="mt-3 text-sm text-[#5f7090]">{workflow.signatureCompliance.notes}</p> : null}
              {workflow.signatureCompliance.sourceUrl ? (
                <a href={workflow.signatureCompliance.sourceUrl} target="_blank" rel="noreferrer" className="mt-2 inline-flex text-sm font-semibold text-[#1f3f84]">
                  Ver fuente normativa
                </a>
              ) : null}

              <label className="mt-3 inline-flex items-center gap-2 text-sm font-semibold text-[#33415c]">
                <input
                  type="checkbox"
                  checked={workflow.signatureCompliance.validatedByLegal}
                  onChange={(event) =>
                    updateWorkflow((previous) => ({
                      ...previous,
                      signatureCompliance: {
                        ...previous.signatureCompliance,
                        validatedByLegal: event.target.checked,
                      },
                    }))
                  }
                />
                Validacion legal realizada (si aplica)
              </label>
            </section>

            <div className="rounded-xl border border-[#d8e1ef] bg-white p-3">
              <div className="flex flex-wrap items-center justify-between gap-3">
                <div>
                  <p className="text-base font-semibold text-[#1b2f54]">{gate.allReady ? "Propuesta lista para envio" : "Completa los pendientes para continuar"}</p>
                  <p className="text-sm text-[#5f7090]">{workflow.readyMarked ? "Marcada como lista para envio." : "El marcado aplica validacion estricta (100%)."}</p>
                </div>
                <div className="flex flex-wrap gap-2">
                  <Button variant="secondary" onClick={() => void handleDownloadPdf("summary")} disabled={pdfLoadingKind !== null}>
                    {pdfLoadingKind === "summary" ? "Generando..." : "Imprimir Resumen"}
                  </Button>
                  <Button onClick={() => void handleMarkReady()} disabled={!gate.allReady || isSavingReady}>
                    {isSavingReady ? "Validando..." : "Marcar como Lista para Envio"}
                  </Button>
                </div>
              </div>
            </div>

            <div className="flex justify-between">
              <Button variant="secondary" onClick={() => updateWorkflow((previous) => ({ ...previous, step: 4 }))}>
                Anterior
              </Button>
              <Button onClick={() => updateWorkflow((previous) => ({ ...previous, step: 6 }))}>Siguiente</Button>
            </div>
          </CardContent>
        </Card>
      ) : null}

      {!isLoadingWorkflow && workflow.step === 6 ? (
        <Card className="border-[#d8e1ef]">
          <CardContent className="space-y-4 p-5">
            <header className="space-y-1">
              <p className="text-3xl font-semibold text-[#14274b] [font-family:var(--font-display)]">Fechas Importantes del Proceso</p>
              <p className="text-sm text-[#5f7090]">Fechas extraidas automaticamente por IA y por la fuente oficial. Revisa la linea de tiempo para saber que hacer y cuando.</p>
            </header>

            <div className="flex flex-wrap gap-2 rounded-xl border border-[#d8e1ef] bg-[#f8fbff] p-3">
              <Button size="sm" variant="secondary" onClick={() => void handleExtractWithAi(null)} disabled={isExtractingAi}>
                {isExtractingAi ? "Actualizando..." : "Actualizar fechas con IA"}
              </Button>
              <Button size="sm" variant="secondary" onClick={() => aiFileInputRef.current?.click()} disabled={isExtractingAi}>
                {isExtractingAi ? "Procesando..." : "Subir hasta 3 PDFs para actualizar fechas"}
              </Button>
              <input
                ref={aiFileInputRef}
                type="file"
                className="hidden"
                accept=".pdf,application/pdf"
                multiple
                onChange={(event) => {
                  const files = event.target.files ? Array.from(event.target.files) : [];
                  void handleExtractWithAi(files.length > 0 ? files : null);
                }}
              />
            </div>

            {sortedMilestones.length === 0 ? (
              <p className="rounded-xl border border-[#f0deb0] bg-[#fff8e9] px-3 py-2 text-sm text-[#8d6308]">Aun no hay fechas cargadas.</p>
            ) : (
              <div className="relative space-y-3 pl-7">
                <span className="pointer-events-none absolute bottom-0 left-3 top-0 w-px bg-[#d8e1ef]" />
                {sortedMilestones.map((item) => {
                  const timelineTone = getMilestoneTimelineTone(item.dateIso);
                  return (
                    <article key={item.id} className="relative rounded-xl border border-[#d8e1ef] bg-white p-3">
                      <span className={`absolute -left-[22px] top-5 h-4 w-4 rounded-full border-2 border-white ${timelineTone.dot}`} />
                      <div className="flex flex-wrap items-start justify-between gap-2">
                        <div>
                          <p className="text-sm font-semibold text-[#1b2f54]">{item.title}</p>
                          <p className="text-xs text-[#5f7090]">{formatDateTime(item.dateIso)}</p>
                        </div>
                        <div className="flex flex-wrap gap-2">
                          <span className={`rounded-full border px-2 py-0.5 text-[11px] font-semibold ${timelineTone.badge}`}>{timelineTone.label}</span>
                          <span className="rounded-full border border-[#d8e1ef] bg-[#f8fbff] px-2 py-0.5 text-[11px] font-semibold text-[#5f7090]">
                            {milestoneSourceLabel(item.source)}
                          </span>
                        </div>
                      </div>

                      {item.note ? <p className="mt-2 text-xs text-[#4e6488]">{item.note}</p> : null}

                      <div className="mt-3 grid gap-2 md:grid-cols-2">
                        <label className="space-y-1 text-xs font-semibold text-[#33415c] md:col-span-2">
                          Evento
                          <input
                            value={item.title}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                milestones: previous.milestones.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        title: event.target.value,
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2 text-sm"
                          />
                        </label>
                        <label className="space-y-1 text-xs font-semibold text-[#33415c]">
                          Fecha y hora
                          <input
                            type="datetime-local"
                            value={isoToLocalInput(item.dateIso)}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                milestones: previous.milestones.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        dateIso: localInputToIso(event.target.value),
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2 text-sm"
                          />
                        </label>
                        <label className="space-y-1 text-xs font-semibold text-[#33415c]">
                          Ubicacion
                          <input
                            value={item.location}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                milestones: previous.milestones.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        location: event.target.value,
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2 text-sm"
                          />
                        </label>
                        <label className="space-y-1 text-xs font-semibold text-[#33415c] md:col-span-2">
                          Nota
                          <input
                            value={item.note}
                            onChange={(event) =>
                              updateWorkflow((previous) => ({
                                ...previous,
                                milestones: previous.milestones.map((entry) =>
                                  entry.id === item.id
                                    ? {
                                        ...entry,
                                        note: event.target.value,
                                      }
                                    : entry,
                                ),
                              }))
                            }
                            className="h-9 w-full rounded-lg border border-[#cfd8e6] px-2 text-sm"
                          />
                        </label>
                      </div>
                      <div className="mt-2 flex items-center justify-end text-xs">
                        <button
                          type="button"
                          className="font-semibold text-[#b23f50]"
                          onClick={() =>
                            updateWorkflow((previous) => ({
                              ...previous,
                              milestones: previous.milestones.filter((entry) => entry.id !== item.id),
                            }))
                          }
                        >
                          Eliminar
                        </button>
                      </div>
                    </article>
                  );
                })}
              </div>
            )}

            <div className="rounded-xl border border-[#d8e1ef] bg-[#f8fbff] p-3">
              <p className="text-sm font-semibold text-[#223a64]">Agregar fecha</p>
              <div className="mt-2 flex flex-wrap gap-2">
                <input
                  value={newMilestoneTitle}
                  onChange={(event) => setNewMilestoneTitle(event.target.value)}
                  className="h-10 min-w-[220px] flex-1 rounded-lg border border-[#cfd8e6] px-3 text-sm"
                  placeholder="Nombre del evento"
                />
                <Button
                  onClick={() => {
                    const title = newMilestoneTitle.trim();
                    if (!title) {
                      return;
                    }

                    updateWorkflow((previous) => ({
                      ...previous,
                      milestones: [
                        ...previous.milestones,
                        {
                          id: newId("milestone"),
                          title,
                          dateIso: null,
                          location: "",
                          note: "",
                          source: "manual",
                        },
                      ],
                    }));
                    setNewMilestoneTitle("");
                  }}
                >
                  Agregar Fecha
                </Button>
              </div>
            </div>

            {props.linkedSource?.documentLinks.length ? (
              <section className="space-y-2">
                <p className="text-sm font-semibold uppercase tracking-[0.08em] text-[#60718f]">Documentos de la convocatoria</p>
                <div className="grid gap-2 md:grid-cols-2">
                  {props.linkedSource.documentLinks.map((item, index) => (
                    <a
                      key={`${item.url}-${index}`}
                      href={item.url}
                      target="_blank"
                      rel="noreferrer"
                      className="rounded-xl border border-[#d8e1ef] bg-white px-3 py-2 text-sm font-semibold text-[#1f3f84]"
                    >
                      {item.name}
                    </a>
                  ))}
                </div>
              </section>
            ) : null}

            <div className="flex justify-between">
              <Button variant="secondary" onClick={() => updateWorkflow((previous) => ({ ...previous, step: 5 }))}>
                Anterior
              </Button>
              <Button onClick={() => updateWorkflow((previous) => ({ ...previous, step: 1 }))}>Volver a inicio</Button>
            </div>
          </CardContent>
        </Card>
      ) : null}
    </div>
  );
}

function LinkButton({ href, label, external }: { href: string; label: string; external?: boolean }) {
  if (external) {
    return (
      <a href={href} target="_blank" rel="noreferrer" className="inline-flex h-10 items-center rounded-lg border border-[#ccd6e5] px-3 text-sm font-semibold text-[#334a73] hover:bg-white">
        {label}
      </a>
    );
  }

  return (
    <Link href={href} className="inline-flex h-10 items-center rounded-lg border border-[#ccd6e5] px-3 text-sm font-semibold text-[#334a73] hover:bg-white">
      {label}
    </Link>
  );
}
