import { Icon } from "@iconify/react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import styled, { keyframes } from "styled-components";
import { getCategoriasRoots } from "../../api/categorias.service";
import { addPedidoItem, createPedido } from "../../api/pedidos.service";
import { buscarProductos, getProducto, getProductos } from "../../api/productos.service";
import { ProductDetailModal } from "./ProductDetailModal";

// Los pedidos todavía no admiten presentaciones (el backend las rechaza: el cálculo
// multiplicaba el precio de la caja por las unidades). Se vuelven a mostrar al corregirlo.
const PRESENTACIONES_EN_PEDIDOS = false;
const presentacionesDe = (x) =>
  PRESENTACIONES_EN_PEDIDOS ? (x?.producto_presentaciones || x?.presentaciones || []).filter((p) => p.active !== false) : [];

export function CatalogPanel({
  pedido,
  cliente,
  contexto,
  monedaId,
  vendedorId,
  depositoId,
  sucursalId,
  onPedidoCreated,
  onPedidoUpdated,
  createPedidoFn = createPedido,
}) {
  const [query, setQuery] = useState("");
  const [productos, setProductos] = useState([]);
  const [loading, setLoading] = useState(false);
  const [adding, setAdding] = useState(null);
  const [activeTab, setActiveTab] = useState("buscar");
  const [categorias, setCategorias] = useState([]);
  const [categoriaId, setCategoriaId] = useState(null);
  const [detailProduct, setDetailProduct] = useState(null);
  const inputRef = useRef(null);
  const debounceRef = useRef(null);

  const frecuentes = useMemo(() => contexto?.productos_frecuentes || [], [contexto]);
  const topVentas = useMemo(() => contexto?.productos_top_ventas || [], [contexto]);
  const ofertas = useMemo(() => contexto?.ofertas_activas || [], [contexto]);
  const listaPrecios = contexto?.cliente?.lista_precios || null;
  // Mapa producto_id -> oferta (para badges en cards)
  // Soporta: aplica_a="producto" con referencia_id, aplica_a="todos", y legacy producto_id
  const { ofertasMap, ofertaGlobal } = useMemo(() => {
    const map = {};
    let global = null;
    if (contexto?.ofertas_activas) {
      contexto.ofertas_activas.forEach((o) => {
        const apps = o.aplicaciones || [];
        if (apps.length === 0) {
          global = o;
          return;
        }
        apps.forEach((a) => {
          if (a.aplica_a === "todos") {
            global = o;
          } else if (a.aplica_a === "producto" && a.referencia_id) {
            map[a.referencia_id] = o;
          } else if (a.producto_id) {
            // Legacy: campo directo producto_id
            map[a.producto_id] = o;
          }
        });
      });
    }
    return { ofertasMap: map, ofertaGlobal: global };
  }, [contexto]);

  // Helper: obtener oferta para un producto dado
  const getOfertaForProduct = useCallback((prodId) => {
    return ofertasMap[prodId] || ofertaGlobal || null;
  }, [ofertasMap, ofertaGlobal]);

  // Resolver datos de productos referenciados en ofertas
  const [ofertaProductos, setOfertaProductos] = useState({});
  useEffect(() => {
    const ids = [];
    (contexto?.ofertas_activas || []).forEach((o) => {
      (o.aplicaciones || []).forEach((a) => {
        if (a.aplica_a === "producto" && a.referencia_id && !a.producto?.descripcion) {
          ids.push(a.referencia_id);
        }
      });
    });
    if (ids.length === 0) return;
    const unique = [...new Set(ids)];
    Promise.allSettled(unique.map((id) => getProducto(id))).then((results) => {
      const map = {};
      results.forEach((r, i) => {
        if (r.status === "fulfilled" && r.value) {
          const prod = r.value?.data || r.value;
          map[unique[i]] = prod;
        }
      });
      setOfertaProductos(map);
    });
  }, [contexto?.ofertas_activas]);

  useEffect(() => {
    inputRef.current?.focus();
    getCategoriasRoots()
      .then((data) => setCategorias(data.filter((c) => c.activo !== false)))
      .catch(() => {});
  }, []);

  useEffect(() => {
    if (query.length >= 2) setActiveTab("buscar");
  }, [query]);

  // Cargar productos por categoría cuando no hay búsqueda
  useEffect(() => {
    if (query.length >= 2 || !categoriaId) return;
    setLoading(true);
    getProductos(1, 60, categoriaId)
      .then((data) => setProductos(data?.data || data?.items || []))
      .catch(() => setProductos([]))
      .finally(() => setLoading(false));
  }, [categoriaId, query]);

  const buscar = useCallback(
    async (term) => {
      if (!term || term.length < 2) {
        setProductos([]);
        return;
      }
      setLoading(true);
      try {
        const data = await buscarProductos(term, 40, null, categoriaId);
        setProductos(data || []);
      } catch {
        setProductos([]);
      } finally {
        setLoading(false);
      }
    },
    [categoriaId],
  );

  const handleChange = (e) => {
    const val = e.target.value;
    setQuery(val);
    clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => buscar(val), 250);
  };

  const handleCategoriaClick = (id) => {
    setCategoriaId((prev) => (prev === id ? null : id));
    setQuery("");
    setProductos([]);
    inputRef.current?.focus();
  };

  const handleAddProduct = async (producto, presentacion = null, fromModal = false) => {
    const addKey = producto.id + (presentacion?.id || "");
    setAdding(addKey);
    try {
      const productoId = producto.producto_id || producto.id;
      const precioBase = Number(producto.precio) || 0;

      // Opción C: Resolver descuento desde oferta como porcentaje
      // El backend resolverá precioBase desde lista de precios y aplicará descuentos
      const oferta = getOfertaForProduct(productoId);
      let descuentoPct = 0;
      let ofertaNombre = null;

      if (oferta) {
        ofertaNombre = oferta.nombre;
        if (oferta.tipo === "descuento_porcentaje") {
          descuentoPct = Number(oferta.valor) || 0;
        } else if (oferta.tipo === "descuento_monto" && precioBase > 0) {
          // Convertir monto a porcentaje del precioBase
          descuentoPct = (Number(oferta.valor) / precioBase) * 100;
        } else if (oferta.tipo === "precio_especial" && precioBase > 0) {
          // Convertir precio especial a porcentaje de descuento
          descuentoPct = ((precioBase - Number(oferta.valor)) / precioBase) * 100;
        }
        descuentoPct = Math.round(descuentoPct * 100) / 100;
      }

      const itemData = {
        producto_id: productoId,
        cantidad: 1,
        ...(presentacion?.id && { presentacion_id: presentacion.id }),
        ...(descuentoPct > 0 && { descuento_porcentaje: descuentoPct }),
      };

      if (!pedido) {
        const result = await createPedidoFn({
          cliente_id: cliente.id,
          items: [itemData],
          ...(monedaId && { moneda_id: monedaId }),
          ...(vendedorId && { vendedor_id: vendedorId }),
          ...(depositoId && { deposito_id: depositoId }),
          ...(sucursalId && { sucursal_id: sucursalId }),
        });
        onPedidoCreated(result.data);
        if (result.stock_warnings?.length > 0) {
          result.stock_warnings.forEach((w) => toast.warning(w, { duration: 5000 }));
        } else {
          const ofertaMsg = ofertaNombre ? ` 🏷️ ${ofertaNombre}` : "";
          toast.success(`Pedido iniciado${ofertaMsg}`);
        }
      } else {
        const result = await addPedidoItem(pedido.id, itemData);
        onPedidoUpdated(result.data);
        const nombre = (producto.descripcion || "Producto")?.substring(0, 28);
        const ofertaMsg = ofertaNombre ? ` 🏷️ ${ofertaNombre}` : "";
        if (result.stock_warning) {
          toast.warning(`${nombre} agregado - ${result.stock_warning}`);
        } else {
          toast.success(`${nombre} agregado${ofertaMsg}`);
        }
      }
      if (fromModal) setDetailProduct(null);
    } catch (err) {
      toast.error(err?.response?.data?.message || "Error al agregar producto");
    } finally {
      setAdding(null);
    }
  };

  const fmt = (price) =>
    (Number(price) || 0).toLocaleString("es-PY", { maximumFractionDigits: 0 });

  const showSmartSections = query.length < 2 && !loading && !categoriaId;
  const showCategoryBrowse = query.length < 2 && !!categoriaId;
  const showSearchResults = query.length >= 2;

  const displayProducts =
    showCategoryBrowse || showSearchResults ? productos : [];

  return (
    <PanelWrapper>
      {/* Buscador */}
      <SearchArea>
        <SearchBox>
          <Icon icon="mdi:magnify" width={20} />
          <input
            id="catalog-search-input"
            ref={inputRef}
            value={query}
            onChange={handleChange}
            placeholder="Buscar productos (F2)..."
            autoComplete="off"
          />
          {loading && <SpinIcon><Icon icon="mdi:loading" width={18} /></SpinIcon>}
          {query && !loading && (
            <ClearBtn
              onClick={() => {
                setQuery("");
                setProductos([]);
                inputRef.current?.focus();
              }}
            >
              <Icon icon="mdi:close" width={16} />
            </ClearBtn>
          )}
        </SearchBox>

        {/* Lista de precios del cliente */}
        {listaPrecios && (
          <ListaBanner>
            <Icon icon="lucide:tag" width={12} />
            Lista de precios activa:
            <ListaBannerName>{listaPrecios.nombre}</ListaBannerName>
            {listaPrecios.moneda && listaPrecios.moneda !== "PYG" && (
              <ListaBannerCurrency>{listaPrecios.moneda}</ListaBannerCurrency>
            )}
          </ListaBanner>
        )}

        {/* Tabs Frecuentes / Top ventas / Ofertas — solo cuando no hay filtro activo */}
        {showSmartSections && (frecuentes.length > 0 || topVentas.length > 0 || ofertas.length > 0) && (
          <TabBar>
            <Tab $active={activeTab === "buscar"} onClick={() => setActiveTab("buscar")}>
              <Icon icon="lucide:search" width={13} />
              Buscar
            </Tab>
            {frecuentes.length > 0 && (
              <Tab $active={activeTab === "frecuentes"} onClick={() => setActiveTab("frecuentes")}>
                <Icon icon="lucide:star" width={13} />
                Frecuentes ({frecuentes.length})
              </Tab>
            )}
            {topVentas.length > 0 && (
              <Tab $active={activeTab === "top"} onClick={() => setActiveTab("top")}>
                <Icon icon="lucide:trending-up" width={13} />
                Top ventas ({topVentas.length})
              </Tab>
            )}
            {ofertas.length > 0 && (
              <Tab $active={activeTab === "ofertas"} onClick={() => setActiveTab("ofertas")}>
                <Icon icon="lucide:sparkles" width={13} />
                Ofertas ({ofertas.length})
              </Tab>
            )}
          </TabBar>
        )}

        {(showSearchResults || showCategoryBrowse) && !loading && (
          <ResultBar>
            {categoriaId && (
              <ActiveCatChip
                onClick={() => {
                  setCategoriaId(null);
                  setProductos([]);
                }}
              >
                <Icon icon="lucide:x" width={11} />
                {categorias.find((c) => c.id === categoriaId)?.descripcion || "Categoría"}
              </ActiveCatChip>
            )}
            {displayProducts.length > 0 && (
              <span>{displayProducts.length} productos</span>
            )}
          </ResultBar>
        )}
      </SearchArea>

      {/* Grid de productos */}
      <ProductGrid>
        {/* Estado inicial — buscar */}
        {showSmartSections && activeTab === "buscar" && (
          <EmptyHint>
            <Icon icon="mdi:package-variant-closed" width={48} />
            <EmptyTitle>Catálogo de productos</EmptyTitle>
            <EmptyText>Busca por nombre, código o código de barras</EmptyText>
            <ShortcutRow>
              <kbd>F2</kbd> buscar &nbsp;·&nbsp; <kbd>Tab</kbd> navegar
              &nbsp;·&nbsp; <kbd>Enter</kbd> agregar
            </ShortcutRow>
          </EmptyHint>
        )}

        {/* Frecuentes — mismo formato que búsqueda */}
        {showSmartSections &&
          activeTab === "frecuentes" &&
          (frecuentes.length > 0 ? frecuentes.map((item, i) => {
            const prodId = item.producto_id || item.id;
            const imgUrl = item.url || item.imagenes?.[0]?.url || null;
            const hasPres = presentacionesDe(item).length > 0;
            const stockNum = item.stock_disponible ?? item.stock_total ?? null;
            const oferta = getOfertaForProduct(prodId);
            const catColor = item.categoria?.color;

            return (
              <ProductCard key={prodId} style={{ animationDelay: `${i * 0.025}s` }} onClick={() => setDetailProduct({ ...item, id: prodId })}>
                <ImageArea $color={catColor} $hasImg={!!imgUrl}>
                  {imgUrl ? (
                    <ProductImg src={imgUrl} alt={item.descripcion} loading="lazy" />
                  ) : (
                    <NoImgPlaceholder $color={catColor}>
                      <Icon icon="mdi:package-variant-closed" width={32} />
                    </NoImgPlaceholder>
                  )}
                  {item.es_padre && <CornerTag $color="#6366f1">Variantes</CornerTag>}
                  {oferta && <OfertaTag>OFERTA</OfertaTag>}
                  {stockNum !== null && stockNum <= 0 && <SinStockTag>Sin stock</SinStockTag>}
                  <SmartBadge $color="#f59e0b"><Icon icon="lucide:star" width={9} />{item.veces_comprado}×</SmartBadge>
                </ImageArea>
                <CardBody>
                  <ProdName title={item.descripcion}>{item.descripcion}</ProdName>
                  {item.cod_producto && <ProdCode>{item.cod_producto}</ProdCode>}
                  {oferta && <OfertaBadgeInline>OFERTA</OfertaBadgeInline>}
                  <PriceRow>
                    <PriceCol>
                      {oferta && <OldPr>₲ {fmt(item.precio)}</OldPr>}
                      <MainPr $disc={!!oferta}>
                        ₲{" "}
                        {oferta?.tipo === "descuento_porcentaje" ? fmt(Number(item.precio) * (1 - oferta.valor / 100))
                          : oferta?.tipo === "descuento_monto" ? fmt(Math.max(0, Number(item.precio) - oferta.valor))
                          : oferta?.tipo === "precio_especial" ? fmt(oferta.valor) : fmt(item.precio)}
                      </MainPr>
                    </PriceCol>
                    <QuickAddBtn onClick={(e) => { e.stopPropagation(); handleAddProduct(item); }} disabled={adding === prodId} title="Agregar">
                      {adding === prodId ? <Icon icon="mdi:loading" width={16} className="spin" /> : <Icon icon="mdi:plus" width={16} />}
                    </QuickAddBtn>
                  </PriceRow>
                  {hasPres && (
                    <PresentacionesRow>
                      {presentacionesDe(item).map((pres) => (
                        <PresBtn key={pres.id} onClick={(e) => { e.stopPropagation(); handleAddProduct(item, pres); }} disabled={adding === prodId + pres.id}>
                          {adding === prodId + pres.id ? <Icon icon="mdi:loading" width={12} className="spin" /> : (
                            <><span>{pres.abreviatura || pres.nombre?.substring(0, 5)}</span>{pres.precio && Number(pres.precio) > 0 && <PresPrice>₲{fmt(pres.precio)}</PresPrice>}</>
                          )}
                        </PresBtn>
                      ))}
                    </PresentacionesRow>
                  )}
                </CardBody>
              </ProductCard>
            );
          }) : (
            <EmptyHint><Icon icon="lucide:star" width={36} /><EmptyText>Sin productos frecuentes</EmptyText></EmptyHint>
          ))}

        {/* Top ventas — mismo formato que búsqueda */}
        {showSmartSections &&
          activeTab === "top" &&
          (topVentas.length > 0 ? topVentas.map((item, i) => {
            const prodId = item.producto_id || item.id;
            const imgUrl = item.url || item.imagenes?.[0]?.url || null;
            const hasPres = presentacionesDe(item).length > 0;
            const stockNum = item.stock_disponible ?? item.stock_total ?? null;
            const oferta = getOfertaForProduct(prodId);
            const catColor = item.categoria?.color;

            return (
              <ProductCard key={prodId} style={{ animationDelay: `${i * 0.025}s` }} onClick={() => setDetailProduct({ ...item, id: prodId })}>
                <ImageArea $color={catColor} $hasImg={!!imgUrl}>
                  {imgUrl ? (
                    <ProductImg src={imgUrl} alt={item.descripcion} loading="lazy" />
                  ) : (
                    <NoImgPlaceholder $color={catColor}>
                      <Icon icon="mdi:package-variant-closed" width={32} />
                    </NoImgPlaceholder>
                  )}
                  {item.es_padre && <CornerTag $color="#6366f1">Variantes</CornerTag>}
                  {oferta && <OfertaTag>OFERTA</OfertaTag>}
                  {stockNum !== null && stockNum <= 0 && <SinStockTag>Sin stock</SinStockTag>}
                  <SmartBadge $color="#10b981"><Icon icon="lucide:trending-up" width={9} />{item.veces_vendido}×</SmartBadge>
                </ImageArea>
                <CardBody>
                  <ProdName title={item.descripcion}>{item.descripcion}</ProdName>
                  {item.cod_producto && <ProdCode>{item.cod_producto}</ProdCode>}
                  {oferta && <OfertaBadgeInline>OFERTA</OfertaBadgeInline>}
                  <PriceRow>
                    <PriceCol>
                      {oferta && <OldPr>₲ {fmt(item.precio)}</OldPr>}
                      <MainPr $disc={!!oferta}>
                        ₲{" "}
                        {oferta?.tipo === "descuento_porcentaje" ? fmt(Number(item.precio) * (1 - oferta.valor / 100))
                          : oferta?.tipo === "descuento_monto" ? fmt(Math.max(0, Number(item.precio) - oferta.valor))
                          : oferta?.tipo === "precio_especial" ? fmt(oferta.valor) : fmt(item.precio)}
                      </MainPr>
                    </PriceCol>
                    <QuickAddBtn onClick={(e) => { e.stopPropagation(); handleAddProduct(item); }} disabled={adding === prodId} title="Agregar">
                      {adding === prodId ? <Icon icon="mdi:loading" width={16} className="spin" /> : <Icon icon="mdi:plus" width={16} />}
                    </QuickAddBtn>
                  </PriceRow>
                  {hasPres && (
                    <PresentacionesRow>
                      {presentacionesDe(item).map((pres) => (
                        <PresBtn key={pres.id} onClick={(e) => { e.stopPropagation(); handleAddProduct(item, pres); }} disabled={adding === prodId + pres.id}>
                          {adding === prodId + pres.id ? <Icon icon="mdi:loading" width={12} className="spin" /> : (
                            <><span>{pres.abreviatura || pres.nombre?.substring(0, 5)}</span>{pres.precio && Number(pres.precio) > 0 && <PresPrice>₲{fmt(pres.precio)}</PresPrice>}</>
                          )}
                        </PresBtn>
                      ))}
                    </PresentacionesRow>
                  )}
                </CardBody>
              </ProductCard>
            );
          }) : (
            <EmptyHint><Icon icon="lucide:trending-up" width={36} /><EmptyText>Sin productos top</EmptyText></EmptyHint>
          ))}

        {/* Ofertas activas — muestra cada oferta con sus productos */}
        {showSmartSections && activeTab === "ofertas" && (
          ofertas.length > 0 ? ofertas.map((o, i) => {
            // Extraer productos de aplicaciones (soporta aplica_a="producto" y legacy producto_id)
            const prodApps = (o.aplicaciones || []).filter((a) =>
              (a.aplica_a === "producto" && a.referencia_id) || a.producto_id
            );
            const isGlobal = (o.aplicaciones || []).some((a) => a.aplica_a === "todos") ||
              (o.aplicaciones || []).length === 0;
            const fmtDisc = o.tipo === "descuento_porcentaje"
              ? `${o.valor}% OFF`
              : o.tipo === "descuento_monto"
                ? `₲${fmt(o.valor)} OFF`
                : `Precio especial ₲${fmt(o.valor)}`;
            const fechaFin = o.fecha_fin
              ? new Date(o.fecha_fin).toLocaleDateString("es-PY", { day: "2-digit", month: "short" })
              : null;

            return (
              <OfertaSection key={o.id} style={{ animationDelay: `${i * 0.04}s` }}>
                <OfertaHeader>
                  <OfertaHeaderLeft>
                    <OfertaBadgeInline>OFERTA</OfertaBadgeInline>
                    <OfertaHeaderTitle>{o.nombre}</OfertaHeaderTitle>
                  </OfertaHeaderLeft>
                  <OfertaHeaderRight>
                    <OfertaDiscountBig>{fmtDisc}</OfertaDiscountBig>
                    {fechaFin && <OfertaExpiry>Hasta {fechaFin}</OfertaExpiry>}
                  </OfertaHeaderRight>
                </OfertaHeader>
                {o.descripcion && <OfertaDesc>{o.descripcion}</OfertaDesc>}
                {prodApps.length > 0 ? (
                  <OfertaProductList>
                    {prodApps.map((a) => {
                      const prodId = a.referencia_id || a.producto_id;
                      const resolved = ofertaProductos[prodId];
                      const prodName = resolved?.descripcion || a.producto?.descripcion || a.descripcion || "Producto";
                      const prodData = resolved || { id: prodId, producto_id: prodId, descripcion: prodName };
                      const prodImg = resolved?.imagenes?.[0]?.url || resolved?.url || null;
                      return (
                        <OfertaProductItem
                          key={prodId}
                          onClick={() => setDetailProduct(prodData)}
                        >
                          <OfertaProdInfo>
                            {prodImg ? (
                              <OfertaProdImg src={prodImg} alt={prodName} />
                            ) : (
                              <Icon icon="mdi:package-variant-closed" width={14} />
                            )}
                            <span>{prodName}</span>
                          </OfertaProdInfo>
                          <QuickAddBtn
                            onClick={(e) => {
                              e.stopPropagation();
                              if (resolved) {
                                handleAddProduct(resolved);
                              } else {
                                // Si no tenemos data completa, abrir detalle
                                setDetailProduct(prodData);
                              }
                            }}
                            disabled={adding === prodId}
                            title="Agregar"
                          >
                            {adding === prodId
                              ? <Icon icon="mdi:loading" width={14} className="spin" />
                              : <Icon icon="mdi:plus" width={14} />}
                          </QuickAddBtn>
                        </OfertaProductItem>
                      );
                    })}
                  </OfertaProductList>
                ) : isGlobal ? (
                  <OfertaAllProducts>
                    <Icon icon="lucide:info" width={12} />
                    Aplica a todos los productos
                  </OfertaAllProducts>
                ) : null}
              </OfertaSection>
            );
          }) : (
            <EmptyHint><Icon icon="lucide:tag" width={36} /><EmptyText>Sin ofertas activas</EmptyText></EmptyHint>
          )
        )}

        {/* Sin resultados */}
        {(showSearchResults || showCategoryBrowse) &&
          displayProducts.length === 0 &&
          !loading && (
            <EmptyHint>
              <Icon icon="mdi:magnify-close" width={40} />
              <EmptyText>
                {showSearchResults
                  ? `Sin resultados para "${query}"`
                  : "Sin productos en esta categoría"}
              </EmptyText>
            </EmptyHint>
          )}

        {/* Loading skeleton */}
        {loading && (
          <>
            {[...Array(6)].map((_, i) => (
              <SkeletonCard key={i} style={{ animationDelay: `${i * 0.05}s` }} />
            ))}
          </>
        )}

        {/* Resultados — búsqueda o categoría */}
        {!loading &&
          displayProducts.map((prod, i) => {
            const imgUrl = prod.url || prod.imagenes?.[0]?.url || null;
            const hasPresentaciones = presentacionesDe(prod).length > 0;
            const esParent = prod.es_padre;
            const stockNum = prod.stock_disponible ?? prod.stock_total ?? null;
            const oferta = getOfertaForProduct(prod.id);
            const catColor = prod.categoria?.color;

            return (
              <ProductCard
                key={prod.id}
                style={{ animationDelay: `${i * 0.025}s` }}
                onClick={() => setDetailProduct(prod)}
              >
                <ImageArea $color={catColor} $hasImg={!!imgUrl}>
                  {imgUrl ? (
                    <ProductImg src={imgUrl} alt={prod.descripcion} loading="lazy" />
                  ) : (
                    <NoImgPlaceholder $color={catColor}>
                      <Icon icon="mdi:package-variant-closed" width={32} />
                    </NoImgPlaceholder>
                  )}
                  {esParent && <CornerTag $color="#6366f1">Variantes</CornerTag>}
                  {oferta && <OfertaTag>OFERTA</OfertaTag>}
                  {stockNum !== null && stockNum <= 0 && (
                    <SinStockTag>Sin stock</SinStockTag>
                  )}
                </ImageArea>

                <CardBody>
                  <ProdName title={prod.descripcion}>{prod.descripcion}</ProdName>
                  {prod.cod_producto && (
                    <ProdCode>{prod.cod_producto}</ProdCode>
                  )}

                  {oferta && <OfertaBadgeInline>OFERTA</OfertaBadgeInline>}

                  <PriceRow>
                    <PriceCol>
                      {oferta && <OldPr>₲ {fmt(prod.precio)}</OldPr>}
                      <MainPr $disc={!!oferta}>
                        ₲{" "}
                        {oferta?.tipo === "descuento_porcentaje"
                          ? fmt(Number(prod.precio) * (1 - oferta.valor / 100))
                          : oferta?.tipo === "descuento_monto"
                            ? fmt(Math.max(0, Number(prod.precio) - oferta.valor))
                            : oferta?.tipo === "precio_especial"
                              ? fmt(oferta.valor)
                              : fmt(prod.precio)}
                      </MainPr>
                    </PriceCol>
                    <QuickAddBtn
                      onClick={(e) => {
                        e.stopPropagation();
                        handleAddProduct(prod);
                      }}
                      disabled={adding === prod.id}
                      title="Agregar unidad base"
                    >
                      {adding === prod.id
                        ? <Icon icon="mdi:loading" width={16} className="spin" />
                        : <Icon icon="mdi:plus" width={16} />}
                    </QuickAddBtn>
                  </PriceRow>

                  {hasPresentaciones && (
                    <PresentacionesRow>
                      {(prod.producto_presentaciones || prod.presentaciones || [])
                        .filter((p) => p.active !== false)
                        .map((pres) => (
                          <PresBtn
                            key={pres.id}
                            onClick={(e) => {
                              e.stopPropagation();
                              handleAddProduct(prod, pres);
                            }}
                            disabled={adding === prod.id + pres.id}
                          >
                            {adding === prod.id + pres.id ? (
                              <Icon icon="mdi:loading" width={12} className="spin" />
                            ) : (
                              <>
                                <span>{pres.abreviatura || pres.nombre?.substring(0, 5)}</span>
                                {pres.precio && Number(pres.precio) > 0 && (
                                  <PresPrice>₲{fmt(pres.precio)}</PresPrice>
                                )}
                              </>
                            )}
                          </PresBtn>
                        ))}
                    </PresentacionesRow>
                  )}
                </CardBody>
              </ProductCard>
            );
          })}
      </ProductGrid>

      {/* Barra de categorías */}
      {categorias.length > 0 && (
        <CatBar>
          <CatPill $active={!categoriaId} onClick={() => handleCategoriaClick(null)}>
            <Icon icon="mdi:apps" width={14} />
            Todos
          </CatPill>
          {categorias.map((cat) => (
            <CatPill
              key={cat.id}
              $active={categoriaId === cat.id}
              $color={cat.color}
              onClick={() => handleCategoriaClick(cat.id)}
            >
              {cat.icono ? (
                <Icon icon={cat.icono} width={14} />
              ) : (
                <CatDot $color={cat.color} />
              )}
              {cat.descripcion}
            </CatPill>
          ))}
        </CatBar>
      )}

      {/* Modal de detalle */}
      {detailProduct && (
        <ProductDetailModal
          producto={detailProduct}
          oferta={getOfertaForProduct(detailProduct.id)}
          contexto={contexto}
          adding={adding === detailProduct.id || adding?.startsWith?.(detailProduct.id)}
          onAdd={(prod, pres) => handleAddProduct(prod, pres, true)}
          onClose={() => setDetailProduct(null)}
        />
      )}
    </PanelWrapper>
  );
}

