'use client';
import { useState, useEffect, useCallback, forwardRef, useImperativeHandle } from 'react';
import { productsApi, pricingApi, inventoryApi, taxApi, type TaxRate } from '@/lib/api-client';
import type { ProductVariant } from '@/types';

/** Imperative handle exposed by PriceStockSection to ProductEditor.
 *  All persistence for this section is centralized in saveAll() and called
 *  by the parent's main "Guardar cambios" button (F-137). */
export interface PriceStockHandle {
  /** Persist price, stock, EAN, peso unitario and compra mínima.
   *  Per-group failures are caught and reported; the function never throws
   *  for a single-group failure, only for catastrophic errors (e.g., no
   *  variant id available). Returns per-group success map. */
  saveAll(): Promise<{
    price: boolean;
    stock: boolean;
    ean: boolean;
    meta: boolean;
  }>;
}

/** Convierte céntimos a string de euros ("12.00"). */
function centsToEur(cents: number): string {
  return (cents / 100).toFixed(2);
}

/** Convierte una entrada de usuario ("12", "12,30", "12.30") a céntimos. */
function eurToCents(input: string): number {
  if (!input) return 0;
  const normalized = String(input).replace(',', '.');
  const val = parseFloat(normalized);
  if (isNaN(val)) return 0;
  return Math.round(val * 100);
}

type VatRate = 'general' | 'reduced' | 'super-reduced';

/**
 * Gestión de precio, stock y EAN a nivel de producto (F-108).
 * El modelo interno conserva una única variante por producto; esta sección
 * opera siempre sobre la primera variante.
 */
