import { ForbiddenException } from '@nestjs/common';
import { SubmoduloGuard } from './submodulo.guard';

/**
 * Cubre el período de prueba que CRM-02 agregó al guard. El resto del guard
 * (addon contratado, módulo padre, exclusión por empresa) no tenía tests en el
 * repo; acá se protege al menos el camino nuevo, que es el que puede cortarle
 * el acceso a empresas que hoy funcionan.
 *
 * El guard deriva el estado contra la fecha real, así que las fechas de estos
 * casos son relativas a hoy, no literales.
 */
describe('SubmoduloGuard · período de prueba', () => {
  const haceDias = (n: number) => new Date(Date.now() - n * 86_400_000);
  const enDias = (n: number) => new Date(Date.now() + n * 86_400_000);

  const armar = (fechaFinPrueba: Date | null, metodo = 'GET') => {
    const prisma: any = {
      usuario: { findUnique: jest.fn().mockResolvedValue({ is_superadmin: false, username: 'u' }) },
      empresas: { findUnique: jest.fn().mockResolvedValue({ type: 'subsidiary' }) },
      // es_addon: true toma el camino corto, con una sola consulta a suscripcion_submodulos.
      submodulos: { findFirst: jest.fn().mockResolvedValue({ id: 'sub-1', modulo_id: 'mod-1', es_addon: true }) },
      suscripciones: { findFirst: jest.fn().mockResolvedValue({ id: 'sus-1' }) },
      suscripcion_submodulos: {
        findFirst: jest.fn().mockResolvedValue({ id: 'ss-1', fecha_fin_prueba: fechaFinPrueba }),
      },
    };
    const reflector: any = { getAllAndOverride: jest.fn().mockReturnValue('CRM_CONTRATOS') };
    const ctx: any = {
      getHandler: () => null,
      getClass: () => null,
      switchToHttp: () => ({
        getRequest: () => ({ user: { id: 'u-1', empresa_id: 'emp-1' }, method: metodo, url: '/x' }),
      }),
    };
    return { guard: new SubmoduloGuard(reflector, prisma), ctx };
  };

  it('sin prueba corriendo no cambia nada: es el caso de todas las empresas hoy', async () => {
    const { guard, ctx } = armar(null, 'POST');
    await expect(guard.canActivate(ctx)).resolves.toBe(true);
  });

  it('con la prueba vigente deja escribir', async () => {
    const { guard, ctx } = armar(enDias(10), 'POST');
    await expect(guard.canActivate(ctx)).resolves.toBe(true);
  });

  it('el último día de la prueba todavía deja escribir', async () => {
    const { guard, ctx } = armar(new Date(), 'POST');
    await expect(guard.canActivate(ctx)).resolves.toBe(true);
  });

  it('vencida pero dentro de la gracia, deja leer', async () => {
    const { guard, ctx } = armar(haceDias(5), 'GET');
    await expect(guard.canActivate(ctx)).resolves.toBe(true);
  });

  it('vencida pero dentro de la gracia, NO deja escribir', async () => {
    const { guard, ctx } = armar(haceDias(5), 'POST');
    await expect(guard.canActivate(ctx)).rejects.toThrow(/solo lectura/i);
  });

  it('pasados los 30 días de gracia tampoco deja leer', async () => {
    const { guard, ctx } = armar(haceDias(45), 'GET');
    await expect(guard.canActivate(ctx)).rejects.toThrow(ForbiddenException);
  });

  it('el día 30 todavía es solo lectura; el 31 ya está bloqueado', async () => {
    const borde = armar(haceDias(30), 'GET');
    await expect(borde.guard.canActivate(borde.ctx)).resolves.toBe(true);

    const pasado = armar(haceDias(31), 'GET');
    await expect(pasado.guard.canActivate(pasado.ctx)).rejects.toThrow(ForbiddenException);
  });
});
