import {
    CanActivate,
    ExecutionContext,
    ForbiddenException,
    Injectable,
    Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PrismaService } from 'src/prisma/prisma.service';
import { REQUIRE_MODULE_KEY } from '../decorators/require-module.decorator';

/**
 * Guard que verifica si la empresa del usuario tiene el módulo activo
 * en su suscripción vigente.
 *
 * Uso: combinar con @RequireModule('CODIGO') y @UseGuards(AuthGuard('jwt'), ModuleGuard)
 *
 * Los usuarios superAdmin pasan automáticamente (el bypass se registra en logs).
 */
@Injectable()
export class ModuleGuard implements CanActivate {
  private readonly logger = new Logger(ModuleGuard.name);

  constructor(
    private reflector: Reflector,
    private prisma: PrismaService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const moduloCodigo = this.reflector.getAllAndOverride<string>(
      REQUIRE_MODULE_KEY,
      [context.getHandler(), context.getClass()],
    );

    // Si no hay decorator @RequireModule, permitir acceso
    if (!moduloCodigo) return true;

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    if (!user?.id || !user?.empresa_id) {
      throw new ForbiddenException('Usuario no autenticado');
    }

    // SuperAdmin pasa siempre (se loggea para trazabilidad)
    const usuario = await this.prisma.usuario.findUnique({
      where: { id: user.id },
      select: { is_superadmin: true, username: true },
    });
    if (usuario?.is_superadmin) {
      this.logger.log(
        `[SUPERADMIN_BYPASS] usuario=${usuario.username ?? user.id} empresa=${user.empresa_id} modulo=${moduloCodigo} ruta=${request.method} ${request.url}`,
      );
      return true;
    }

    // Holdings y resellers no tienen suscripción propia con módulos, pasan siempre
    const empresa = await this.prisma.empresas.findUnique({
      where: { id: user.empresa_id },
      select: { type: true },
    });
    if (empresa?.type === 'holding' || empresa?.type === 'reseller')
      return true;

    // Verificar si la empresa tiene suscripción activa con ese módulo
    const moduloActivo = await this.prisma.suscripcion_modulos.findFirst({
      where: {
        activo: true,
        suscripciones: {
          empresa_id: user.empresa_id,
          estado: { in: ['Activo', 'EnGracia'] },
        },
        modulos: {
          codigo: moduloCodigo,
          active: true,
        },
      },
    });

    if (!moduloActivo) {
      throw new ForbiddenException(
        `El módulo "${moduloCodigo}" no está disponible en su plan actual`,
      );
    }

    return true;
  }
}