export const PriceStockSection = forwardRef<PriceStockHandle, { productId?: string }>(function PriceStockSection(
  { productId },
  ref,
) {
  const pending = !productId;
  const [variant, setVariant] = useState<ProductVariant | null>(null);
  const [loadError, setLoadError] = useState('');

  // Precio
  const [gross, setGross] = useState('');
  const [net, setNet] = useState('');
  const [cost, setCost] = useState('');
  const [offer, setOffer] = useState('');
  const [vatRate, setVatRate] = useState<VatRate>('general');
  const [taxRates, setTaxRates] = useState<TaxRate[]>([]);
  const [priceMsg, setPriceMsg] = useState('');

  // Stock
  const [stock, setStock] = useState('');
  const [stockMsg, setStockMsg] = useState('');

  // EAN
  const [ean, setEan] = useState('');
  const [eanMsg, setEanMsg] = useState('');

  // Peso y compra mínima (F-102)
  // Peso se gestiona en gramos. La UI es un <input type="number" list="…"> con
  // <datalist> que ofrece los presets como sugerencias pero permite cualquier
  // valor (custom) sin necesidad de un segundo campo (F-133). Se convierte a
  // kg al persistir.
  const WEIGHT_PRESETS_GR = [100, 150, 200, 250, 300, 350, 500, 740] as const;
  const [unitWeightGr, setUnitWeightGr] = useState('1');
  const [, setCustomWeightGr] = useState(''); // legacy, mantenida para no romper el handler
  const [minPurchaseQty, setMinPurchaseQty] = useState('1');
  const [metaMsg, setMetaMsg] = useState('');

  useEffect(() => {
    taxApi.list().then(({ items }) => setTaxRates(items.filter((r) => r.active))).catch(() => {});
  }, []);

  useEffect(() => {
    if (!productId) return; // pending: nothing to load yet
    const pid = productId;
    let cancelled = false;
    productsApi
      .get(pid)
      .then((product) => {
        if (cancelled) return;
        const kg = (product as unknown as { unitWeightKg?: number }).unitWeightKg ?? 1;
        setUnitWeightGr(String(Math.round(kg * 1000)));
        setCustomWeightGr('');
        setMinPurchaseQty(String((product as unknown as { minPurchaseQty?: number }).minPurchaseQty ?? 1));
      })
      .catch(() => {});
    productsApi
      .getVariants(pid)
      .then(async ({ items }) => {
        if (cancelled) return;
        const first = items?.[0] ?? null;
        setVariant(first);
        setEan(first?.ean ?? '');
        if (!first) return;
        // Precio vigente
        try {
          const price = await pricingApi.getVariantPrice(first.id);
          if (cancelled) return;
          const rateP = taxRates.find((r) => r.appliesTo === price.vatRate)?.ratePercent ?? 21;
          setVatRate(price.vatRate);
          setNet(centsToEur(price.netUnitAmountCents));
          setGross(centsToEur(Math.round(price.netUnitAmountCents * (1 + rateP / 100))));
          setCost(price.costCents !== null ? centsToEur(price.costCents) : '');
          setOffer(price.offerCents !== null ? centsToEur(price.offerCents) : '');
        } catch {
          if (!cancelled) { setGross(''); setNet(''); }
        }
        // Stock disponible
        try {
          const availability = await inventoryApi.getAvailability(first.id);
          if (!cancelled) setStock(String(availability.availableQuantity));
        } catch {
          if (!cancelled) setStock('0');
        }
      })
      .catch(() => {
        if (!cancelled) setLoadError('No se pudieron cargar los datos del producto');
      });
    return () => { cancelled = true; };
    // taxRates solo afecta al cálculo inicial del bruto; se recalcula al guardar.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [productId]);

  const rateFor = useCallback(
    (vr: VatRate) => taxRates.find((r) => r.appliesTo === vr)?.ratePercent ?? 21,
    [taxRates],
  );

  const onGrossChange = (raw: string) => {
    setGross(raw);
    setNet(centsToEur(Math.round(eurToCents(raw) / (1 + rateFor(vatRate) / 100))));
  };

  const onNetChange = (raw: string) => {
    setNet(raw);
    setGross(centsToEur(Math.round(eurToCents(raw) * (1 + rateFor(vatRate) / 100))));
  };

  const onVatChange = (vr: VatRate) => {
    setVatRate(vr);
    const rateP = rateFor(vr);
    setGross(centsToEur(Math.round(eurToCents(net) * (1 + rateP / 100))));
  };

  /** Persist PVP/IVA/Coste/Oferta/Neto via pricingApi. Returns ok=false on
   *  validation or network failure; sets priceMsg with the error text so
   *  the caller can surface it next to the section heading. */
  const savePrice = async (): Promise<boolean> => {
    if (!variant) return false;
    const grossCents = eurToCents(gross);
    const netCents = Math.round(grossCents / (1 + rateFor(vatRate) / 100));
    if (grossCents < 0 || netCents < 0) { setPriceMsg('Precio inválido'); return false; }
    const offerCents = offer.trim() ? eurToCents(offer) : null;
    const costCents = cost.trim() ? eurToCents(cost) : null;
    if (offerCents !== null && offerCents < 0) { setPriceMsg('Oferta inválida'); return false; }
    if (costCents !== null && costCents < 0) { setPriceMsg('Coste inválido'); return false; }
    try {
      const updated = await pricingApi.setVariantPrice(variant.id, netCents, vatRate, offerCents, costCents);
      setNet(centsToEur(updated.netUnitAmountCents));
      setPriceMsg('');
      return true;
    } catch (error) {
      setPriceMsg(error instanceof Error ? error.message : 'Error al guardar precio');
      return false;
    }
  };

  const saveStock = async (): Promise<boolean> => {
    if (!variant) return false;
    const qty = parseInt(stock, 10);
    if (isNaN(qty) || qty < 0) {
      setStockMsg('Stock inválido');
      return false;
    }
    try {
      const result = await inventoryApi.setStock(variant.id, qty);
      setStock(String(result.available));
      setStockMsg('');
      return true;
    } catch (error) {
      setStockMsg(error instanceof Error ? error.message : 'Error al guardar stock');
      return false;
    }
  };

  const saveEan = async (): Promise<boolean> => {
    if (!variant) return false;
    const next = ean.trim();
    if (next === (variant.ean ?? '')) return true; // no-op, count as success
    try {
      const updated = await productsApi.updateVariant(productId as string, variant.id, { ean: next || null });
      setVariant((prev) => (prev ? { ...prev, ean: updated.ean } : prev));
      setEan(updated.ean ?? '');
      setEanMsg('');
      return true;
    } catch (error) {
      const msg = error instanceof Error
        ? (error.message.includes('409') ? 'EAN duplicado' : error.message)
        : 'Error al guardar EAN';
      setEanMsg(msg);
      return false;
    }
  };

  const saveProductMeta = async (): Promise<boolean> => {
    if (pending || !productId) return false;
    const gr = parseFloat(unitWeightGr.replace(',', '.'));
    const weight = gr / 1000;
    const minQty = parseInt(minPurchaseQty, 10);
    if (isNaN(gr) || gr <= 0 || gr > 100000) {
      setMetaMsg('Peso inválido');
      return false;
    }
    if (isNaN(minQty) || minQty < 1 || minQty > 999) {
      setMetaMsg('Compra mínima inválida');
      return false;
    }
    try {
      await productsApi.update(productId as string, { unitWeightKg: weight, minPurchaseQty: minQty });
      setMetaMsg('');
      return true;
    } catch (error) {
      setMetaMsg(error instanceof Error ? error.message : 'Error al guardar peso/compra mínima');
      return false;
    }
  };

  /** Resolve a variant id; in create flow the section's load effect may
   *  not have run yet, so we fetch it once on demand. Idempotent. */
  const ensureVariant = async (): Promise<ProductVariant | null> => {
    if (variant) return variant;
    if (!productId) return null;
    try {
      const { items } = await productsApi.getVariants(productId);
      const first = items?.[0] ?? null;
      if (first) setVariant(first);
      return first;
    } catch {
      return null;
    }
  };

  /** Imperative API exposed to ProductEditor. Called from the main
   *  "Guardar cambios" handler. Persists all four groups in sequence;
   *  per-group failures are caught and reported, never throw.
   *  The save* helpers close over the state values listed in the deps
   *  array, so the imperative handle always reflects the latest form
   *  contents. Including the helpers themselves would also work but
   *  recreates the handle on every render. */
  useImperativeHandle(ref, () => ({
    async saveAll() {
      setPriceMsg('');
      setStockMsg('');
      setEanMsg('');
      setMetaMsg('');
      // Ensure we have a variant id before any save attempts. If we don't,
      // every group fails and we report a single, clear error.
      const v = await ensureVariant();
      if (!v) {
        setPriceMsg('No hay variante asociada al producto todavía.');
        return { price: false, stock: false, ean: false, meta: false };
      }
      const [price, stockOk, ean, meta] = await Promise.all([
        savePrice(),
        saveStock(),
        saveEan(),
        saveProductMeta(),
      ]);
      return { price, stock: stockOk, ean, meta };
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps -- save* helpers close over the deps listed below; tracking them separately would recreate the handle on every render.
  }), [variant, productId, gross, net, cost, offer, vatRate, stock, ean, unitWeightGr, minPurchaseQty, taxRates]);

  if (loadError) {
    return <div className="p-4 bg-red-50 border border-red-200 rounded-xl text-sm text-red-700">{loadError}</div>;
  }

  if (!pending && !variant) {
    return (
      <div className="p-4 bg-amber-50 border border-amber-200 rounded-xl text-sm text-amber-800">
        ⚠️ Este producto aún no tiene datos internos de venta. Recarga la página para generarlos.
      </div>
    );
  }

  return (
    <div className="border border-gray-200 rounded-xl p-5 space-y-4 bg-gray-50/50">
      <div className="flex items-center justify-between">
        <h3 className="text-sm font-bold text-gray-900">Precio y stock</h3>
        <div className="flex items-center gap-3">
          {pending && (
            <span className="text-xs text-gray-400">Se guardará al crear el producto</span>
          )}
          {priceMsg && (
            <span className="text-xs text-red-600">{priceMsg}</span>
          )}
        </div>
      </div>

      <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">PVP (IVA incl.) €</label>
          <input
            type="text" inputMode="decimal" value={gross}
            onChange={(e) => onGrossChange(e.target.value)}
            placeholder="0.00"
            className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm font-semibold text-[#2D6A4F] focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
          />
        </div>
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">IVA</label>
          <select
            value={vatRate}
            onChange={(e) => onVatChange(e.target.value as VatRate)}
            className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
          >
            {taxRates.length === 0 && (
              <>
                <option value="general">21% (general)</option>
                <option value="reduced">10% (reducido)</option>
                <option value="super-reduced">4% (superreducido)</option>
              </>
            )}
            {taxRates.map((r) => (
              <option key={r.appliesTo} value={r.appliesTo}>{r.name} ({r.ratePercent}%)</option>
            ))}
          </select>
        </div>
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">Coste (sin IVA) €</label>
          <input
            type="text" inputMode="decimal" value={cost}
            onChange={(e) => setCost(e.target.value)}
            placeholder="0.00"
            className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
          />
        </div>
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">Oferta (IVA incl.) €</label>
          <input
            type="text" inputMode="decimal" value={offer}
            onChange={(e) => setOffer(e.target.value)}
            placeholder="—"
            className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
          />
        </div>
      </div>

      <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">Stock (uds.)</label>
          <div className="flex items-center gap-2">
            <input
              type="number" min={0} value={stock}
              onChange={(e) => setStock(e.target.value)}
              className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
            />
            {stockMsg && <span className="text-xs shrink-0 text-red-600">{stockMsg}</span>}
          </div>
        </div>
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">EAN</label>
          <div className="flex items-center gap-2">
            <input
              type="text" value={ean}
              onChange={(e) => setEan(e.target.value)}
              placeholder="8412345678901"
              className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm font-mono focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
            />
            {eanMsg && <span className="text-xs shrink-0 text-red-600">{eanMsg}</span>}
          </div>
        </div>
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">Neto (sin IVA) €</label>
          <input
            type="text" inputMode="decimal" value={net}
            onChange={(e) => onNetChange(e.target.value)}
            placeholder="calculado del PVP"
            className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
          />
        </div>
      </div>

      <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">Peso unitario (Gr)</label>
          {/* F-133: input único con datalist. El usuario puede escribir cualquier
              valor (custom) o elegir uno de los presets del desplegable nativo
              del navegador. Sin segundo campo separado, sin romper el grid. */}
          <input
            type="number"
            list="weight-presets-list"
            min={1}
            max={100000}
            value={unitWeightGr}
            onChange={(e) => {
              setUnitWeightGr(e.target.value);
              setCustomWeightGr('');
            }}
            placeholder="Gramos"
            className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
          />
          <datalist id="weight-presets-list">
            {WEIGHT_PRESETS_GR.map(g => (
              <option key={g} value={g} label={`${g} g`} />
            ))}
          </datalist>
        </div>
        <div>
          <label className="block text-xs font-semibold text-gray-600 mb-1">Compra mínima (uds.)</label>
          <div className="flex items-center gap-2">
            <input
              type="number" min={1} max={999} value={minPurchaseQty}
              onChange={(e) => setMinPurchaseQty(e.target.value)}
              className="w-full px-3 py-2 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none bg-white"
            />
            {metaMsg && <span className="text-xs shrink-0 text-red-600">{metaMsg}</span>}
          </div>
        </div>
        <div className="col-span-2 flex items-end">
          <p className="text-xs text-gray-400">
            El peso del pedido se calcula como cantidad × peso unitario y limita los métodos de envío disponibles.
            La compra mínima bloquea en la tienda los pedidos por debajo de esa cantidad.
          </p>
        </div>
      </div>
    </div>
  );
});