const fadeIn = keyframes`from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}`;
const spin = keyframes`to{transform:rotate(360deg)}`;
const shimmer = keyframes`0%{background-position:-400px 0}100%{background-position:400px 0}`;

/* ── Layout ── */
const PanelWrapper = styled.div`
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  border-right: 1px solid ${(p) => p.theme.borderColor};
`;

const SearchArea = styled.div`
  padding: 0.75rem 1rem 0.5rem;
  border-bottom: 1px solid ${(p) => p.theme.borderColor};
  background: ${(p) => p.theme.bg2};
  flex-shrink: 0;
`;

const SearchBox = styled.div`
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  background: ${(p) => p.theme.inputBg};
  border: 1.5px solid ${(p) => p.theme.inputBorder};
  border-radius: 10px;
  transition: border-color 0.2s;
  color: ${(p) => p.theme.textSecondary};
  &:focus-within {
    border-color: ${(p) => p.theme.primary};
    box-shadow: 0 0 0 3px ${(p) => p.theme.primary}18;
  }
  input {
    flex: 1;
    border: none;
    background: transparent;
    font-size: 0.875rem;
    color: ${(p) => p.theme.text};
    outline: none;
    font-weight: 500;
    &::placeholder { color: ${(p) => p.theme.textSecondary}; font-weight: 400; }
  }
  .spin { animation: ${spin} 1s linear infinite; }
`;

