"use client";

import { useConfirm } from "@/components/confirm-provider";
import {
  DashboardEmptyState,
  DashboardSection,
} from "@/components/dashboard-page";
import { usePrompt } from "@/components/prompt-provider";
import { DataRefreshControl } from "@/components/data-refresh-control";
import { useAuth } from "@/components/providers";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { ErrorState } from "@/components/ui/error-state";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { SkeletonDetailHeader, SkeletonTable } from "@/components/ui/skeleton";
import { useFlagsConfiguracion } from "@/hooks/use-flags-configuracion";
import { useToast } from "@/hooks/use-toast";
import { cotizacionesApi, otsApi, productosApi, whatsappApi } from "@/lib/api";
import { db } from "@/lib/db";
import {
  getLocalOtByRouteId,
  putRemoteOtIfNewer,
  setLocalOtCotizacion,
} from "@/lib/offline-ots";
import { OT_DETAIL_REFRESH_INTERVAL_MS } from "@/lib/ot-detail";
import {
  cacheRemoteProductos,
  searchLocalProductos,
} from "@/lib/offline-productos";
import { formatCurrency, formatDate, formatDateTime } from "@/lib/utils";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  AlertTriangle,
  ArrowLeft,
  CheckCircle2,
  ChevronLeft,
  ChevronRight,
  Copy,
  History,
  Lock,
  Loader2,
  MessageCircle,
  PackageSearch,
  Plus,
  Printer,
  Receipt,
  Save,
  Search,
  Send,
  Trash2,
  WifiOff,
  Wrench,
} from "lucide-react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useMemo, useState } from "react";

const EMPTY_LINEAS: any[] = [];

type SearchMode = "taller" | "servicios" | "todos";

function getLineTaxRate(linea: any) {
  const subtotal = Number(linea?.subtotal || 0);
  const iva = Number(linea?.iva || 0);
  return subtotal > 0 ? iva / subtotal : 0;
}

function getLineUnitTotal(linea: any) {
  const cantidad = Number(linea?.cantidad || 0);
  if (cantidad > 0) {
    return Number(linea?.total || 0) / cantidad;
  }

  return Number(linea?.precioUnitario || 0) * (1 + getLineTaxRate(linea));
}

async function refreshOtAndCotizacion(routeId: string) {
  const numericId = Number(routeId);

  if (Number.isFinite(numericId) && numericId > 0 && navigator.onLine) {
    try {
      const remoteOt = await otsApi.get(numericId);
      await putRemoteOtIfNewer(remoteOt);
    } catch (error) {
      console.warn("Using local OT cache for cotizacion", error);
    }
  }

  const ot = await getLocalOtByRouteId(routeId);
  if (!ot) return null;

  if (ot.serverId && navigator.onLine) {
    try {
      const remoteCotizacion = await cotizacionesApi.getByOt(
        Number(ot.serverId),
      );
      if (remoteCotizacion) {
        await setLocalOtCotizacion(Number(ot.serverId), remoteCotizacion);
      }
    } catch (error) {
      console.warn("Using local cotizacion cache", error);
    }
  }

  const freshOt = await getLocalOtByRouteId(routeId);
  const cliente = freshOt?.clienteTarjeta
    ? await db.clientes.where("tarjeta").equals(freshOt.clienteTarjeta).first()
    : null;

  return { ot: freshOt, cliente };
}

