import { abrirPorCuenta, dimensionesItem } from './apertura-items';

// Apertura por ítem (spec 2026-10-13 "reglas de cuenta por dimensión", §5.2):
// los netos de los ítems se agrupan por la cuenta que resuelve cada uno y la
// suma tiene que dar exactamente el total de la tasa en la cabecera.

it('agrupa por cuenta y conserva el total exacto', async () => {
  const m = await abrirPorCuenta(
    [{ neto: 100, dims: { CATEGORIA_PRODUCTO: 'serv' } }, { neto: 50, dims: { CATEGORIA_PRODUCTO: 'merc' } }, { neto: 25, dims: { CATEGORIA_PRODUCTO: 'serv' } }],
    175, async (d) => (d.CATEGORIA_PRODUCTO === 'serv' ? 'c-serv' : 'c-merc'), 0);
  expect(Object.fromEntries(m)).toEqual({ 'c-serv': 125, 'c-merc': 50 });
});

it('[RF-4] el redondeo va a la línea mayor y la suma da el total de la tasa', async () => {
  const m = await abrirPorCuenta(
    [{ neto: 33.333, dims: { TIPO_ITEM: 'A' } }, { neto: 33.333, dims: { TIPO_ITEM: 'B' } }, { neto: 33.334, dims: { TIPO_ITEM: 'B' } }],
    100, async (d) => `c-${d.TIPO_ITEM}`, 2);
  expect([...m.values()].reduce((a, b) => a + b, 0)).toBeCloseTo(100, 10);
  expect(m.get('c-B')).toBeCloseTo(66.67, 10);
});

it('[RF-3] ítem sin categoría va a la cuenta que resuelva sin dimensiones de ítem', async () => {
  const m = await abrirPorCuenta([{ neto: 10, dims: {} }, { neto: 5, dims: { CATEGORIA_PRODUCTO: 'serv' } }], 15,
    async (d) => (d.CATEGORIA_PRODUCTO ? 'c-serv' : 'c-def'), 0);
  expect(Object.fromEntries(m)).toEqual({ 'c-def': 10, 'c-serv': 5 });
});

it('si los netos no suman el total (ítems en otra moneda redondeados), se prorratea al total', async () => {
  const m = await abrirPorCuenta([{ neto: 60, dims: { TIPO_ITEM: 'A' } }, { neto: 40, dims: { TIPO_ITEM: 'B' } }], 101, async (d) => `c-${d.TIPO_ITEM}`, 0);
  expect([...m.values()].reduce((a, b) => a + b, 0)).toBe(101);
});

it('un total con más decimales que el redondeo se conserva entero en la línea mayor', async () => {
  // Compra en guaraníes con total 827.781,82 (los totales de compra traen centavos).
  const m = await abrirPorCuenta([{ neto: 500000.5, dims: { TIPO_ITEM: 'A' } }, { neto: 327781.32, dims: { TIPO_ITEM: 'B' } }], 827781.82, async (d) => `c-${d.TIPO_ITEM}`, 0);
  expect(m.get('c-B')).toBe(327781);
  expect([...m.values()].reduce((a, b) => a + b, 0)).toBeCloseTo(827781.82, 8);
});

it('una sola cuenta resultante lleva exactamente el total (el asiento de hoy)', async () => {
  const total = (1234.56 - 112.23) * 7312.5;
  const m = await abrirPorCuenta([{ neto: 1, dims: {} }, { neto: 2, dims: { TIPO_ITEM: 'A' } }], total, async () => 'c', 2);
  expect(m.get('c')).toBe(total);
});

it('dimensionesItem: categoría, rubro propio o heredado de la categoría, y tipo; sin producto, vacías', () => {
  expect(dimensionesItem({ tipo: 'SERVICIO', rubro_id: null, categoria_id: 'cat', categoria: { rubro_id: 'rub-cat' } }))
    .toEqual({ CATEGORIA_PRODUCTO: 'cat', RUBRO: 'rub-cat', TIPO_ITEM: 'SERVICIO' });
  expect(dimensionesItem({ tipo: null, rubro_id: 'rub-prop', categoria_id: 'cat', categoria: { rubro_id: 'rub-cat' } }))
    .toEqual({ CATEGORIA_PRODUCTO: 'cat', RUBRO: 'rub-prop' });
  expect(dimensionesItem(null)).toEqual({});
});