const SpinIcon = styled.span`
  color: ${(p) => p.theme.primary};
  display: flex;
  animation: ${spin} 1s linear infinite;
`;

const ClearBtn = styled.button`
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px;
  color: ${(p) => p.theme.textSecondary};
  display: flex;
  border-radius: 4px;
  &:hover { color: ${(p) => p.theme.text}; }
`;

const TabBar = styled.div`
  display: flex;
  gap: 2px;
  margin-top: 8px;
  background: ${(p) => p.theme.bgAlpha};
  border-radius: 8px;
  padding: 3px;
`;

const Tab = styled.button`
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1;
  justify-content: center;
  padding: 5px 8px;
  border: none;
  border-radius: 6px;
  font-size: 0.6875rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s;
  background: ${(p) => (p.$active ? p.theme.bg2 : "transparent")};
  color: ${(p) => (p.$active ? p.theme.primary : p.theme.textSecondary)};
  box-shadow: ${(p) => (p.$active ? "0 1px 3px rgba(0,0,0,0.08)" : "none")};
  &:hover { color: ${(p) => p.theme.primary}; }
`;

const ResultBar = styled.div`
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0.25rem 0.25rem 0;
  min-height: 1.25rem;
  font-size: 0.6875rem;
  color: ${(p) => p.theme.textSecondary};
`;

