import { MoneyDTO, PercentageDTO, QuantityDTO, SpainTaxCatalogProvider } from "@erp/core";
import { useMoney, usePercentage, useQuantity } from "@erp/core/hooks";
import { useMemo } from "react";

/**
 * Calcula subtotal, descuento, base imponible, impuestos y total de una línea de factura.
 * Trabaja con DTOs escalados (value+scale) como los del backend.
 */

type ItemShape = {
  quantity: QuantityDTO | null | undefined;
  unit_amount: MoneyDTO | null | undefined;
  discount_percentage?: PercentageDTO | null;
  tax_codes?: string[] | null;
};

// ⚠️ Devuelve todo en MoneyDTO manteniendo moneda/escala del unit_amount
export function useInvoiceItemSummary(item: ItemShape) {
  const {
    add,
    sub,
    multiply,
    percentage: moneyPct,
    fromNumber,
    isEmptyMoneyDTO,
    fallbackCurrency,
  } = useMoney();

  const { toNumber: qtyToNumber } = useQuantity();
  const { toNumber: pctToNumber } = usePercentage();

  // Cero monetario con la misma divisa/escala del unit_amount (fallback EUR/2)
  const zero = useMemo<MoneyDTO>(() => {
    const cur = item.unit_amount?.currency_code ?? fallbackCurrency;
    const sc = Number(item.unit_amount?.scale ?? 2);
    return fromNumber(0, cur as any, sc);
  }, [item.unit_amount?.currency_code, item.unit_amount?.scale, fromNumber, fallbackCurrency]);

  const taxCatalog = useMemo(() => SpainTaxCatalogProvider(), []);

  return useMemo(() => {
    // 1) Cantidad
    const qty = qtyToNumber(item.quantity); // 0 si null/DTO vacío

    // 2) Subtotal = quantity × unit_amount
    const unit = item.unit_amount && !isEmptyMoneyDTO(item.unit_amount) ? item.unit_amount : zero;
    const subtotal = multiply(unit, qty); // usa dinero.js, respeta escala

    // 3) Descuento
    const pctDTO = item.discount_percentage ?? ({ value: "", scale: "" } as PercentageDTO);
    const pct = pctToNumber(pctDTO); // 0 si vacío
    const discountAmount = pct !== 0 ? moneyPct(subtotal, pct) : zero;

    // 4) Base imponible = subtotal - descuento
    const baseAmount = sub(subtotal, discountAmount);

    // 5) Impuestos (cada código es un % sobre base; soporta negativos)
    const taxesBreakdown =
      item.tax_codes?.map((code) => {
        const maybe = taxCatalog.findByCode(code);
        if (maybe.isNone()) return { label: code, percentage: 0, amount: zero };

        const tax = maybe.unwrap()!; // { name, value, scale }
        const p = pctToNumber({ value: tax.value, scale: tax.scale }); // ej. 21 → 21%
        return {
          label: tax.name,
          percentage: p,
          amount: moneyPct(baseAmount, p),
        };
      }) ?? [];

    // 6) Total impuestos = suma amounts
    const taxesTotal = taxesBreakdown.reduce((acc, t) => add(acc, t.amount), zero);

    // 7) Total línea = base + impuestos
    const total = add(baseAmount, taxesTotal);

    return {
      qty,
      subtotal,
      discountAmount,
      baseAmount,
      taxesBreakdown, // [{label, percentage, amount}]
      taxesTotal,
      total,
    };
  }, [
    item.quantity,
    item.unit_amount,
    item.discount_percentage,
    item.tax_codes,
    qtyToNumber,
    pctToNumber,
    add,
    sub,
    multiply,
    moneyPct,
    isEmptyMoneyDTO,
    taxCatalog,
    zero,
  ]);
}
