import type { MoneyDTO } from "@erp/core/common";
import type { Currency } from "dinero.js";
import * as React from "react";
import { useTranslation } from "../i18n";

export type { Currency };

// --- Utils locales (edición texto → número) ---

// Quita símbolos de moneda/letras, conserva dígitos, signo y , .
const stripCurrencySymbols = (s: string) =>
  s
    .replace(/[^\d.,\-]/g, "")
    .replace(/\s+/g, " ")
    .trim();

// Heurística robusta: determina decimal por última ocurrencia de , o .
const parseLocaleNumber = (raw: string): number | null => {
  if (!raw) return null;
  const s = stripCurrencySymbols(raw);
  if (!s) return null;
  const lastComma = s.lastIndexOf(",");
  const lastDot = s.lastIndexOf(".");
  let normalized = s;
  if (lastComma > -1 && lastDot > -1) {
    if (lastComma > lastDot) normalized = s.replace(/\./g, "").replace(",", ".");
    else normalized = s.replace(/,/g, "");
  } else if (lastComma > -1) {
    normalized = s.replace(/\s/g, "").replace(",", ".");
  } else {
    normalized = s.replace(/\s/g, "");
  }
  const n = Number(normalized);
  return Number.isFinite(n) ? n : null;
};

// Redondeo a escala (por defecto 2)
const roundToScale = (n: number, scale = 2) => {
  const f = 10 ** scale;
  return Math.round(n * f) / f;
};

// DTO vacío (API puede mandar "", "")
const isEmptyMoneyDTO = (m?: MoneyDTO | null) =>
  !m || m.value?.trim?.() === "" || m.scale?.trim?.() === "";

// Convierte DTO→número sin instanciar dinero.js (solo lectura)
const toNumberUnsafe = (dto?: MoneyDTO | null, fallbackScale = 2): number => {
  if (isEmptyMoneyDTO(dto)) return 0;
  const scale = Number(dto!.scale || fallbackScale);
  return Number(dto!.value || 0) / 10 ** scale;
};

// Convierte número→DTO (sin costo extra)
const fromNumberUnsafe = (n: number, currency: Currency = "EUR", scale = 2): MoneyDTO => ({
  value: String(Math.round(n * 10 ** scale)),
  scale: String(scale),
  currency_code: currency,
});

// --- Hook ---

export function useMoney(overrides?: {
  locale?: string; // e.g. "es-ES" (si no, i18n.language)
  fallbackCurrency?: Currency; // por defecto "EUR"
  defaultScale?: number; // por defecto 2
}) {
  const { i18n } = useTranslation();
  const locale = overrides?.locale || i18n.language || "es-ES";
  const fallbackCurrency: Currency = overrides?.fallbackCurrency ?? "EUR";
  const defaultScale = overrides?.defaultScale ?? 2;

  // Conversión básica
  const toNumber = React.useCallback(
    (dto?: MoneyDTO | null) => toNumberUnsafe(dto, defaultScale),
    [defaultScale]
  );

  const fromNumber = React.useCallback(
    (n: number, currency: Currency = fallbackCurrency, scale: number = defaultScale): MoneyDTO =>
      fromNumberUnsafe(n, currency, scale),
    [fallbackCurrency, defaultScale]
  );

  // Reescala manteniendo magnitud
  const withScale = React.useCallback(
    (dto: MoneyDTO, scale: number) => {
      const curr = toNumber(dto);
      return fromNumber(curr, (dto.currency_code as Currency) || fallbackCurrency, scale);
    },
    [toNumber, fromNumber, fallbackCurrency]
  );

  // Formateos
  const formatCurrency = React.useCallback(
    (dto: MoneyDTO, loc?: string) => formatDTO(dto, loc ?? locale),
    [locale]
  );

  const formatPlain = React.useCallback(
    (dto: MoneyDTO, loc?: string) => {
      const n = toNumber(dto);
      const dec = Number(dto?.scale || defaultScale);
      return new Intl.NumberFormat(loc ?? locale, {
        maximumFractionDigits: dec,
        minimumFractionDigits: Number.isInteger(n) ? 0 : 0,
        useGrouping: true,
      }).format(n);
    },
    [locale, toNumber, defaultScale]
  );

  const parse = React.useCallback((text: string): number | null => parseLocaleNumber(text), []);

  // Adaptadores API
  const fromApi = React.useCallback(
    (m?: MoneyDTO | null): MoneyDTO | null => (m == null || isEmptyMoneyDTO(m) ? null : m),
    []
  );
  const toApi = React.useCallback(
    (m: MoneyDTO | null, currency: Currency = fallbackCurrency): MoneyDTO =>
      m ? m : { value: "", scale: "", currency_code: currency },
    [fallbackCurrency]
  );

  /* // Operaciones (dinero.js via helpers)
  const add = React.useCallback(
    (a: MoneyDTO, b: MoneyDTO): MoneyDTO => sumDTO([a, b], fallbackCurrency),
    [fallbackCurrency]
  );
  const sub = React.useCallback(
    (a: MoneyDTO, b: MoneyDTO): MoneyDTO => sumDTO([a, multiplyDTO(b, -1)], fallbackCurrency),
    [fallbackCurrency]
  );
  const multiply = React.useCallback(
    (dto: MoneyDTO, k: number, rounding: Dinero.RoundingMode = "HALF_EVEN") =>
      multiplyDTO(dto, k, rounding, fallbackCurrency),
    [fallbackCurrency]
  );
  const percentage = React.useCallback(
    (dto: MoneyDTO, p: number, rounding: Dinero.RoundingMode = "HALF_EVEN") =>
      percentageDTO(dto, p, rounding, fallbackCurrency),
    [fallbackCurrency]
  ); */

  // Estado/Comparaciones
  const isZero = React.useCallback((dto?: MoneyDTO | null) => toNumber(dto) === 0, [toNumber]);
  const sameCurrency = React.useCallback(
    (a?: MoneyDTO | null, b?: MoneyDTO | null) =>
      (a?.currency_code || fallbackCurrency) === (b?.currency_code || fallbackCurrency),
    [fallbackCurrency]
  );

  // Stepping teclado con redondeo a escala
  const stepNumber = React.useCallback(
    (base: number, step = 0.01, scale = defaultScale) => roundToScale(base + step, scale),
    [defaultScale]
  );

  return React.useMemo(
    () => ({
      // Conversión
      toNumber,
      fromNumber,
      withScale,

      // Formateo/parseo
      formatCurrency,
      formatPlain,
      parse,

      // DTO vacío / adaptadores
      isEmptyMoneyDTO,
      fromApi,
      toApi,

      // Operaciones
      //add,
      //sub,
      //multiply,
      //percentage,

      // Estado/ayudas
      isZero,
      sameCurrency,
      stepNumber,
      roundToScale,

      // Utils UI
      stripCurrencySymbols,

      // Config efectiva
      locale,
      fallbackCurrency,
      defaultScale,
      // Factory Dinero si se necesita en algún punto de bajo nivel:
      //toDinero: (dto: MoneyDTO) => dineroFromDTO(dto, fallbackCurrency),
      //fromDinero: dtoFromDinero,
    }),
    [
      toNumber,
      fromNumber,
      withScale,
      formatCurrency,
      formatPlain,
      parse,
      fromApi,
      toApi,
      //add,
      //sub,
      //multiply,
      //percentage,
      isZero,
      sameCurrency,
      stepNumber,
      locale,
      fallbackCurrency,
      defaultScale,
    ]
  );
}