const ActiveCatChip = styled.button`
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.625rem;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 10px;
  background: ${(p) => p.theme.primary}18;
  color: ${(p) => p.theme.primary};
  border: 1px solid ${(p) => p.theme.primary}30;
  cursor: pointer;
  transition: all 0.15s;
  &:hover { background: ${(p) => p.theme.primary}28; }
`;

/* ── Grid de productos ── */
const ProductGrid = styled.div`
  flex: 1;
  overflow-y: auto;
  padding: 0.75rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 0.625rem;
  align-content: start;
`;

/* ── Card de producto ── */
const ProductCard = styled.div`
  background: ${(p) => p.theme.bg2};
  border: 1px solid ${(p) => p.theme.borderColor};
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
  animation: ${fadeIn} 0.3s ease both;
  &:hover {
    border-color: ${(p) => p.theme.primary}60;
    box-shadow: 0 4px 20px ${(p) => p.theme.primary}14;
    transform: translateY(-2px);
  }
`;

const ImageArea = styled.div`
  position: relative;
  height: 130px;
  background: ${(p) =>
    p.$hasImg ? p.theme.bgAlpha : (p.$color ? p.$color + "18" : p.theme.bgAlpha)};
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
`;

const ProductImg = styled.img`
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
  ${ProductCard}:hover & {
    transform: scale(1.06);
  }
`;

