import type { PaymentFrequency } from "./types";

/**
 * Client-side twin of apps/api/src/policies/premium.ts. Duplicated rather than
 * shared because the API and the web app do not share a package today, and
 * both need it: the form computes IVA and Total live as the operator types,
 * the API stores what it is sent.
 *
 *   base  = prima neta + recargo + derecho de póliza
 *   IVA   = round(base * tasa)
 *   Total = base + IVA
 *
 * The recargo is inside the taxable base — that is what reconciles the Access
 * books (policy 7006785 prints IVA 52.03 on 610.86 + 8.55 + 31.00; leaving the
 * recargo out gives 51.35, which matches nothing on the page).
 */

/** Applied when neither the policy nor its type carries a rate. The single
 *  row both legacy IMPUESTOS tables held. */
export const DEFAULT_TAX_RATE = 0.08;

/** Paying in more than one exhibición is what earns a recargo. A null
 *  frequency (every migrated policy) is treated as "unknown, allow it": the
 *  legacy recargo figures are real and hiding the field would hide them. */
export function surchargeApplies(
  frequency: PaymentFrequency | null | undefined,
): boolean {
  return frequency !== "ANNUAL" && frequency !== "SINGLE";
}

export function num(v: string | number | null | undefined): number {
  if (v === null || v === undefined || v === "") return 0;
  const n = typeof v === "number" ? v : Number(String(v).trim());
  return Number.isFinite(n) ? n : 0;
}

/** Half-up to cents, matching how the printed policy rounds. */
export function round2(n: number): number {
  return Math.round((n + Number.EPSILON) * 100) / 100;
}

export interface PremiumParts {
  netPremium: string | number | null | undefined;
  surcharge: string | number | null | undefined;
  policyFee: string | number | null | undefined;
}

export function taxableBase(p: PremiumParts): number {
  return round2(num(p.netPremium) + num(p.surcharge) + num(p.policyFee));
}

export function computeTax(p: PremiumParts, rate: number): number {
  return round2(taxableBase(p) * rate);
}

export function computeTotal(p: PremiumParts, rate: number): number {
  return round2(taxableBase(p) + computeTax(p, rate));
}

/** Rate ladder: what the policy was issued at, else its line of business, else
 *  the default. Keeps an old policy reading back at its original rate after
 *  somebody edits the catalog. */
export function resolveTaxRate(
  policyRate: string | number | null | undefined,
  policyTypeRate: string | number | null | undefined,
): number {
  for (const candidate of [policyRate, policyTypeRate]) {
    if (candidate === null || candidate === undefined || candidate === "") continue;
    const n = Number(candidate);
    if (Number.isFinite(n) && n >= 0) return n;
  }
  return DEFAULT_TAX_RATE;
}

/** 0.08 -> "8%". Rates are stored as fractions but read as percentages. */
export function formatRate(rate: number): string {
  const pct = round2(rate * 100);
  return `${pct}%`;
}
