import {
  whereCategoriaPorRubro,
  resolverRubroDefault,
  resolverRubrosPermitidos,
  rubrosAConsultar,
  whereProductoPorRubro,
  whereProveedorPorRubro,
} from './rubros.util';

describe('whereProveedorPorRubro', () => {
  it('sin rubro en contexto no filtra nada', () => {
    expect(whereProveedorPorRubro(undefined)).toEqual({});
    expect(whereProveedorPorRubro(null)).toEqual({});
    expect(whereProveedorPorRubro('')).toEqual({});
  });

  it('con rubro incluye los proveedores sin rubro asignado y los del rubro', () => {
    expect(whereProveedorPorRubro('r1')).toEqual({
      AND: [{ OR: [{ proveedor_rubros: { none: {} } }, { proveedor_rubros: { some: { rubro_id: 'r1' } } }] }],
    });
  });

  it('con varios rubros permitidos incluye los compartidos y los de cualquiera de ellos', () => {
    expect(whereProveedorPorRubro(['r1', 'r2'])).toEqual({
      AND: [{ OR: [{ proveedor_rubros: { none: {} } }, { proveedor_rubros: { some: { rubro_id: { in: ['r1', 'r2'] } } } }] }],
    });
  });

  it('con lista vacía no deja pasar ningún proveedor', () => {
    expect(whereProveedorPorRubro([])).toEqual({ AND: [{ id: { in: [] } }] });
  });

  // `proveedores.service` y `compras.service` ya usan `OR` en el nivel de arriba
  // para la búsqueda por texto. Si el filtro de rubro devolviera otro `OR`, el
  // spread lo pisaría y la búsqueda por nombre/RUC dejaría de filtrar.
  it('se combina con un where que ya tiene OR sin pisarlo', () => {
    const porTexto = { OR: [{ personas: { razon_social: { contains: 'nuar' } } }] };
    const combinado = { empresa_id: 'emp-1', ...porTexto, ...whereProveedorPorRubro('r1') };

    expect(combinado.OR).toEqual(porTexto.OR);
    expect(combinado.AND).toHaveLength(1);
  });
});

describe('whereCategoriaPorRubro', () => {
  it('sin rubro en contexto no filtra nada', () => {
    expect(whereCategoriaPorRubro(null)).toEqual({});
  });

  it('con rubro incluye las compartidas (sin rubro) y las del rubro', () => {
    expect(whereCategoriaPorRubro('r1')).toEqual({ AND: [{ OR: [{ rubro_id: null }, { rubro_id: 'r1' }] }] });
  });

  it('con varios rubros permitidos incluye las compartidas y las de cualquiera', () => {
    expect(whereCategoriaPorRubro(['r1', 'r2'])).toEqual({
      AND: [{ OR: [{ rubro_id: null }, { rubro_id: { in: ['r1', 'r2'] } }] }],
    });
  });

  it('con lista vacía no deja pasar ninguna categoría', () => {
    expect(whereCategoriaPorRubro([])).toEqual({ AND: [{ id: { in: [] } }] });
  });
});

describe('whereProductoPorRubro', () => {
  it('sin rubro en contexto no filtra nada', () => {
    expect(whereProductoPorRubro(undefined)).toEqual({});
  });

  it('el override del producto gana sobre lo que diga su categoría', () => {
    expect(whereProductoPorRubro('r1')).toEqual({
      AND: [
        {
          OR: [
            // Override explícito en el producto.
            { rubro_id: 'r1' },
            // Sin override: se mira la categoría.
            {
              rubro_id: null,
              OR: [{ categoria_id: null }, { categoria: { rubro_id: null } }, { categoria: { rubro_id: 'r1' } }],
            },
          ],
        },
      ],
    });
  });

  it('con varios rubros permitidos filtra por cualquiera de ellos', () => {
    expect(whereProductoPorRubro(['r1', 'r2'])).toEqual({
      AND: [
        {
          OR: [
            { rubro_id: { in: ['r1', 'r2'] } },
            {
              rubro_id: null,
              OR: [
                { categoria_id: null },
                { categoria: { rubro_id: null } },
                { categoria: { rubro_id: { in: ['r1', 'r2'] } } },
              ],
            },
          ],
        },
      ],
    });
  });

  it('con lista vacía no deja pasar nada, ni los compartidos', () => {
    expect(whereProductoPorRubro([])).toEqual({ AND: [{ id: { in: [] } }] });
  });

  it('se combina con el OR de stock de productos.findAll sin pisarlo', () => {
    const porStock = { OR: [{ stock_deposito: { some: { cantidad_disponible: { gt: 0 } } } }] };
    const combinado = { empresa_id: 'emp-1', ...porStock, ...whereProductoPorRubro('r1') };

    expect(combinado.OR).toEqual(porStock.OR);
    expect(combinado.AND).toHaveLength(1);
  });
});