const NoImgPlaceholder = styled.div`
  color: ${(p) => p.$color || p.theme.textSecondary};
  opacity: ${(p) => (p.$color ? 0.5 : 0.2)};
`;

const CornerTag = styled.span`
  position: absolute;
  top: 6px;
  right: 6px;
  font-size: 0.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: ${(p) => p.$color || p.theme.primary};
  color: #fff;
  padding: 2px 5px;
  border-radius: 4px;
`;

const OfertaTag = styled.span`
  position: absolute;
  top: 6px;
  left: 6px;
  font-size: 0.5rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: #22c55e;
  color: #fff;
  padding: 3px 8px;
  border-radius: 4px;
`;

const OfertaBadgeInline = styled.span`
  display: inline-block;
  align-self: center;
  font-size: 0.5625rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 10px;
  border-radius: 4px;
  background: #22c55e;
  color: #fff;
  margin-bottom: 2px;
`;

/* ── Ofertas tab section ── */
const OfertaSection = styled.div`
  grid-column: 1 / -1;
  background: ${(p) => p.theme.bg2};
  border: 1px solid ${(p) => p.theme.borderColor};
  border-radius: 12px;
  padding: 0.875rem;
  animation: ${fadeIn} 0.3s ease both;
`;

const OfertaHeader = styled.div`
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
`;

