import { ConflictException, NotFoundException } from '@nestjs/common';
import { PuntoExpedicionesService } from './punto-expediciones.service';

/**
 * Borrado de puntos de expedición.
 *
 * El código del punto es parte del número de comprobante
 * (establecimiento-punto-correlativo) y debe ser único dentro de la sucursal,
 * así que un punto inactivo igual ocupa el código. La única forma de liberarlo
 * es borrarlo, y sólo se puede si nunca se usó.
 */
describe('PuntoExpedicionesService - borrado', () => {
  const PUNTO = {
    id: 'pe-1',
    empresa_id: 'emp-1',
    sucursal_id: 'suc-1',
    caja_id: 'caja-1',
    punto_expedicion: '003',
    active: false,
  };

  const crearService = (overrides: Record<string, any> = {}) => {
    const prisma: any = {
      empresas_puntos_expedicion: {
        findUnique: jest.fn().mockResolvedValue(PUNTO),
        findFirst: jest.fn().mockResolvedValue(null),
        delete: jest.fn().mockResolvedValue(PUNTO),
      },
      empresas_sucursales: {
        findUnique: jest.fn().mockResolvedValue({ id: 'suc-1', punto_establecimiento: '001' }),
      },
      pagos: { count: jest.fn().mockResolvedValue(0) },
      numeraciones_documento: { findMany: jest.fn().mockResolvedValue([]) },
      sesion_caja_documentos: { count: jest.fn().mockResolvedValue(0) },
      nota_remision_cab: { count: jest.fn().mockResolvedValue(0) },
      factura_cab: { count: jest.fn().mockResolvedValue(0) },
      ...overrides,
    };
    const audit = { log: jest.fn().mockResolvedValue(undefined) };
    const service = new PuntoExpedicionesService({} as any, {} as any, prisma as any, audit as any);
    return { service, prisma };
  };

  it('borra el punto cuando no tiene nada vinculado', async () => {
    const { service, prisma } = crearService();

    await service.remove('pe-1', 'user-1');

    expect(prisma.empresas_puntos_expedicion.delete).toHaveBeenCalledWith({ where: { id: 'pe-1' } });
  });

  it('no borra un punto inexistente', async () => {
    const { service } = crearService({
      empresas_puntos_expedicion: { findUnique: jest.fn().mockResolvedValue(null), delete: jest.fn() },
    });

    await expect(service.remove('pe-fantasma')).rejects.toThrow(NotFoundException);
  });

  it('rechaza si tiene pagos vinculados y dice cuántos', async () => {
    const { service, prisma } = crearService({ pagos: { count: jest.fn().mockResolvedValue(7) } });

    await expect(service.remove('pe-1')).rejects.toThrow(/7 pagos/);
    expect(prisma.empresas_puntos_expedicion.delete).not.toHaveBeenCalled();
  });

  it('rechaza si alguna numeración ya consumió números', async () => {
    const { service, prisma } = crearService({
      numeraciones_documento: {
        findMany: jest.fn().mockResolvedValue([{ id: 'num-1', numero_actual: 45 }]),
      },
    });

    await expect(service.remove('pe-1')).rejects.toThrow(ConflictException);
    expect(prisma.empresas_puntos_expedicion.delete).not.toHaveBeenCalled();
  });

  it('permite borrar cuando las numeraciones existen pero están sin estrenar', async () => {
    const { service, prisma } = crearService({
      numeraciones_documento: {
        findMany: jest.fn().mockResolvedValue([{ id: 'num-1', numero_actual: 1 }, { id: 'num-2', numero_actual: 1 }]),
      },
    });

    await service.remove('pe-1');

    expect(prisma.empresas_puntos_expedicion.delete).toHaveBeenCalled();
  });

  it('rechaza si hay facturas emitidas con ese establecimiento y punto', async () => {
    const { service, prisma } = crearService({ factura_cab: { count: jest.fn().mockResolvedValue(3) } });

    await expect(service.remove('pe-1')).rejects.toThrow(/3 facturas/);
    // La factura no tiene FK al punto: se compara por establecimiento + punto.
    // Y SIEMPRE acotado a la empresa: `dest`/`dpunexp` son strings sueltos, así
    // que sin ese filtro se contarían las facturas de todas las empresas y el
    // punto quedaría imposible de borrar por documentos ajenos.
    expect(prisma.factura_cab.count.mock.calls[0][0].where).toEqual({
      empresa_id: 'emp-1',
      dest: '001',
      dpunexp: '003',
    });
  });

  it('rechaza si hay documentos de sesión de caja sobre sus numeraciones', async () => {
    const { service } = crearService({
      numeraciones_documento: { findMany: jest.fn().mockResolvedValue([{ id: 'num-1', numero_actual: 1 }]) },
      sesion_caja_documentos: { count: jest.fn().mockResolvedValue(2) },
    });

    await expect(service.remove('pe-1')).rejects.toThrow(ConflictException);
  });

  it('junta todos los motivos en un solo mensaje', async () => {
    const { service } = crearService({
      pagos: { count: jest.fn().mockResolvedValue(1) },
      factura_cab: { count: jest.fn().mockResolvedValue(2) },
    });

    await expect(service.remove('pe-1')).rejects.toThrow(/1 pago.*2 facturas|2 facturas.*1 pago/);
  });
});

describe('PuntoExpedicionesService - conflicto al crear', () => {
  it('el mensaje dice en qué caja está el punto que choca y si está inactivo', async () => {
    const prisma: any = {
      empresas_puntos_expedicion: {
        findFirst: jest.fn().mockResolvedValue({
          id: 'pe-viejo',
          punto_expedicion: '003',
          active: false,
          cajas: { descripcion: 'Caja Principal' },
        }),
        create: jest.fn(),
      },
    };
    const service = new PuntoExpedicionesService(
      { findOne: jest.fn().mockResolvedValue({ id: 'emp-1' }) } as any,
      { findOne: jest.fn().mockResolvedValue({ id: 'suc-1' }) } as any,
      prisma as any,
      { log: jest.fn() } as any,
    );

    await expect(
      service.create({ empresa_id: 'emp-1', sucursal_id: 'suc-1', punto_expedicion: '003' } as any),
    ).rejects.toThrow(/Caja Principal/);
  });
});
