import { PrismaService } from '../../prisma/prisma.service';
import { CondicionRegla, Dimension, ReglaMapeo, fraseRegla } from './reglas-mapeo';

/**
 * La frase de una regla ("Si sucursal es Ciudad del Este → 4.01.02 Ventas
 * exterior") con los nombres legibles de sus valores. La usan la pantalla de
 * reglas, el catálogo de asientos y el detalle del asiento: vive aparte para que
 * MapeoCuentasService y AsientosService la usen sin depender de ReglasMapeoService.
 */

export type NombresDeValores = (d: Dimension, valor: string) => string;

type FilaConFrase = Pick<ReglaMapeo, 'id' | 'concepto' | 'orden' | 'cuenta_id' | 'vigente_desde' | 'vigente_hasta'> & {
  condiciones: unknown;
  modo: string;
  estado: string;
  cuenta?: { codigo: string; descripcion: string } | null;
};

/** Mismos textos que `tiposEntidadProveedor.js` del ERP: la frase no muestra el código interno. */
const NOMBRES_TIPO_PROVEEDOR = new Map([
  ['PROVEEDOR_LOCAL', 'Proveedor local'],
  ['PROVEEDOR_EXTERIOR', 'Proveedor del exterior'],
  ['ACREEDOR_VARIO', 'Acreedor vario'],
]);
const NOMBRES_CANAL = new Map([
  ['POS', 'POS'],
  ['FACTURA', 'Factura'],
]);

/** Nombres legibles de los valores que usan las condiciones (sucursal, categoría, rubro, tipo de proveedor, canal), de la empresa. */
export async function cargarNombresDeValores(prisma: PrismaService, empresaId: string, condiciones: unknown[]): Promise<NombresDeValores> {
  const todas = condiciones.flatMap((c) => ((c as CondicionRegla[]) ?? []));
  const ids = (d: Dimension) => [...new Set(todas.filter((c) => c.dimension === d).flatMap((c) => c.valores))];
  const [suc, cat, rub] = [ids('SUCURSAL'), ids('CATEGORIA_PRODUCTO'), ids('RUBRO')];
  type Nombre = { id: string; descripcion: string | null };
  const ninguno = Promise.resolve([] as Nombre[]);
  const [sucursales, categorias, rubros]: Nombre[][] = await Promise.all([
    suc.length
      ? prisma.empresas_sucursales.findMany({ where: { empresa_id: empresaId, id: { in: suc } }, select: { id: true, descripcion: true } })
      : ninguno,
    cat.length
      ? prisma.categorias.findMany({ where: { empresa_id: empresaId, id: { in: cat } }, select: { id: true, descripcion: true } })
      : ninguno,
    rub.length ? prisma.rubros.findMany({ where: { empresa_id: empresaId, id: { in: rub } }, select: { id: true, descripcion: true } }) : ninguno,
  ]);
  const mapa: Partial<Record<Dimension, Map<string, string>>> = {
    TIPO_PROVEEDOR: NOMBRES_TIPO_PROVEEDOR,
    CANAL: NOMBRES_CANAL,
    SUCURSAL: new Map(sucursales.map((s) => [s.id, s.descripcion ?? s.id])),
    CATEGORIA_PRODUCTO: new Map(categorias.map((c) => [c.id, c.descripcion ?? c.id])),
    RUBRO: new Map(rubros.map((r) => [r.id, r.descripcion ?? r.id])),
  };
  return (d, valor) => mapa[d]?.get(valor) ?? valor;
}

/** A dónde manda la regla, como se lee al final de la frase. */
export const destinoRegla = (r: { modo: string; cuenta?: { codigo: string; descripcion: string } | null }) =>
  r.modo === 'SUMAR_A_PRINCIPAL' ? 'se suma a la cuenta principal' : r.cuenta ? `${r.cuenta.codigo} ${r.cuenta.descripcion}` : 'sin cuenta';

export const fraseDeFila = (r: FilaConFrase, nombres: NombresDeValores) =>
  fraseRegla(
    {
      id: r.id,
      concepto: r.concepto,
      orden: r.orden,
      condiciones: (r.condiciones as CondicionRegla[]) ?? [],
      modo: r.modo as ReglaMapeo['modo'],
      cuenta_id: r.cuenta_id,
      estado: r.estado as ReglaMapeo['estado'],
      vigente_desde: r.vigente_desde,
      vigente_hasta: r.vigente_hasta,
    },
    nombres,
    destinoRegla(r),
  );