const OfertaHeaderLeft = styled.div`
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
`;

const OfertaHeaderTitle = styled.span`
  font-size: 0.8125rem;
  font-weight: 700;
  color: ${(p) => p.theme.text};
`;

const OfertaHeaderRight = styled.div`
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  flex-shrink: 0;
`;

const OfertaDiscountBig = styled.span`
  font-size: 0.875rem;
  font-weight: 800;
  color: #22c55e;
`;

const OfertaExpiry = styled.span`
  font-size: 0.5625rem;
  color: ${(p) => p.theme.textSecondary};
`;

const OfertaDesc = styled.p`
  font-size: 0.6875rem;
  color: ${(p) => p.theme.textSecondary};
  margin: 0 0 8px;
  line-height: 1.3;
`;

const OfertaProductList = styled.div`
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 6px;
`;

const OfertaProductItem = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 8px;
  background: ${(p) => p.theme.bgAlpha};
  border: 1px solid ${(p) => p.theme.borderColor};
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
  &:hover {
    border-color: ${(p) => p.theme.primary}50;
    background: ${(p) => p.theme.primary}08;
  }
`;

const OfertaProdInfo = styled.div`
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.75rem;
  font-weight: 500;
  color: ${(p) => p.theme.text};
  min-width: 0;
  span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