describe('resolverRubroDefault', () => {
  it('sin sucursales asignadas devuelve null: el usuario arranca viendo todo', () => {
    expect(resolverRubroDefault([])).toBeNull();
  });

  it('una sucursal con un rubro devuelve ese rubro', () => {
    expect(resolverRubroDefault([{ sucursal_rubros: [{ rubro_id: 'r1' }] }])).toBe('r1');
  });

  it('dos sucursales del mismo rubro devuelven ese rubro', () => {
    expect(
      resolverRubroDefault([
        { sucursal_rubros: [{ rubro_id: 'r1' }] },
        { sucursal_rubros: [{ rubro_id: 'r1' }] },
      ]),
    ).toBe('r1');
  });

  it('sucursales que cubren más de un rubro devuelven null: no se elige por el usuario', () => {
    expect(
      resolverRubroDefault([
        { sucursal_rubros: [{ rubro_id: 'r1' }] },
        { sucursal_rubros: [{ rubro_id: 'r2' }] },
      ]),
    ).toBeNull();
  });

  it('una sucursal con dos rubros devuelve null por la misma razón', () => {
    expect(resolverRubroDefault([{ sucursal_rubros: [{ rubro_id: 'r1' }, { rubro_id: 'r2' }] }])).toBeNull();
  });

  it('sucursal asignada sin rubro configurado devuelve null', () => {
    expect(resolverRubroDefault([{ sucursal_rubros: [] }])).toBeNull();
  });
});

describe('resolverRubrosPermitidos', () => {
  it('acceso elevado no tiene restricción aunque tenga sucursales asignadas', () => {
    expect(resolverRubrosPermitidos([{ sucursal_rubros: [{ rubro_id: 'r1' }] }], true)).toBeNull();
  });

  it('sin sucursales asignadas no tiene restricción', () => {
    expect(resolverRubrosPermitidos([], false)).toBeNull();
  });

  it('asignado a una sucursal sin rubro no tiene restricción: esa sucursal vende de todo', () => {
    expect(
      resolverRubrosPermitidos([{ sucursal_rubros: [{ rubro_id: 'r1' }] }, { sucursal_rubros: [] }], false),
    ).toBeNull();
  });

  it('devuelve los rubros de sus sucursales, sin repetir', () => {
    expect(
      resolverRubrosPermitidos(
        [
          { sucursal_rubros: [{ rubro_id: 'r1' }] },
          { sucursal_rubros: [{ rubro_id: 'r1' }, { rubro_id: 'r2' }] },
        ],
        false,
      ),
    ).toEqual(['r1', 'r2']);
  });
});

describe('rubrosAConsultar', () => {
  it('sin restricción y sin rubro pedido no filtra', () => {
    expect(rubrosAConsultar(null, undefined)).toBeNull();
  });

  it('sin restricción respeta el rubro pedido', () => {
    expect(rubrosAConsultar(null, 'r2')).toEqual(['r2']);
  });

  it('con restricción y sin rubro pedido usa todos los permitidos', () => {
    expect(rubrosAConsultar(['r1'], undefined)).toEqual(['r1']);
  });

  it('con restricción acepta un rubro permitido', () => {
    expect(rubrosAConsultar(['r1', 'r2'], 'r2')).toEqual(['r2']);
  });

  it('con restricción un rubro no permitido devuelve lista vacía', () => {
    expect(rubrosAConsultar(['r1'], 'r2')).toEqual([]);
  });
});