export default function CotizacionPage() {
  const confirm = useConfirm();
  const prompt = usePrompt();
  const params = useParams();
  const router = useRouter();
  const { toast } = useToast();
  const { canRead, canWrite } = useAuth();
  const canAddProductoLibre = canWrite("productoLibre");
  const queryClient = useQueryClient();
  const routeId = String(params.id);
  const [productSearch, setProductSearch] = useState("");
  const [cantidad, setCantidad] = useState("1");
  const [lineaCantidades, setLineaCantidades] = useState<
    Record<number, string>
  >({});
  const [lineaPrecios, setLineaPrecios] = useState<Record<number, string>>({});
  const [cotizacionLock, setCotizacionLock] = useState<any>(null);
  const [lockError, setLockError] = useState("");
  const [searchMode, setSearchMode] = useState<SearchMode>("taller");
  const [productPage, setProductPage] = useState(1);
  const [productPageSize, setProductPageSize] = useState(5);
  const [manualDescripcion, setManualDescripcion] = useState("");
  const [manualPrecio, setManualPrecio] = useState("0");
  const [manualEsServicio, setManualEsServicio] = useState(false);
  const flags = useFlagsConfiguracion();
  const canViewLogs = canRead("logs");

  const { data, dataUpdatedAt, isFetching, isLoading, isError, refetch } =
    useQuery({
      queryKey: ["cotizacion", "ot", routeId],
      queryFn: () => refreshOtAndCotizacion(routeId),
      enabled: !!routeId,
      refetchInterval: OT_DETAIL_REFRESH_INTERVAL_MS,
      refetchOnReconnect: true,
      refetchOnWindowFocus: true,
    });

  const ot = data?.ot || null;
  const { data: eventos = [] } = useQuery({
    queryKey: ["ots", "eventos", routeId],
    queryFn: () => otsApi.getEventos(Number(ot?.serverId)),
    enabled: canViewLogs && flags.usaBitacora && Boolean(ot?.serverId) && navigator.onLine,
    refetchInterval: OT_DETAIL_REFRESH_INTERVAL_MS,
    refetchOnReconnect: true,
    refetchOnWindowFocus: true,
  });
  const cliente = data?.cliente || null;
  const cotizacion = ot?.cotizaciones?.[0] || null;
  const { data: cotizacionVersiones = [] } = useQuery({
    queryKey: ["cotizacion", "versions", cotizacion?.id],
    queryFn: () => cotizacionesApi.versions(Number(cotizacion?.id)),
    enabled: canViewLogs && Boolean(cotizacion?.id) && navigator.onLine,
  });
  const lineas = cotizacion?.lineas ?? EMPTY_LINEAS;
  const servicios = lineas.filter((l: any) => l.esServicio);
  const repuestos = lineas.filter((l: any) => !l.esServicio);
  const lineasKey = lineas
    .map((linea: any) => `${linea.id}:${linea.cantidad}`)
    .join("|");
  const lineasPrecioKey = lineas
    .map((linea: any) => `${linea.id}:${linea.precioUnitario}`)
    .join("|");
  const totalLineas = lineas.length;
  const cotizacionEventos = eventos.filter((evento: any) =>
    `${evento.tipo || ""} ${evento.descripcion || ""}`
      .toLowerCase()
      .includes("cotizaci"),
  );
  const totalUnidades = lineas.reduce(
    (sum: number, item: any) => sum + Number(item.cantidad || 0),
    0,
  );
  const cantidadNumerica = Number(cantidad);
  const cantidadValida =
    Number.isFinite(cantidadNumerica) && cantidadNumerica > 0;
  const canWriteCotizacion =
    Number.isFinite(Number(ot?.serverId)) && navigator.onLine;

  const usaWhatsappCotizacion = flags.usaWhatsapp && flags.usaLinkPublicoCotizacion;
  const cotizacionAprobada = cotizacion?.estado === "aprobada";
  const cotizacionRechazada = cotizacion?.estado === "rechazada";
  const cotizacionEnviada = cotizacion?.estado === "enviada";
  const cotizacionCerrada = cotizacionAprobada;
  const lineasBloqueadas = cotizacionAprobada || cotizacionEnviada;
  const cotizacionId = Number(cotizacion?.id || 0);
  const lockToken = String(cotizacionLock?.token || "");
  const needsLock = Boolean(
    cotizacionId && canWriteCotizacion && !cotizacionCerrada,
  );
  const canEditCotizacion =
    canWriteCotizacion &&
    !cotizacionCerrada &&
    (!cotizacionId || Boolean(lockToken));
  const canEditLineas = canEditCotizacion && !cotizacionEnviada;
  const canViewCotizacionAudit = canViewLogs;
  const cotizacionEstadoLabel = !cotizacion
    ? "Sin cotización"
    : cotizacion.estado === "borrador"
      ? "Cuenta abierta"
      : cotizacion.estado === "aprobada"
        ? "Aprobada"
        : cotizacion.estado === "rechazada"
          ? "Rechazada"
          : cotizacion.estado || "Borrador";

  const filtroProductos = useMemo(() => {
    if (searchMode === "servicios") {
      return { esServicio: true };
    }

    if (searchMode === "taller") {
      return { esServicio: false, soloTaller: true };
    }

    return {};
  }, [searchMode]);

  useEffect(() => {
    if (!lineas.length) {
      setLineaCantidades({});
      setLineaPrecios({});
      return;
    }

    setLineaCantidades(
      Object.fromEntries(
        lineas.map((linea: any) => [
          Number(linea.id),
          String(Number(linea.cantidad || 1)),
        ]),
      ),
    );
    setLineaPrecios(
      Object.fromEntries(
        lineas.map((linea: any) => [
          Number(linea.id),
          String(Number(getLineUnitTotal(linea).toFixed(2))),
        ]),
      ),
    );
  }, [cotizacion?.id, lineas, lineasKey, lineasPrecioKey, totalLineas]);

  const { data: productos = [], isFetching: searchingProducts } = useQuery({
    queryKey: ["productos", "search", productSearch, searchMode],
    queryFn: async () => {
      const term = productSearch.trim();

      if (navigator.onLine) {
        try {
          const remote = term
            ? await productosApi.search(term, 50, filtroProductos)
            : await productosApi.getTop(50, filtroProductos);
          await cacheRemoteProductos(remote || []);
          return remote || [];
        } catch (error) {
          console.warn("Using local product cache", error);
        }
      }

      return searchLocalProductos(term, 50, filtroProductos);
    },
    enabled: Boolean(ot),
  });

  const totalProductPages = Math.max(
    1,
    Math.ceil(productos.length / productPageSize),
  );
  const visibleProductos = productos.slice(
    (productPage - 1) * productPageSize,
    productPage * productPageSize,
  );

  useEffect(() => {
    setProductPage(1);
  }, [productSearch, searchMode, productPageSize]);

  useEffect(() => {
    if (productPage > totalProductPages) {
      setProductPage(totalProductPages);
    }
  }, [productPage, totalProductPages]);

  const ensureCotizacion = async () => {
    if (!ot?.serverId) {
      throw new Error("La OT aún no está sincronizada con el servidor.");
    }

    if (cotizacion?.id) {
      return cotizacion;
    }

    const created = await cotizacionesApi.create({ otId: Number(ot.serverId) });
    await setLocalOtCotizacion(Number(ot.serverId), created);
    return created;
  };

  const refreshCotizacionCache = async () => {
    if (!ot?.serverId) return;
    const refreshed = await cotizacionesApi.getByOt(Number(ot.serverId));
    await setLocalOtCotizacion(Number(ot.serverId), refreshed);
  };

  const ensureCotizacionLock = async (cotId: number) => {
    if (lockToken) return lockToken;
    const acquired = await cotizacionesApi.acquireLock(cotId);
    setCotizacionLock(acquired);
    setLockError("");
    return String(acquired.token || "");
  };

  useEffect(() => {
    if (!needsLock) {
      setCotizacionLock(null);
      setLockError("");
      return;
    }

    let mounted = true;
    let acquiredToken = "";

    cotizacionesApi
      .acquireLock(cotizacionId)
      .then((lock) => {
        if (!mounted) {
          if (lock?.token)
            void cotizacionesApi
              .releaseLock(cotizacionId, lock.token)
              .catch(() => undefined);
          return;
        }
        acquiredToken = String(lock?.token || "");
        setCotizacionLock(lock);
        setLockError("");
      })
      .catch((error: any) => {
        if (!mounted) return;
        setCotizacionLock(null);
        setLockError(
          error.message || "Esta cotización está bloqueada por otro usuario.",
        );
      });

    return () => {
      mounted = false;
      if (acquiredToken) {
        void cotizacionesApi
          .releaseLock(cotizacionId, acquiredToken)
          .catch(() => undefined);
      }
    };
  }, [cotizacionId, needsLock]);

  useEffect(() => {
    if (!needsLock || !lockToken) return;

    const intervalId = window.setInterval(() => {
      cotizacionesApi
        .renewLock(cotizacionId, lockToken)
        .then((lock) => {
          setCotizacionLock(lock);
          setLockError("");
        })
        .catch((error: any) => {
          setCotizacionLock(null);
          setLockError(
            error.message || "El bloqueo expiro. Recarga para volver a editar.",
          );
        });
    }, 60000);

    return () => window.clearInterval(intervalId);
  }, [cotizacionId, lockToken, needsLock]);

  const createCotizacionMutation = useMutation({
    mutationFn: ensureCotizacion,
    onSuccess: async (created: any) => {
      if (created?.id && canWriteCotizacion) {
        const acquired = await cotizacionesApi.acquireLock(Number(created.id));
        setCotizacionLock(acquired);
        setLockError("");
      }
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      toast({
        variant: "success",
        title: "Cotización creada",
        description: "Ya puedes agregar líneas y calcular el total.",
      });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo crear la cotización",
      }),
  });

  const addLineaMutation = useMutation({
    mutationFn: async (producto: any) => {
      if (!cantidadValida) {
        throw new Error("Ingresa una cantidad mayor a cero.");
      }

      const current = await ensureCotizacion();
      const token = await ensureCotizacionLock(Number(current.id));
      const isManual = Boolean(producto.manual);
      const result = await cotizacionesApi.addLinea(Number(current.id), {
        ...(isManual
          ? {
              descripcion: producto.descripcion,
              precioUnitarioConIva: Number(producto.precio || 0),
              esServicio: Boolean(producto.esServicio),
            }
          : { plu: producto.plu }),
        cantidad: cantidadNumerica,
        lockToken: token,
      });
      await refreshCotizacionCache();
      return result;
    },
    onSuccess: async (result: any) => {
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      setProductSearch("");
      setCantidad("1");
      setManualDescripcion("");
      setManualPrecio("0");
      toast({
        variant: "success",
        title: result?.duplicado ? "Cantidad actualizada" : "Producto agregado",
        description: result?.mensaje || "La cotización fue recalculada.",
      });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo agregar la línea",
      }),
  });

  const updateLineaMutation = useMutation({
    mutationFn: async ({
      lineaId,
      cantidadLinea,
      precioUnitarioConIva,
      motivo,
      action,
    }: {
      lineaId: number;
      cantidadLinea: number;
      precioUnitarioConIva: number;
      motivo: string;
      action: "cantidad" | "precio";
    }) => {
      if (!cotizacion?.id || !ot?.serverId) {
        throw new Error("No hay una cotización válida para editar.");
      }

      await cotizacionesApi.updateLinea(Number(cotizacion.id), lineaId, {
        cantidad: cantidadLinea,
        precioUnitarioConIva,
        motivo: motivo || undefined,
        lockToken,
      });
      return { action };
    },
    onSuccess: async ({ action }) => {
      await refreshCotizacionCache();
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "eventos", routeId],
      });
      toast({
        variant: "success",
        title: "Cantidad actualizada",
        description: "La línea fue recalculada correctamente.",
      });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo cambiar la cantidad",
      }),
  });

  const removeLineaMutation = useMutation({
    mutationFn: async ({
      lineaId,
      motivo,
    }: {
      lineaId: number;
      motivo: string;
    }) => {
      if (!cotizacion?.id || !ot?.serverId) {
        throw new Error("No hay una cotización válida para editar.");
      }

      await cotizacionesApi.removeLinea(Number(cotizacion.id), lineaId, {
        motivo: motivo || undefined,
        lockToken,
      });
      await refreshCotizacionCache();
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "eventos", routeId],
      });
      toast({
        variant: "success",
        title: "Línea eliminada",
        description: "La cotización se actualizó correctamente.",
      });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo eliminar la línea",
      }),
  });

  const aprobarMutation = useMutation({
    mutationFn: async () => {
      if (!cotizacion?.id || !ot?.serverId) {
        throw new Error("No hay una cotización válida para aprobar.");
      }

      const aprobar = await confirm({
        title: "¿Aprobar esta cotización?",
        description:
          "Una vez aprobada ya no se puede modificar. Revisá los precios y las cantidades antes de continuar.",
        confirmLabel: "Aprobar cotización",
      });

      if (!aprobar) {
        throw new Error("Aprobación cancelada.");
      }

      const approved = await cotizacionesApi.aprobar(Number(cotizacion.id), {
        lockToken,
      });
      await setLocalOtCotizacion(Number(ot.serverId), approved);
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      await queryClient.invalidateQueries({ queryKey: ["ots"] });
      toast({
        variant: "success",
        title: "Cotización aprobada",
        description: "La cotización quedó cerrada para edición.",
      });
    },
    onError: (error: any) => {
      if (error.message === "Aprobación cancelada.") return;
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo aprobar la cotización",
      });
    },
  });

  const publicLinkMutation = useMutation({
    mutationFn: async () => {
      if (!cotizacion?.id) {
        throw new Error("Primero crea la cotización.");
      }
      return cotizacionesApi.createPublicLink(Number(cotizacion.id));
    },
    onSuccess: async (result: any) => {
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "versions", cotizacion?.id],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      await queryClient.invalidateQueries({ queryKey: ["ots"] });
      const url = `${window.location.origin}${result.publicPath}`;
      await navigator.clipboard?.writeText(url).catch(() => undefined);
      toast({
        variant: "success",
        title: "Link público creado",
        description: "El link del cliente fue copiado al portapapeles.",
      });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo crear el link público",
      }),
  });

  const whatsappCotizacionMutation = useMutation({
    mutationFn: async () => {
      if (!cotizacion?.id) {
        throw new Error("Primero crea la cotización.");
      }
      return whatsappApi.sendCotizacion(Number(cotizacion.id));
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "ot", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["cotizacion", "versions", cotizacion?.id],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "eventos", routeId],
      });
      await queryClient.invalidateQueries({
        queryKey: ["ots", "detail", routeId],
      });
      await queryClient.invalidateQueries({ queryKey: ["ots"] });
      toast({
        variant: "success",
        title: "WhatsApp enviado",
        description: "El cliente recibió el link de la cotización.",
      });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || "No se pudo enviar el WhatsApp",
      }),
  });

  // null = el usuario canceló; "" = el motivo no se exige y no se pidió.
  const promptAuditReason = async (title: string): Promise<string | null> => {
    if (!flags.exigeMotivoCambio) return "";
    const motivo = await prompt({
      title,
      description:
        "Este cambio queda registrado en la bitácora de la orden. Explicá brevemente por qué se hace.",
      label: "Motivo",
      placeholder: "Por ejemplo: el cliente autorizó cambiar el repuesto",
      multiline: true,
      confirmLabel: "Guardar motivo",
      validate: (value) =>
        value.length < 5 ? "Escribí un motivo de al menos 5 letras." : null,
    });
    return motivo?.trim() || null;
  };

  if (isLoading) {
    return (
      <div className="mx-auto max-w-7xl space-y-6">
        <div className="rounded-xl border border-border bg-surface p-5 md:p-6">
          <SkeletonDetailHeader />
        </div>
        <div className="rounded-xl border border-border bg-surface">
          <SkeletonTable rows={5} columns={4} />
        </div>
      </div>
    );
  }

  if (isError) {
    return (
      <ErrorState
        title="No se pudo cargar la cotización"
        description="Revisá tu conexión e intentá de nuevo."
        onRetry={() => void refetch()}
      />
    );
  }

  if (!ot) {
    return (
      <DashboardEmptyState
        title="OT no encontrada"
        description="No fue posible abrir la orden de trabajo para cotizar."
        icon={Receipt}
        action={
          <Button onClick={() => router.push("/dashboard/ots")}>
            Volver a recepciones
          </Button>
        }
      />
    );
  }

  return (
    <div className="min-h-full pb-16 md:pb-10">
      <main className="mx-auto flex max-w-7xl flex-col gap-6">
        <Card className="overflow-hidden bg-surface print:shadow-none">
          <CardContent className="space-y-5 p-5 md:p-6">
            <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
              <div className="flex items-start gap-3 md:gap-4">
                <Button
                  variant="ghost"
                  onClick={() => router.push(`/dashboard/ots/${routeId}`)}
                  className="no-print border border-border bg-surface px-4 font-semibold text-foreground hover:bg-muted"
                >
                  <ArrowLeft className="h-4 w-4" />
                  <span className="ml-2">Volver a OT</span>
                </Button>
                <div>
                  <div className="flex flex-wrap items-center gap-2">
                    <h1 className="text-2xl font-bold tracking-tight text-foreground md:text-3xl">
                      Cotización
                    </h1>
                    <span className="rounded-full border border-border bg-muted px-3 py-1 text-xs font-semibold uppercase tracking-wider text-foreground">
                      {cotizacionEstadoLabel}
                    </span>
                  </div>
                  <p className="mt-2 text-sm text-muted-foreground">
                    {ot.numeroOt} | {ot.vehiculo?.placa || "Sin placa"} |{" "}
                    {formatDate(ot.fechaEntrada)}
                  </p>
                  <p className="mt-1 text-sm text-muted-foreground">
                    {cliente?.nombre || ot.clienteTarjeta}
                  </p>
                </div>
              </div>

              <div className="no-print flex w-full flex-col gap-2 sm:flex-row sm:flex-wrap lg:w-auto">
                <DataRefreshControl
                  updatedAt={dataUpdatedAt}
                  isFetching={isFetching}
                  onRefresh={() => void refetch()}
                  className="w-full sm:w-auto"
                />
                {flags.imprimeCotizacion ? (
                  <Link
                    href={`/dashboard/ots/${routeId}/imprimir/cotizacion`}
                    target="_blank"
                    className="w-full sm:w-auto"
                  >
                    <Button
                      variant="outline"
                      className="w-full border-border bg-surface sm:w-auto"
                    >
                      <Printer className="mr-2 h-4 w-4" />
                      Imprimir para cliente
                    </Button>
                  </Link>
                ) : null}
                {flags.imprimeRecepcion ? (
                  <Link
                    href={`/dashboard/ots/${routeId}/imprimir/recepcion`}
                    target="_blank"
                    className="w-full sm:w-auto"
                  >
                    <Button
                      variant="outline"
                      className="w-full border-border bg-surface sm:w-auto"
                    >
                      <Printer className="mr-2 h-4 w-4" />
                      Imprimir recepción
                    </Button>
                  </Link>
                ) : null}
                {cotizacion && flags.usaLinkPublicoCotizacion ? (
                  <Button
                    variant="outline"
                    className="w-full border-border bg-surface sm:w-auto"
                    disabled={
                      !canWriteCotizacion ||
                      publicLinkMutation.isPending ||
                      lineas.length === 0 ||
                      cotizacionAprobada
                    }
                    onClick={() => publicLinkMutation.mutate()}
                  >
                    {publicLinkMutation.isPending ? (
                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                    ) : (
                      <Send className="mr-2 h-4 w-4" />
                    )}
                    Link cliente
                  </Button>
                ) : null}
                {cotizacion && usaWhatsappCotizacion ? (
                  <Button
                    variant="outline"
                    className="w-full border-emerald-200 bg-surface text-emerald-700 hover:bg-emerald-50 sm:w-auto"
                    disabled={
                      !canWriteCotizacion ||
                      whatsappCotizacionMutation.isPending ||
                      lineas.length === 0 ||
                      cotizacionAprobada
                    }
                    onClick={() => whatsappCotizacionMutation.mutate()}
                  >
                    {whatsappCotizacionMutation.isPending ? (
                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                    ) : (
                      <MessageCircle className="mr-2 h-4 w-4" />
                    )}
                    WhatsApp
                  </Button>
                ) : null}
                {!cotizacion ? (
                  <Button
                    className="w-full active:scale-[0.98] sm:w-auto"
                    onClick={() => createCotizacionMutation.mutate()}
                    disabled={
                      !canWriteCotizacion || createCotizacionMutation.isPending
                    }
                  >
                    {createCotizacionMutation.isPending ? (
                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                    ) : (
                      <Plus className="mr-2 h-4 w-4" />
                    )}
                    {canWriteCotizacion
                      ? "Crear cotización"
                      : "Requiere conexión"}
                  </Button>
                ) : (
                  <Button
                    className="w-full active:scale-[0.98] sm:w-auto"
                    onClick={() => aprobarMutation.mutate()}
                    disabled={
                      !canEditCotizacion ||
                      aprobarMutation.isPending ||
                      lineas.length === 0
                    }
                  >
                    {aprobarMutation.isPending ? (
                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                    ) : (
                      <CheckCircle2 className="mr-2 h-4 w-4" />
                    )}
                    {cotizacionAprobada ? "Ya aprobada" : "Aprobar cotización"}
                  </Button>
                )}
              </div>
            </div>

            {!canWriteCotizacion ? (
              <div className="no-print rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
                <span className="inline-flex items-center gap-2 font-semibold">
                  <WifiOff className="h-4 w-4" />
                  La edición de cotizaciones requiere una recepción sincronizada
                  y conexión activa.
                </span>
              </div>
            ) : null}

            {needsLock && (!lockToken || lockError) ? (
              <div className="no-print rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
                <span className="inline-flex items-center gap-2 font-semibold">
                  <Lock className="h-4 w-4" />
                  {lockError || "Preparando edicion segura..."}
                </span>
              </div>
            ) : null}

            {cotizacionRechazada ? (
              <div className="no-print rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
                <span className="inline-flex items-center gap-2 font-semibold">
                  <AlertTriangle className="h-4 w-4" />
                  El cliente rechazo esta version. Puedes editarla y generar un
                  nuevo link para aprobacion.
                </span>
              </div>
            ) : null}

            <div className="grid gap-3 sm:grid-cols-2">
              <div className="rounded-xl border border-border bg-muted p-4">
                <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
                  Líneas / unidades
                </p>
                <p className="mt-2 text-2xl font-bold tabular-nums text-foreground md:text-3xl">
                  {totalLineas} / {totalUnidades.toLocaleString()}
                </p>
              </div>
              <div className="rounded-xl border border-border bg-muted p-4">
                <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
                  Total a pagar
                </p>
                <p className="mt-2 break-words text-2xl font-bold tabular-nums text-foreground md:text-3xl">
                  {formatCurrency(Number(cotizacion?.total || 0))}
                </p>
              </div>
            </div>
          </CardContent>
        </Card>

        <div className="grid gap-6 2xl:grid-cols-[minmax(0,1.05fr)_minmax(620px,0.95fr)]">
          <DashboardSection
            title="Líneas de cotización"
            description="Se guarda el precio con el que se cotizó. Los totales se recalculan solos."
          >
            {cotizacion ? (
              lineas.length > 0 ? (
                <div className="space-y-6">
                  {/* SERVICIOS BLOCK */}
                  <div>
                    <h3 className="mb-3 font-semibold text-foreground">
                      Servicios
                    </h3>
                    {servicios.length > 0 ? (
                      <div className="space-y-3">
                        {servicios.map((linea: any) => {
                          const quantityValue =
                            lineaCantidades[Number(linea.id)] ??
                            String(Number(linea.cantidad || 1));
                          const priceValue =
                            lineaPrecios[Number(linea.id)] ??
                            String(Number(linea.precioUnitario || 0));
                          const parsedQuantity = Number(quantityValue);
                          const parsedPrice = Number(priceValue);
                          const parsedQuantityValid =
                            Number.isFinite(parsedQuantity) &&
                            parsedQuantity > 0;
                          const parsedPriceValid =
                            Number.isFinite(parsedPrice) && parsedPrice >= 0;
                          return (
                            <div
                              key={linea.id}
                              className="rounded-xl border border-emerald-100 bg-surface p-4 shadow-sm"
                            >
                              <div className="grid gap-4">
                                <div className="min-w-0">
                                  <div className="flex flex-wrap items-center gap-2">
                                    <p className="text-base font-bold text-foreground">
                                      {linea.descripcion}
                                    </p>
                                    <span className="rounded-full bg-muted px-2.5 py-1 text-xs font-semibold text-muted-foreground">
                                      {linea.plu}
                                    </span>
                                    <span className="rounded-full bg-emerald-50 px-2.5 py-1 text-xs font-semibold text-emerald-700">
                                      Servicio
                                    </span>
                                  </div>
                                  <div className="mt-4 grid grid-cols-2 gap-2 md:grid-cols-3">
                                    <div className="rounded-xl bg-muted p-3">
                                      <p className="text-[11px] font-bold uppercase tracking-wider text-subtle-foreground">
                                        Cant.
                                      </p>
                                      <p className="mt-1 font-semibold text-foreground">
                                        {Number(
                                          linea.cantidad || 0,
                                        ).toLocaleString()}
                                      </p>
                                    </div>
                                    <div className="rounded-xl bg-muted p-3">
                                      <p className="text-[11px] font-bold uppercase tracking-wider text-subtle-foreground">
                                        Unitario
                                      </p>
                                      <p className="mt-1 font-semibold text-foreground">
                                        {formatCurrency(
                                          getLineUnitTotal(linea),
                                        )}
                                      </p>
                                    </div>
                                    <div className="rounded-xl bg-muted p-3">
                                      <p className="text-[11px] font-bold uppercase tracking-wider text-muted-foreground">
                                        Total
                                      </p>
                                      <p className="mt-1 font-bold text-foreground">
                                        {formatCurrency(
                                          Number(linea.total || 0),
                                        )}
                                      </p>
                                    </div>
                                  </div>
                                </div>

                                {canEditLineas ? (
                                  <div className="no-print grid w-full gap-2 md:grid-cols-[1fr_1fr_auto]">
                                    <Input
                                      type="number"
                                      min="0.001"
                                      step="0.001"
                                      aria-label="Cantidad"
                                      placeholder="Cantidad"
                                      value={quantityValue}
                                      onChange={(event) =>
                                        setLineaCantidades((current) => ({
                                          ...current,
                                          [Number(linea.id)]: event.target.value,
                                        }))
                                      }
                                      className="h-11 border-border bg-surface"
                                    />
                                    <Button
                                      variant="outline"
                                      className="h-11 border-border"
                                      disabled={
                                        updateLineaMutation.isPending ||
                                        !parsedQuantityValid
                                      }
                                      onClick={async () => {
                                        const motivo =
                                          await promptAuditReason("Cambio de cantidad");
                                        if (motivo === null) return;
                                        updateLineaMutation.mutate({
                                          lineaId: Number(linea.id),
                                          cantidadLinea: parsedQuantity,
                                          precioUnitarioConIva:
                                            getLineUnitTotal(linea),
                                          motivo,
                                          action: "cantidad",
                                        });
                                      }}
                                    >
                                      {updateLineaMutation.isPending ? (
                                        <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                      ) : (
                                        <Save className="mr-2 h-4 w-4" />
                                      )}
                                      Cantidad
                                    </Button>
                                    <Input
                                      type="number"
                                      min="0"
                                      step="0.01"
                                      aria-label="Precio unitario final"
                                      placeholder="Precio unitario final"
                                      value={priceValue}
                                      onChange={(event) =>
                                        setLineaPrecios((current) => ({
                                          ...current,
                                          [Number(linea.id)]: event.target.value,
                                        }))
                                      }
                                      className="h-11 border-border bg-surface"
                                    />
                                    <div className="flex gap-2 md:col-span-2">
                                      <Button
                                        variant="outline"
                                        className="flex-1 border-border"
                                        disabled={
                                          updateLineaMutation.isPending ||
                                          !parsedQuantityValid ||
                                          !parsedPriceValid
                                        }
                                        onClick={async () => {
                                          const motivo =
                                            await promptAuditReason("Cambio de precio");
                                          if (motivo === null) return;
                                          updateLineaMutation.mutate({
                                            lineaId: Number(linea.id),
                                            cantidadLinea: parsedQuantity,
                                            precioUnitarioConIva: parsedPrice,
                                            motivo,
                                            action: "precio",
                                          });
                                        }}
                                      >
                                        {updateLineaMutation.isPending ? (
                                          <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                        ) : (
                                          <Save className="mr-2 h-4 w-4" />
                                        )}
                                        Cambiar precio
                                      </Button>
                                      <Button
                                        variant="outline"
                                        className="border-border text-red-600 hover:bg-red-50 hover:text-red-700"
                                        disabled={removeLineaMutation.isPending}
                                        aria-label="Eliminar línea de la cotización"
                                        onClick={async () => {
                                          const motivo =
                                            await promptAuditReason("Eliminar linea");
                                          if (motivo === null) return;
                                          const ok = await confirm({
                                            title: "¿Eliminar esta línea?",
                                            description:
                                              "Se quita de la cotización y el total se recalcula.",
                                            confirmLabel: "Eliminar línea",
                                            tone: "destructive",
                                          });
                                          if (!ok) return;
                                          removeLineaMutation.mutate({
                                            lineaId: Number(linea.id),
                                            motivo,
                                          });
                                        }}
                                      >
                                        <Trash2 className="h-4 w-4" />
                                      </Button>
                                    </div>
                                  </div>
                                ) : null}
                              </div>
                            </div>
                          );
                        })}
                      </div>
                    ) : (
                      <p className="text-sm italic text-subtle-foreground">
                        No hay servicios agregados todavía.
                      </p>
                    )}
                  </div>

                  {/* REPUESTOS BLOCK */}
                  <div>
                    <h3 className="mb-3 font-semibold text-foreground">
                      Repuestos y productos
                    </h3>
                    {repuestos.length > 0 ? (
                      <div className="space-y-3">
                        {repuestos.map((linea: any) => {
                          const quantityValue =
                            lineaCantidades[Number(linea.id)] ??
                            String(Number(linea.cantidad || 1));
                          const priceValue =
                            lineaPrecios[Number(linea.id)] ??
                            String(Number(linea.precioUnitario || 0));
                          const parsedQuantity = Number(quantityValue);
                          const parsedPrice = Number(priceValue);
                          const parsedQuantityValid =
                            Number.isFinite(parsedQuantity) &&
                            parsedQuantity > 0;
                          const parsedPriceValid =
                            Number.isFinite(parsedPrice) && parsedPrice >= 0;
                          return (
                            <div
                              key={linea.id}
                              className="rounded-xl border border-primary/30 bg-surface p-4 shadow-sm"
                            >
                              <div className="grid gap-4">
                                <div className="min-w-0">
                                  <div className="flex flex-wrap items-center gap-2">
                                    <p className="text-base font-bold text-foreground">
                                      {linea.descripcion}
                                    </p>
                                    <span className="rounded-full bg-muted px-2.5 py-1 text-xs font-semibold text-muted-foreground">
                                      {linea.plu}
                                    </span>
                                    <span className="rounded-full bg-primary-soft px-2.5 py-1 text-xs font-semibold text-primary">
                                      Producto
                                    </span>
                                  </div>
                                  <div className="mt-4 grid grid-cols-2 gap-2 md:grid-cols-3">
                                    <div className="rounded-xl bg-muted p-3">
                                      <p className="text-[11px] font-bold uppercase tracking-wider text-subtle-foreground">
                                        Cant.
                                      </p>
                                      <p className="mt-1 font-semibold text-foreground">
                                        {Number(
                                          linea.cantidad || 0,
                                        ).toLocaleString()}
                                      </p>
                                    </div>
                                    <div className="rounded-xl bg-muted p-3">
                                      <p className="text-[11px] font-bold uppercase tracking-wider text-subtle-foreground">
                                        Unitario
                                      </p>
                                      <p className="mt-1 font-semibold text-foreground">
                                        {formatCurrency(
                                          getLineUnitTotal(linea),
                                        )}
                                      </p>
                                    </div>
                                    <div className="rounded-xl bg-muted p-3">
                                      <p className="text-[11px] font-bold uppercase tracking-wider text-muted-foreground">
                                        Total
                                      </p>
                                      <p className="mt-1 font-bold text-foreground">
                                        {formatCurrency(
                                          Number(linea.total || 0),
                                        )}
                                      </p>
                                    </div>
                                  </div>
                                </div>

                                {canEditLineas ? (
                                  <div className="no-print grid w-full gap-2 md:grid-cols-[1fr_1fr_auto]">
                                    <Input
                                      type="number"
                                      min="0.001"
                                      step="0.001"
                                      aria-label="Cantidad"
                                      placeholder="Cantidad"
                                      value={quantityValue}
                                      onChange={(event) =>
                                        setLineaCantidades((current) => ({
                                          ...current,
                                          [Number(linea.id)]: event.target.value,
                                        }))
                                      }
                                      className="h-11 border-border bg-surface"
                                    />
                                    <Button
                                      variant="outline"
                                      className="h-11 border-border"
                                      disabled={
                                        updateLineaMutation.isPending ||
                                        !parsedQuantityValid
                                      }
                                      onClick={async () => {
                                        const motivo =
                                          await promptAuditReason("Cambio de cantidad");
                                        if (motivo === null) return;
                                        updateLineaMutation.mutate({
                                          lineaId: Number(linea.id),
                                          cantidadLinea: parsedQuantity,
                                          precioUnitarioConIva:
                                            getLineUnitTotal(linea),
                                          motivo,
                                          action: "cantidad",
                                        });
                                      }}
                                    >
                                      {updateLineaMutation.isPending ? (
                                        <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                      ) : (
                                        <Save className="mr-2 h-4 w-4" />
                                      )}
                                      Cantidad
                                    </Button>
                                    <Input
                                      type="number"
                                      min="0"
                                      step="0.01"
                                      aria-label="Precio unitario final"
                                      placeholder="Precio unitario final"
                                      value={priceValue}
                                      onChange={(event) =>
                                        setLineaPrecios((current) => ({
                                          ...current,
                                          [Number(linea.id)]: event.target.value,
                                        }))
                                      }
                                      className="h-11 border-border bg-surface"
                                    />
                                    <div className="flex gap-2 md:col-span-2">
                                      <Button
                                        variant="outline"
                                        className="flex-1 border-border"
                                        disabled={
                                          updateLineaMutation.isPending ||
                                          !parsedQuantityValid ||
                                          !parsedPriceValid
                                        }
                                        onClick={async () => {
                                          const motivo =
                                            await promptAuditReason("Cambio de precio");
                                          if (motivo === null) return;
                                          updateLineaMutation.mutate({
                                            lineaId: Number(linea.id),
                                            cantidadLinea: parsedQuantity,
                                            precioUnitarioConIva: parsedPrice,
                                            motivo,
                                            action: "precio",
                                          });
                                        }}
                                      >
                                        {updateLineaMutation.isPending ? (
                                          <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                        ) : (
                                          <Save className="mr-2 h-4 w-4" />
                                        )}
                                        Cambiar precio
                                      </Button>
                                      <Button
                                        variant="outline"
                                        className="border-border text-red-600 hover:bg-red-50 hover:text-red-700"
                                        disabled={removeLineaMutation.isPending}
                                        aria-label="Eliminar línea de la cotización"
                                        onClick={async () => {
                                          const motivo =
                                            await promptAuditReason("Eliminar linea");
                                          if (motivo === null) return;
                                          const ok = await confirm({
                                            title: "¿Eliminar esta línea?",
                                            description:
                                              "Se quita de la cotización y el total se recalcula.",
                                            confirmLabel: "Eliminar línea",
                                            tone: "destructive",
                                          });
                                          if (!ok) return;
                                          removeLineaMutation.mutate({
                                            lineaId: Number(linea.id),
                                            motivo,
                                          });
                                        }}
                                      >
                                        <Trash2 className="h-4 w-4" />
                                      </Button>
                                    </div>
                                  </div>
                                ) : null}
                              </div>
                            </div>
                          );
                        })}
                      </div>
                    ) : (
                      <p className="text-sm italic text-subtle-foreground">
                        No hay repuestos agregados todavía.
                      </p>
                    )}
                  </div>
                </div>
              ) : (
                <DashboardEmptyState
                  title="La cotización está vacía"
                  description="Agrega productos o servicios desde la búsqueda lateral para empezar a calcular el total."
                  icon={Receipt}
                  className="border-none bg-muted shadow-none"
                />
              )
            ) : (
              <DashboardEmptyState
                title="Todavía no existe una cotización"
                description="Créala primero y luego agrega líneas según el trabajo estimado."
                icon={Receipt}
                className="border-none bg-muted shadow-none"
              />
            )}
          </DashboardSection>

          <div className="space-y-6">
            <DashboardSection
              title={
                lineasBloqueadas ? "Cotización bloqueada" : "Agregar productos"
              }
              description={
                cotizacionAprobada
                  ? "La cotización aprobada queda en solo lectura para evitar cambios accidentales."
                  : cotizacionEnviada
                    ? "La cotización enviada al cliente queda en solo lectura hasta que responda."
                    : "Flujo rápido para tablet: filtro, cantidad y agregar sin abrir pantallas extra."
              }
            >
              {lineasBloqueadas ? (
                <div className="rounded-xl border border-emerald-200 bg-emerald-50 p-5 text-sm text-emerald-800">
                  <span className="inline-flex items-center gap-2 font-semibold">
                    <CheckCircle2 className="h-4 w-4" />
                    {cotizacionAprobada
                      ? "Esta cotización ya fue aprobada. Puedes imprimirla, pero no agregar ni modificar líneas."
                      : "Esta cotización ya fue enviada al cliente. Espera su respuesta o márcala como rechazada para volver a editarla."}
                  </span>
                </div>
              ) : (
                <div className="space-y-4">
                  <div className="flex flex-wrap gap-2">
                    <Button
                      type="button"
                      variant={searchMode === "taller" ? "default" : "outline"}
                      className={
                        searchMode === "taller" ? "" : "border-border bg-surface"
                      }
                      onClick={() => setSearchMode("taller")}
                    >
                      <Wrench className="mr-2 h-4 w-4" />
                      Repuestos taller
                    </Button>
                    <Button
                      type="button"
                      variant={
                        searchMode === "servicios" ? "default" : "outline"
                      }
                      className={
                        searchMode === "servicios"
                          ? ""
                          : "border-border bg-surface"
                      }
                      onClick={() => setSearchMode("servicios")}
                    >
                      <Receipt className="mr-2 h-4 w-4" />
                      Servicios
                    </Button>
                    <Button
                      type="button"
                      variant={searchMode === "todos" ? "default" : "outline"}
                      className={
                        searchMode === "todos" ? "" : "border-border bg-surface"
                      }
                      onClick={() => setSearchMode("todos")}
                    >
                      <PackageSearch className="mr-2 h-4 w-4" />
                      Ver todo
                    </Button>
                  </div>

                  <div className="grid gap-3 md:grid-cols-[1fr_140px]">
                    <div className="relative">
                      <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-subtle-foreground" />
                      <Input
                        value={productSearch}
                        onChange={(event) =>
                          setProductSearch(event.target.value)
                        }
                        placeholder="Buscar por código (PLU) o descripción..."
                        className="h-11 border-border bg-surface pl-10"
                      />
                    </div>
                    <Input
                      type="number"
                      min="0.001"
                      step="0.001"
                      value={cantidad}
                      onChange={(event) => setCantidad(event.target.value)}
                      className="h-11 border-border bg-surface"
                    />
                  </div>

                  <div className="rounded-xl border border-border bg-muted p-4">
                    <p className="text-sm font-semibold text-foreground">
                      Cantidad seleccionada
                    </p>
                    <p className="mt-1 text-sm text-muted-foreground">
                      {cantidadValida
                        ? `Cada línea se agregará con ${cantidadNumerica.toLocaleString()} unidad(es).`
                        : "Ingresa una cantidad mayor a cero."}
                    </p>
                    {searchMode === "taller" ? (
                      <p className="mt-2 text-xs font-medium uppercase tracking-wider text-subtle-foreground">
                        Mostrando productos marcados para taller
                      </p>
                    ) : null}
                  </div>

                  {canAddProductoLibre ? (
                    <div className="rounded-xl border border-amber-200 bg-amber-50 p-4">
                      <div className="flex flex-col gap-3">
                        <div>
                          <p className="text-sm font-bold text-amber-950">
                            Producto por ingresar
                          </p>
                          <p className="mt-1 text-xs font-medium text-amber-700">
                            Usalo cuando el repuesto no exista en inventario o se
                            cotice en Q 0.00 hasta confirmar con el cliente. Se
                            agrega solo a esta cotización — no crea un producto
                            nuevo en tu catálogo de Productos.
                          </p>
                        </div>
                        <Input
                          value={manualDescripcion}
                          onChange={(event) =>
                            setManualDescripcion(event.target.value)
                          }
                          placeholder="Descripción del producto o servicio"
                          className="h-11 border-amber-200 bg-surface"
                        />
                        <div className="grid gap-2 sm:grid-cols-[1fr_150px_auto]">
                          <Select
                            value={manualEsServicio ? "servicio" : "repuesto"}
                            onValueChange={(value) =>
                              setManualEsServicio(value === "servicio")
                            }
                          >
                            <SelectTrigger className="h-11 border-amber-200 bg-surface font-semibold">
                              <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="repuesto">Repuesto</SelectItem>
                              <SelectItem value="servicio">Servicio</SelectItem>
                            </SelectContent>
                          </Select>
                          <Input
                            type="number"
                            min="0"
                            step="0.01"
                            value={manualPrecio}
                            onChange={(event) => setManualPrecio(event.target.value)}
                            placeholder="Q 0.00"
                            className="h-11 border-amber-200 bg-surface"
                          />
                          <Button
                            type="button"
                            className="h-11 bg-amber-600 px-5 font-bold hover:bg-amber-700 active:scale-[0.98]"
                            disabled={
                              !canEditLineas ||
                              addLineaMutation.isPending ||
                              !cantidadValida ||
                              !manualDescripcion.trim() ||
                              !Number.isFinite(Number(manualPrecio || 0)) ||
                              Number(manualPrecio || 0) < 0
                            }
                            onClick={() =>
                              addLineaMutation.mutate({
                                manual: true,
                                descripcion: manualDescripcion.trim(),
                                precio: Number(manualPrecio || 0),
                                esServicio: manualEsServicio,
                              })
                            }
                          >
                            {addLineaMutation.isPending ? (
                              <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                            ) : (
                              <Plus className="mr-2 h-4 w-4" />
                            )}
                            Agregar
                          </Button>
                        </div>
                      </div>
                    </div>
                  ) : null}

                  {searchingProducts ? (
                    <div className="flex items-center justify-center py-10 text-sm text-muted-foreground">
                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                      Buscando productos...
                    </div>
                  ) : productos.length > 0 ? (
                    <div className="overflow-hidden rounded-xl border border-border bg-surface">
                      <div className="flex flex-col gap-3 border-b border-border bg-muted px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
                        <p className="text-sm font-semibold text-foreground">
                          {productos.length} resultado(s). Mostrando{" "}
                          {visibleProductos.length} por pagina.
                        </p>
                        <div className="flex items-center gap-2">
                          <label className="text-sm font-medium text-muted-foreground">
                            Filas
                          </label>
                          <Select
                            value={String(productPageSize)}
                            onValueChange={(value) =>
                              setProductPageSize(Number(value))
                            }
                          >
                            <SelectTrigger className="h-9 w-20 font-semibold">
                              <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                              {[5, 10, 15, 25].map((size) => (
                                <SelectItem key={size} value={String(size)}>
                                  {size}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                      </div>

                      <div className="grid gap-2 p-2 xl:grid-cols-2">
                        {visibleProductos.map((producto: any) => (
                          <button
                            key={producto.plu}
                            type="button"
                            className="flex w-full items-center justify-between gap-3 rounded-xl border border-border bg-surface p-3 text-left shadow-sm transition-colors active:scale-[0.98] hover:bg-muted disabled:cursor-not-allowed disabled:opacity-60 disabled:active:scale-100"
                            disabled={
                              !canEditLineas ||
                              addLineaMutation.isPending ||
                              !cantidadValida
                            }
                            onClick={() => addLineaMutation.mutate(producto)}
                          >
                            <span className="min-w-0 flex-1 text-sm font-bold leading-5 text-foreground">
                              {producto.desclarga}
                            </span>
                            <span className="flex shrink-0 items-center gap-2">
                              <span className="text-right">
                                <span className="block text-sm font-bold tabular-nums text-foreground">
                                  {formatCurrency(Number(producto.precio || 0))}
                                </span>
                                <span className="block text-[10px] font-bold uppercase tracking-wider text-subtle-foreground">
                                  Final
                                </span>
                              </span>
                              {addLineaMutation.isPending ? (
                                <Loader2 className="h-4 w-4 animate-spin" />
                              ) : (
                                <Plus className="h-4 w-4" />
                              )}
                            </span>
                          </button>
                        ))}
                      </div>

                      <div className="flex flex-col gap-3 border-t border-border bg-surface px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
                        <p className="text-sm font-medium text-muted-foreground">
                          Pagina {productPage} de {totalProductPages}
                        </p>
                        <div className="flex gap-2">
                          <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            className="rounded-xl border-border"
                            disabled={productPage <= 1}
                            onClick={() =>
                              setProductPage((page) => Math.max(1, page - 1))
                            }
                          >
                            <ChevronLeft className="mr-1 h-4 w-4" />
                            Anterior
                          </Button>
                          <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            className="rounded-xl border-border"
                            disabled={productPage >= totalProductPages}
                            onClick={() =>
                              setProductPage((page) =>
                                Math.min(totalProductPages, page + 1),
                              )
                            }
                          >
                            Siguiente
                            <ChevronRight className="ml-1 h-4 w-4" />
                          </Button>
                        </div>
                      </div>
                    </div>
                  ) : (
                    <DashboardEmptyState
                      title="Sin productos disponibles"
                      description="Busca por nombre o PLU. Si ya sincronizaste productos, también aparecerán sin depender del servidor en tiempo real."
                      icon={PackageSearch}
                      className="border-none bg-muted shadow-none"
                    />
                  )}
                </div>
              )}
            </DashboardSection>

            {canViewCotizacionAudit ? (
              <DashboardSection
                title="Historial de cotización"
                description={
                  flags.exigeMotivoCambio
                    ? "Auditoria de cambios con usuario y motivo obligatorio."
                    : "Auditoria de cambios con usuario y motivo."
                }
              >
                {cotizacionVersiones.length > 0 ? (
                  <div className="mb-6 space-y-2">
                    <p className="text-xs font-bold uppercase tracking-wider text-subtle-foreground">
                      Versiones guardadas
                    </p>
                    {cotizacionVersiones.slice(0, 5).map((version: any) => (
                      <div
                        key={version.id}
                        className="rounded-xl border border-border bg-surface p-3 text-sm"
                      >
                        <div className="flex flex-wrap items-center justify-between gap-2">
                          <span className="font-bold text-foreground">
                            Version {version.version} | {version.estado}
                          </span>
                          <span className="text-xs font-medium text-muted-foreground">
                            {version.createdAt
                              ? formatDateTime(version.createdAt)
                              : "Sin fecha"}
                          </span>
                        </div>
                        <p className="mt-1 text-muted-foreground">
                          {version.motivo || "Cambio guardado"}
                        </p>
                        {version.createdBy ? (
                          <p className="mt-1 text-xs text-subtle-foreground">
                            Usuario {version.createdBy}
                          </p>
                        ) : null}
                      </div>
                    ))}
                  </div>
                ) : null}
                {cotizacionEventos.length > 0 ? (
                  <div className="space-y-3">
                    <p className="text-xs font-bold uppercase tracking-wider text-subtle-foreground">
                      Registro completo de eventos
                    </p>
                    {cotizacionEventos.slice(0, 8).map((evento: any) => (
                      <div
                        key={evento.id}
                        className="rounded-xl border border-border bg-muted p-4"
                      >
                        <div className="flex items-start gap-3">
                          <span className="mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface text-primary shadow-sm">
                            <History className="h-4 w-4" />
                          </span>
                          <div className="min-w-0 flex-1">
                            <p className="text-sm font-bold text-foreground">
                              {evento.descripcion || "Cambio registrado"}
                            </p>
                            <p className="mt-1 text-xs text-muted-foreground">
                              {evento.createdAt
                                ? formatDateTime(evento.createdAt)
                                : "Fecha no registrada"}
                              {evento.usuario?.nombre ||
                              evento.usuario?.username
                                ? ` | ${evento.usuario?.nombre || evento.usuario?.username}`
                                : evento.usuarioId
                                  ? ` | Usuario ${evento.usuarioId}`
                                  : ""}
                            </p>
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div className="rounded-xl border border-dashed border-border-strong bg-muted p-4 text-sm text-muted-foreground">
                    Todavía no hay cambios auditados en esta cotización.
                  </div>
                )}
              </DashboardSection>
            ) : null}

            {flags.imprimeCotizacion || flags.imprimeRecepcion ? (
              <DashboardSection
                title="Documentos para imprimir"
                description="Formatos profesionales listos para entregar al cliente o usar internamente."
              >
                <div className="space-y-4 rounded-xl border border-border bg-muted p-4">
                  <div>
                    <p className="text-xs uppercase tracking-wider text-subtle-foreground">
                      Cliente
                    </p>
                    <p className="mt-1 font-bold text-foreground">
                      {cliente?.nombre || ot.clienteTarjeta}
                    </p>
                  </div>
                  <div>
                    <p className="text-xs uppercase tracking-wider text-subtle-foreground">
                      Vehículo
                    </p>
                    <p className="mt-1 font-bold text-foreground">
                      {ot.vehiculo?.placa || "-"} | {ot.vehiculo?.marca || ""}{" "}
                      {ot.vehiculo?.modelo || ""}
                    </p>
                  </div>
                  <div className="grid gap-3 sm:grid-cols-2">
                    <div>
                      <p className="text-xs uppercase tracking-wider text-subtle-foreground">
                        Número
                      </p>
                      <p className="mt-1 font-semibold text-foreground">
                        {cotizacion?.numeroCotizacion || "Pendiente"}
                      </p>
                    </div>
                    <div>
                      <p className="text-xs uppercase tracking-wider text-subtle-foreground">
                        Total
                      </p>
                      <p className="mt-1 text-xl font-bold tabular-nums text-foreground">
                        {formatCurrency(Number(cotizacion?.total || 0))}
                      </p>
                    </div>
                  </div>
                  <div className="no-print grid gap-2 sm:grid-cols-2">
                    {flags.imprimeCotizacion ? (
                      <Link
                        href={`/dashboard/ots/${routeId}/imprimir/cotizacion`}
                        target="_blank"
                        className="w-full"
                      >
                        <Button
                          variant="outline"
                          className="w-full border-border bg-surface"
                        >
                          <Printer className="mr-2 h-4 w-4" />
                          Imprimir para cliente
                        </Button>
                      </Link>
                    ) : null}
                    {flags.imprimeRecepcion ? (
                      <Link
                        href={`/dashboard/ots/${routeId}/imprimir/recepcion`}
                        target="_blank"
                        className="w-full"
                      >
                        <Button
                          variant="outline"
                          className="w-full border-border bg-surface"
                        >
                          <Printer className="mr-2 h-4 w-4" />
                          Imprimir recepción
                        </Button>
                      </Link>
                    ) : null}
                  </div>
                  <p className="no-print text-center text-xs text-subtle-foreground">
                    Los documentos se abren en una pestaña limpia, lista para
                    imprimir.
                  </p>
                </div>
              </DashboardSection>
            ) : null}
          </div>
        </div>
      </main>
    </div>
  );
}
