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

/**
 * Guard a nivel privilegio (Fase 5 del refactor de seguridad).
 *
 * Resuelve módulo + submódulo desde el privilegio (relación
 * `privilegios → submodulos → modulos` en BD) y valida en orden:
 *   1. Existencia y activación del privilegio.
 *   2. Módulo raíz en plan (capa 1) — holdings/resellers bypasean.
 *   3. Submódulo addon contratado en `suscripcion_submodulos` (si aplica).
 *   4. Submódulo no-addon NO excluido per-empresa (`suscripcion_submodulos.active=false`).
 *   5. Usuario tiene el privilegio asignado vía sus perfiles (capa 2) —
 *      superAdmin bypasea esta capa pero respeta el plan de la empresa.
 *
 * Uso: `@RequirePrivilegio('VEN_FAC_FACTURA_ANULAR')` +
 *      `@UseGuards(AuthGuard('jwt'), PrivilegioGuard)`.
 */
@Injectable()
export class PrivilegioGuard implements CanActivate {
  private readonly logger = new Logger(PrivilegioGuard.name);

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

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const codigoPrivilegio = this.reflector.getAllAndOverride<string>(
      REQUIRE_PRIVILEGIO_KEY,
      [context.getHandler(), context.getClass()],
    );
    if (!codigoPrivilegio) 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, privilegio] = await Promise.all([
      this.prisma.usuario.findUnique({
        where: { id: user.id },
        select: { is_superadmin: true, username: true },
      }),
      this.prisma.empresas.findUnique({
        where: { id: user.empresa_id },
        select: { type: true },
      }),
      this.prisma.privilegios.findFirst({
        where: { codigo: codigoPrivilegio, active: true },
        select: {
          id: true,
          submodulos: {
            select: {
              id: true,
              codigo: true,
              es_addon: true,
              modulo_id: true,
              modulos: { select: { codigo: true } },
            },
          },
        },
      }),
    ]);

    if (!privilegio) {
      throw new ForbiddenException(`Privilegio "${codigoPrivilegio}" no existe`);
    }
    const submodulo = privilegio.submodulos;
    const moduloCodigo = submodulo?.modulos?.codigo;
    if (!submodulo || !moduloCodigo) {
      throw new ForbiddenException(
        `Privilegio "${codigoPrivilegio}" no está asociado a un submódulo válido`,
      );
    }

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

    if (!isHoldingOrReseller) {
      const suscripcion = await this.prisma.suscripciones.findFirst({
        where: {
          empresa_id: user.empresa_id,
          estado: { in: ['Activo', 'EnGracia'] },
        },
        orderBy: { created_at: 'desc' },
        select: { id: true },
      });
      if (!suscripcion) {
        throw new ForbiddenException('La empresa no tiene una suscripción activa');
      }

      const moduloActivo = await this.prisma.suscripcion_modulos.findFirst({
        where: {
          suscripcion_id: suscripcion.id,
          activo: true,
          modulos: { codigo: moduloCodigo, active: true },
        },
        select: { id: true },
      });
      if (!moduloActivo) {
        throw new ForbiddenException(
          `El módulo "${moduloCodigo}" no está disponible en su plan actual`,
        );
      }

      if (submodulo.es_addon) {
        const addonActivo = await this.prisma.suscripcion_submodulos.findFirst({
          where: {
            suscripcion_id: suscripcion.id,
            submodulo_id: submodulo.id,
            active: true,
          },
          select: { id: true },
        });
        if (!addonActivo) {
          throw new ForbiddenException(
            `El submódulo "${submodulo.codigo}" requiere un addon no contratado en su plan`,
          );
        }
      } else {
        const exclusion = await this.prisma.suscripcion_submodulos.findFirst({
          where: {
            suscripcion_id: suscripcion.id,
            submodulo_id: submodulo.id,
            active: false,
          },
          select: { id: true },
        });
        if (exclusion) {
          throw new ForbiddenException(
            `El submódulo "${submodulo.codigo}" está deshabilitado para esta empresa`,
          );
        }
      }
    }

    if (isSuperAdmin) {
      this.logger.log(
        `[SUPERADMIN_BYPASS] usuario=${usuario?.username ?? user.id} privilegio=${codigoPrivilegio}`,
      );
      return true;
    }

    const tienePrivilegio = await this.prisma.perfiles_privilegios.findFirst({
      where: {
        active: true,
        privilegios: { codigo: codigoPrivilegio },
        modulos: { codigo: moduloCodigo },
        perfiles: {
          usuario_perfiles: { some: { user_id: user.id } },
        },
      },
      select: { id: true },
    });
    if (!tienePrivilegio) {
      throw new ForbiddenException(
        `No tiene el privilegio "${codigoPrivilegio}"`,
      );
    }

    return true;
  }
}
