import { TaxCatalogProvider, TaxItemType } from "@erp/core";
import { toDinero, toNum } from "./calculate-utils";

export interface InvoiceItemCalcInput {
  quantity?: string; // p.ej. "3.5"
  unit_amount?: string; // p.ej. "125.75"
  discount_percentage?: string; // p.ej. "10" (=> 10%)
  header_discount_percentage?: string; // p.ej. "5" (=> 5%)
  tax_codes: string[]; // ["iva_21", ...]
}

export type InvoiceItemTaxSummary = TaxItemType & {
  taxable_amount: number;
  taxes_amount: number;
};

export interface InvoiceItemCalcResult {
  subtotal_amount: number;
  discount_amount: number;
  header_discount_amount: number;
  taxable_amount: number;
  taxes_amount: number;
  taxes_summary: InvoiceItemTaxSummary[];
  total_amount: number;
}

/**
 * Cálculo financiero exacto por línea de factura.
 * Usa Dinero.js (base 10^2 y round half up) → resultados seguros en céntimos.
 */
export function calculateInvoiceItemAmounts(
  item: InvoiceItemCalcInput,
  currency: string,
  taxCatalog: TaxCatalogProvider
): InvoiceItemCalcResult {
  const defaultScale = 4;
  const taxesSummary: InvoiceItemTaxSummary[] = [];

  const qty = Number.parseFloat(item.quantity || "0") || 0;
  const unit = Number.parseFloat(item.unit_amount || "0") || 0;
  const iten_pct = Number.parseFloat(item.discount_percentage || "0") || 0;
  const header_pct = Number.parseFloat(item.header_discount_percentage || "0") || 0;

  // Subtotal = cantidad × precio unitario
  const subtotal_amount = toDinero(unit, defaultScale, currency).multiply(qty);

  // Descuento = subtotal × (item_pct / 100)
  const discount_amount = subtotal_amount.percentage(iten_pct);
  const subtotal_w_discount_amount = subtotal_amount.subtract(discount_amount);

  // Descuento de la cabecera = subtotal con dto de línea × (header_pct / 100)
  const header_discount = subtotal_w_discount_amount.percentage(header_pct);

  // Base imponible
  const taxable_amount = subtotal_w_discount_amount.subtract(header_discount);

  // Impuestos acumulados con signo
  let taxes_amount = toDinero(0, defaultScale, currency);
  for (const code of item.tax_codes ?? []) {
    const tax = taxCatalog.findByCode(code);
    if (tax.isNone()) continue;

    tax.map((taxItem) => {
      const tax_pct_value =
        Number.parseFloat(taxItem.value) / 10 ** Number.parseInt(taxItem.scale, 10);
      const item_taxables_amount = taxable_amount.percentage(tax_pct_value);

      // Sumar o restar según grupo
      switch (taxItem.group.toLowerCase()) {
        case "retención":
          taxes_amount = taxes_amount.subtract(item_taxables_amount);
          break;
        default:
          taxes_amount = taxes_amount.add(item_taxables_amount);
          break;
      }

      taxesSummary.push({
        ...taxItem,
        taxable_amount: toNum(taxable_amount),
        taxes_amount: toNum(item_taxables_amount),
      });
    });
  }

  const total = taxable_amount.add(taxes_amount);

  return {
    subtotal_amount: toNum(subtotal_amount),
    discount_amount: toNum(discount_amount),
    header_discount_amount: toNum(header_discount),
    taxable_amount: toNum(taxable_amount),
    taxes_amount: toNum(taxes_amount),
    taxes_summary: taxesSummary,
    total_amount: toNum(total),
  };
}
