import { NotFoundException, ConflictException } from '@nestjs/common';
import type { Response } from 'express';
import { REQUIRE_PERMISSION_KEY } from '../../auth/decorators/require-permission.decorator';
import type { LoginUserInfo } from '../../auth/dto/login.dto';
import { LiquidacionesController } from './liquidaciones.controller';
import { LiquidacionesService } from '../services/liquidaciones.service';

describe('LiquidacionesController', () => {
  let controller: LiquidacionesController;
  let service: jest.Mocked<LiquidacionesService>;

  const user = { id: 'usr-1', empresa_id: 'emp-1' } as LoginUserInfo;

  beforeEach(async () => {
    const serviceMock = {
      obtenerPlanillaConsolidada: jest.fn(),
      generarPlanillaConsolidadaXlsx: jest.fn(),
    } as unknown as jest.Mocked<LiquidacionesService>;

    service = serviceMock;
    controller = new LiquidacionesController(service);
  });

  it('declara permiso RRHH_REPORTES_VER en endpoint planilla', () => {
    const meta = Reflect.getMetadata(REQUIRE_PERMISSION_KEY, LiquidacionesController.prototype.planilla);
    expect(meta).toEqual({ modulo: 'RRHH', privilegio: 'RRHH_REPORTES_VER' });
  });

  it('retorna json consolidado cuando format=json', async () => {
    const dataset = { resumen_conceptos: [], detalle: [], totales: { ingresos: 0, egresos: 0, neto: 0 } };
    service.obtenerPlanillaConsolidada.mockResolvedValue(dataset as any);

    const res = {} as Response;
    const out = await controller.planilla('liq-1', user, { format: 'json' }, res);

    expect(service.obtenerPlanillaConsolidada).toHaveBeenCalledWith('liq-1', 'emp-1');
    expect(service.generarPlanillaConsolidadaXlsx).not.toHaveBeenCalled();
    expect(out).toEqual(dataset);
  });

  it('retorna json consolidado por defecto cuando no se envía format', async () => {
    const dataset = { resumen_conceptos: [], detalle: [], totales: { ingresos: 0, egresos: 0, neto: 0 } };
    service.obtenerPlanillaConsolidada.mockResolvedValue(dataset as any);

    const res = {} as Response;
    const out = await controller.planilla('liq-1', user, {} as any, res);

    expect(service.obtenerPlanillaConsolidada).toHaveBeenCalledWith('liq-1', 'emp-1');
    expect(out).toEqual(dataset);
  });

  it('envía archivo xlsx cuando format=xlsx', async () => {
    const setHeader = jest.fn();
    const send = jest.fn();
    const res = { setHeader, send } as unknown as Response;

    service.generarPlanillaConsolidadaXlsx.mockResolvedValue({
      buffer: Buffer.from('xlsx'),
      filename: 'planilla_rrhh_2026-05_liq_abc12345.xlsx',
    });

    const out = await controller.planilla('liq-1', user, { format: 'xlsx' }, res);

    expect(service.generarPlanillaConsolidadaXlsx).toHaveBeenCalledWith('liq-1', 'emp-1');
    expect(service.obtenerPlanillaConsolidada).not.toHaveBeenCalled();
    expect(setHeader).toHaveBeenCalledWith(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    expect(setHeader).toHaveBeenCalledWith(
      'Content-Disposition',
      'attachment; filename="planilla_rrhh_2026-05_liq_abc12345.xlsx"',
    );
    expect(send).toHaveBeenCalledWith(Buffer.from('xlsx'));
    expect(out).toBeUndefined();
  });

  it('propaga NotFoundException (404) desde el service', async () => {
    service.obtenerPlanillaConsolidada.mockRejectedValue(new NotFoundException('Liquidación no encontrada'));
    await expect(controller.planilla('liq-404', user, { format: 'json' }, {} as Response)).rejects.toThrow(
      NotFoundException,
    );
  });

  it('propaga ConflictException (409) para tipo/estado inválido', async () => {
    service.obtenerPlanillaConsolidada.mockRejectedValue(
      new ConflictException('La planilla consolidada solo aplica a liquidaciones MENSUALES'),
    );
    await expect(controller.planilla('liq-409', user, { format: 'json' }, {} as Response)).rejects.toThrow(
      ConflictException,
    );
  });
});