`;

const OfertaProdImg = styled.img`
  width: 28px;
  height: 28px;
  border-radius: 6px;
  object-fit: cover;
  flex-shrink: 0;
`;

const OfertaAllProducts = styled.div`
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 8px;
  margin-top: 6px;
  font-size: 0.6875rem;
  color: ${(p) => p.theme.textSecondary};
  background: ${(p) => p.theme.bgAlpha};
  border-radius: 6px;
`;

const SmartBadge = styled.span`
  position: absolute;
  bottom: 6px;
  right: 6px;
  display: flex;
  align-items: center;
  gap: 2px;
  font-size: 0.5rem;
  font-weight: 700;
  background: ${(p) => p.$color || p.theme.primary};
  color: #fff;
  padding: 2px 5px;
  border-radius: 4px;
`;

const SinStockTag = styled.span`
  position: absolute;
  bottom: 6px;
  left: 6px;
  font-size: 0.5rem;
  font-weight: 700;
  text-transform: uppercase;
  background: #ef444488;
  color: #fff;
  padding: 2px 5px;
  border-radius: 4px;
`;

const CardBody = styled.div`
  padding: 0.5rem 0.625rem 0.625rem;
`;

const ProdName = styled.div`
  font-size: 0.75rem;
  font-weight: 600;
  color: ${(p) => p.theme.text};
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-bottom: 2px;
`;

const ProdCode = styled.div`
  font-size: 0.5625rem;
  font-family: "JetBrains Mono", monospace;
  color: ${(p) => p.theme.textSecondary};
  margin-bottom: 0.375rem;
