import { ViajeCalculosService } from '../viaje-calculos.service';
import { ViajeDocumentosService } from '../viaje-documentos.service';

describe('Viajes — aislamiento por empresa y estados', () => {
  describe('ViajeCalculosService exige la empresa del viaje', () => {
    const crear = () => {
      const prisma: any = {
        nota_remision_det: { findMany: jest.fn().mockResolvedValue([]) },
        factura_det: { findMany: jest.fn().mockResolvedValue([]) },
        pedido_detalle: { findMany: jest.fn().mockResolvedValue([]) },
        presupuesto_det: { findMany: jest.fn().mockResolvedValue([]) },
        producto_presentaciones: { findMany: jest.fn().mockResolvedValue([]) },
      };
      const documentos: any = { idsPorTipo: jest.fn().mockResolvedValue([]) };
      // findOne es el que valida empresa: si el viaje es de otra, lanza.
      const viajes: any = {
        findOne: jest.fn().mockRejectedValue(new Error('Viaje no encontrado')),
      };
      const service = Object.create(ViajeCalculosService.prototype) as any;
      service.prisma = prisma;
      // Los cálculos piden solo los vigentes; acá el filtro de bajas no es lo que se prueba.
      documentos.idsVigentes ??= documentos.idsPorTipo;
      service.documentos = documentos;
      service.viajes = viajes;
      return { service, viajes, documentos };
    };

    it('carga de un viaje de otra empresa no devuelve datos', async () => {
      const { service, viajes, documentos } = crear();
      await expect(service.carga('v-ajeno', 'emp-1')).rejects.toThrow(/no encontrado/i);
      expect(viajes.findOne).toHaveBeenCalledWith('v-ajeno', 'emp-1');
      expect(documentos.idsPorTipo).not.toHaveBeenCalled();
    });

    it('matriz de un viaje de otra empresa no devuelve datos', async () => {
      const { service, viajes, documentos } = crear();
      await expect(service.matriz('v-ajeno', 'emp-1', 'entregado')).rejects.toThrow(/no encontrado/i);
      expect(viajes.findOne).toHaveBeenCalledWith('v-ajeno', 'emp-1');
      expect(documentos.idsPorTipo).not.toHaveBeenCalled();
    });
  });

  describe('Un viaje anulado libera sus documentos', () => {
    const crear = (estado: string) => {
      const viaje = { id: 'v-1', empresa_id: 'emp-1', estado, documentos: [] };
      const prisma: any = {
        viaje_documentos: {
          findFirst: jest.fn().mockResolvedValue({ id: 'vd-1', viaje_id: 'v-1' }),
          delete: jest.fn().mockResolvedValue({}),
        },
      };
      const viajes: any = {
        findOne: jest.fn().mockResolvedValue(viaje),
        exigirEditable: jest.fn().mockImplementation(() => {
          if (estado === 'ANULADO') throw new Error('El viaje está anulado');
          if (estado === 'CERRADO') throw new Error('El viaje está cerrado');
          return Promise.resolve(viaje);
        }),
      };
      const service = Object.create(ViajeDocumentosService.prototype) as any;
      service.prisma = prisma;
      service.viajes = viajes;
      return { service, prisma };
    };

    it('se puede desenganchar un documento de un viaje ANULADO', async () => {
      const { service, prisma } = crear('ANULADO');
      await service.quitar('v-1', 'vd-1', 'emp-1');
      expect(prisma.viaje_documentos.delete).toHaveBeenCalledWith({ where: { id: 'vd-1' } });
    });

    it('un viaje CERRADO sigue sin aceptar desenganches hasta reabrirlo', async () => {
      const { service } = crear('CERRADO');
      await expect(service.quitar('v-1', 'vd-1', 'emp-1')).rejects.toThrow(/cerrado/i);
    });

    it('un viaje ANULADO sigue sin aceptar que se le AGREGUEN documentos', async () => {
      const { service } = crear('ANULADO');
      await expect(
        service.agregar('v-1', [{ tipo: 'FACTURA', documento_id: 'f-1' }], 'emp-1', 'usr-1'),
      ).rejects.toThrow(/anulado/i);
    });
  });
});
