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

/**
 * Guard que verifica:
 *  1. Que la empresa tenga el módulo activo en su suscripción
 *  2. Que el perfil del usuario tenga el privilegio para ese módulo
 *
 * Uso: combinar con @RequirePermission('MODULO', 'PRIVILEGIO')
 *      y @UseGuards(AuthGuard('jwt'), PermissionGuard)
 *
 * Los usuarios superAdmin pasan automáticamente.
 */
@Injectable()
export class PermissionGuard implements CanActivate {
  private readonly logger = new Logger(PermissionGuard.name);

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

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

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

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

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

    const [usuario, empresa] = await Promise.all([
      this.prisma.usuario.findUnique({
        where: { id: user.id },
        select: { is_superadmin: true },
      }),
      this.prisma.empresas.findUnique({
        where: { id: user.empresa_id },
        select: { type: true },
      }),
    ]);

    const isSuperAdmin = usuario?.is_superadmin ?? false;
    const isHoldingOrReseller = empresa?.type === 'holding' || empresa?.type === 'reseller';

    // Capa 1: Verificar módulo activo en la suscripción
    // Holdings/resellers bypasean (no tienen suscripción propia)
    // SuperAdmin de subsidiaria NO bypasea — debe respetar el plan
    let hasModuloSuscripcion = isHoldingOrReseller;
    if (!isHoldingOrReseller) {
      const moduloActivo = await this.prisma.suscripcion_modulos.findFirst({
        where: {
          activo: true,
          suscripciones: {
            empresa_id: user.empresa_id,
            estado: { in: ['Activo', 'EnGracia'] },
          },
          modulos: {
            codigo: meta.modulo,
            active: true,
          },
        },
      });

      if (!moduloActivo) {
        throw new ForbiddenException(`El módulo "${meta.modulo}" no está disponible en su plan actual`);
      }
      hasModuloSuscripcion = true;
    }

    // Capa 1.2: Si el privilegio pertenece a un submódulo addon,
    // exigir que la empresa lo tenga contratado en suscripcion_submodulos.
    // Holdings/resellers se mantienen exceptuados.
    if (!isHoldingOrReseller) {
      const priv = await this.prisma.privilegios.findFirst({
        where: { codigo: meta.privilegio, active: true },
        select: {
          submodulos: { select: { id: true, codigo: true, es_addon: true } },
        },
      });
      const submodulo = priv?.submodulos;
      if (submodulo?.es_addon) {
        const addonActivo = await this.prisma.suscripcion_submodulos.findFirst({
          where: {
            active: true,
            submodulo_id: submodulo.id,
            suscripciones: {
              empresa_id: user.empresa_id,
              estado: { in: ['Activo', 'EnGracia'] },
            },
          },
          select: { id: true },
        });
        if (!addonActivo) {
          throw new ForbiddenException(
            `El submódulo "${submodulo.codigo}" requiere un addon no contratado en su plan`,
          );
        }
      }
    }

    // Capa 1.1: Para IMPORTACIONES, exigir switch operativo por empresa.
    // Los privilegios de configuración (IMP_CFG_*) quedan exceptuados para permitir habilitar el módulo.
    if (meta.modulo === 'IMPORTACIONES' && !meta.privilegio.startsWith('IMP_CFG_')) {
      let config = await this.prisma.imp_config_empresa.findUnique({
        where: { empresa_id: user.empresa_id },
        select: { modulo_operativo_activo: true },
      });

      if (!config) {
        config = await this.prisma.imp_config_empresa.create({
          data: {
            empresa_id: user.empresa_id,
            modulo_operativo_activo: hasModuloSuscripcion,
            perfil_activo: 'AUTOS',
          },
          select: { modulo_operativo_activo: true },
        });
      }

      if (!config.modulo_operativo_activo) {
        throw new ForbiddenException('El módulo "IMPORTACIONES" está desactivado para esta empresa');
      }
    }

    // Capa 2: Verificar privilegio del usuario
    // SuperAdmin bypasea — tiene todos los privilegios sobre módulos disponibles
    if (isSuperAdmin) {
      this.logger.log(
        `[SUPERADMIN_BYPASS] usuario=${user.id} empresa=${user.empresa_id} modulo=${meta.modulo} privilegio=${meta.privilegio} ruta=${request.method} ${request.url}`,
      );
      return true;
    }

    const tienePermiso = await this.prisma.perfiles_privilegios.findFirst({
      where: {
        active: true,
        modulos: { codigo: meta.modulo },
        privilegios: { codigo: meta.privilegio },
        perfiles: {
          usuario_perfiles: {
            some: { user_id: user.id },
          },
        },
      },
    });

    if (!tienePermiso) {
      throw new ForbiddenException(`No tiene permiso "${meta.privilegio}" en el módulo "${meta.modulo}"`);
    }

    return true;
  }
}