`;

const PriceRow = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem;
`;

const PriceCol = styled.div`
  display: flex;
  flex-direction: column;
  gap: 1px;
`;

const OldPr = styled.span`
  font-size: 0.6rem;
  color: ${(p) => p.theme.textSecondary};
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
`;

const MainPr = styled.span`
  font-size: 0.9375rem;
  font-weight: 800;
  color: ${(p) => (p.$disc ? "#10b981" : p.theme.text)};
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
`;

const QuickAddBtn = styled.button`
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: ${(p) => p.theme.primary};
  color: #fff;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.15s;
  &:hover:not(:disabled) { filter: brightness(1.15); transform: scale(1.08); }
  &:disabled { opacity: 0.6; cursor: wait; }
  .spin { animation: ${spin} 1s linear infinite; }
`;

const PresentacionesRow = styled.div`
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-top: 0.375rem;
  padding-top: 0.375rem;
  border-top: 1px dashed ${(p) => p.theme.borderColor};
`;

const PresBtn = styled.button`
  display: flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.2rem 0.5rem;
  background: ${(p) => p.theme.bg6};
  border: 1px solid ${(p) => p.theme.primary}30;
  border-radius: 6px;
  font-size: 0.625rem;
  font-weight: 600;
  color: ${(p) => p.theme.primary};
  cursor: pointer;
  transition: all 0.15s;
  &:hover:not(:disabled) { background: ${(p) => p.theme.primary}; color: #fff; }
  &:disabled { opacity: 0.5; cursor: wait; }
  .spin { animation: ${spin} 1s linear infinite; }
`;

const PresPrice = styled.span`
  font-size: 0.5625rem;
  opacity: 0.8;
  font-variant-numeric: tabular-nums;
`;

/* ── Smart cards (frecuentes / top) ── */
/* ── Skeleton ── */
const SkeletonCard = styled.div`
  height: 200px;
  border-radius: 12px;
  background: linear-gradient(
    90deg,
    ${(p) => p.theme.bgAlpha} 25%,
    ${(p) => p.theme.bg6} 50%,
    ${(p) => p.theme.bgAlpha} 75%
  );
  background-size: 800px 100%;
  animation: ${shimmer} 1.4s infinite linear, ${fadeIn} 0.3s ease both;
`;

/* ── Barra de categorías ── */
const CatBar = styled.div`
  display: flex;
  gap: 6px;
  padding: 8px 12px;
  border-top: 1px solid ${(p) => p.theme.borderColor};
  background: ${(p) => p.theme.bg2};
  overflow-x: auto;
  flex-shrink: 0;
  scrollbar-width: none;
  &::-webkit-scrollbar { display: none; }
`;

const CatPill = styled.button`
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 12px;
  border-radius: 20px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.15s;
  border: 1.5px solid
    ${(p) =>
      p.$active
        ? (p.$color || p.theme.primary)
        : p.theme.borderColor};
  background: ${(p) =>
    p.$active
      ? (p.$color ? p.$color + "20" : p.theme.primary + "15")
      : "transparent"};
  color: ${(p) =>
    p.$active
      ? (p.$color || p.theme.primary)
      : p.theme.textSecondary};
  &:hover {
    border-color: ${(p) => p.$color || p.theme.primary};
    color: ${(p) => p.$color || p.theme.primary};
    background: ${(p) => (p.$color ? p.$color + "15" : p.theme.primary + "10")};
  }
`;

const CatDot = styled.span`
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: ${(p) => p.$color || p.theme.textSecondary};
  flex-shrink: 0;
`;

/* ── Lista de precios banner ── */
const ListaBanner = styled.div`
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  padding: 4px 8px;
  background: ${(p) => p.theme.primary}12;
  border: 1px solid ${(p) => p.theme.primary}30;
  border-radius: 6px;
  font-size: 0.625rem;
  font-weight: 600;
  color: ${(p) => p.theme.textSecondary};
`;

const ListaBannerName = styled.span`
  font-weight: 700;
  color: ${(p) => p.theme.primary};
`;

const ListaBannerCurrency = styled.span`
  margin-left: auto;
  font-size: 0.5625rem;
  background: ${(p) => p.theme.primary}20;
  color: ${(p) => p.theme.primary};
  padding: 1px 5px;
  border-radius: 4px;
  font-weight: 700;
`;

/* ── Oferta cards (tab ofertas) ── */
/* ── Empty / hints ── */
const EmptyHint = styled.div`
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 3rem 1rem;
  color: ${(p) => p.theme.textSecondary};
  text-align: center;
  animation: ${fadeIn} 0.4s ease;
`;

const EmptyTitle = styled.div`
  font-size: 1rem;
  font-weight: 700;
  color: ${(p) => p.theme.text};
`;

const EmptyText = styled.div`
  font-size: 0.8125rem;
  max-width: 300px;
  line-height: 1.4;
`;

const ShortcutRow = styled.div`
  font-size: 0.6875rem;
  opacity: 0.6;
  margin-top: 0.5rem;
  kbd {
    display: inline-block;
    padding: 0.1rem 0.3rem;
    background: ${(p) => p.theme.bgAlpha};
    border: 1px solid ${(p) => p.theme.borderColor};
    border-radius: 3px;
    font-size: 0.5625rem;
    font-weight: 700;
    font-family: monospace;
  }
`;
