import {
  CanActivate,
  ExecutionContext,
  ForbiddenException,
  Injectable,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { SuscripcionesService } from '../../suscripciones/suscripciones.service';

export const SKIP_SUSCRIPCION_CHECK = 'skip_suscripcion_check';
export const SkipSuscripcionCheck = () =>
  Reflect.metadata(SKIP_SUSCRIPCION_CHECK, true);

/**
 * Guard global que verifica si la empresa del usuario tiene una suscripción activa.
 * Bloquea operaciones de escritura (POST, PUT, PATCH, DELETE) si la suscripción
 * está vencida o no existe.
 *
 * Rutas excluidas automáticamente:
 * - Login, registro, refresh token
 * - Endpoints de suscripción (mi-suscripcion, comprobantes, pagos)
 * - GET requests (lectura permitida siempre)
 *
 * Se puede saltar con el decorador @SkipSuscripcionCheck()
 */
@Injectable()
export class SuscripcionGuard implements CanActivate {
  // Rutas que siempre se permiten (parciales)
  private readonly allowedPaths = [
    '/auth/',
    '/suscripciones/mi-suscripcion',
    '/suscripciones/mis-pagos',
    '/suscripciones/comprobantes',
    '/suscripciones/cron/',
    '/suscripciones/holding/',
  ];

  constructor(
    private readonly suscripcionesService: SuscripcionesService,
    private readonly reflector: Reflector,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // Verificar si el handler tiene el decorador de skip
    const skip = this.reflector.get<boolean>(
      SKIP_SUSCRIPCION_CHECK,
      context.getHandler(),
    );
    if (skip) return true;

    const req = context.switchToHttp().getRequest();
    const method = req.method as string;

    // Solo bloquear mutaciones (POST, PUT, PATCH, DELETE)
    if (method === 'GET' || method === 'OPTIONS' || method === 'HEAD') {
      return true;
    }

    // Si no hay usuario autenticado, dejar pasar (otro guard se encargará)
    const user = req.user;
    if (!user?.empresa_id) return true;

    // Verificar si la ruta está en la lista de permitidas
    const path = req.url as string;
    if (this.allowedPaths.some((p) => path.includes(p))) {
      return true;
    }

    // Verificar estado de la suscripción
    const estado = await this.suscripcionesService.verificarEstadoSuscripcion(
      user.empresa_id,
    );

    if (estado.bloqueada) {
      throw new ForbiddenException({
        blocked: true,
        reason: 'subscription_expired',
        message:
          'Su suscripción ha vencido. No puede realizar esta operación hasta renovar su plan.',
        detalle: estado.razon,
      });
    }

    return true;
  }
}
