import {
  Injectable,
  CanActivate,
  ExecutionContext,
  ForbiddenException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PermissionService } from '../../permission/permission.service';
import { PERMISSION_KEY } from './../../common/guards/decorators/permission.decorator';
import { IS_PUBLIC_KEY } from './../../common/guards/decorators/public.decorator';

@Injectable()
export class PermissionGuard implements CanActivate {
  constructor(
    private permissionService: PermissionService,
    private reflector: Reflector,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // Skip if route is marked @Public()
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) return true;

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

    // No user = not authenticated, let auth guard handle it
    if (!user) return true;

    // Extract URL segment: /api/planning-modules/... → "planning-modules"
    const parts = request.path.split('/').filter(Boolean);
    const urlSegment = parts[0] === 'api' ? parts[1] : parts[0];

    if (!urlSegment) return true;

    // 1️⃣ Check if there's a specific @RequirePermission('approve') on the route
    const requiredAction = this.reflector.getAllAndOverride<string>(
      PERMISSION_KEY,
      [context.getHandler(), context.getClass()],
    );

    // 2️⃣ Find the module by EITHER slug OR api_prefix matching the URL segment
    const moduleInfo = await this.permissionService.findModuleByUrlSegment(urlSegment);

    // If no module found for this URL, allow access (not a protected module)
    if (!moduleInfo) return true;

    // 3️⃣ If decorator specifies an action, use it; otherwise fetch ALL user permissions for this module
    if (requiredAction) {
      const allowed = await this.permissionService.checkUserPermission(
        user.id,
        moduleInfo.slug,
        requiredAction,
      );
      if (!allowed) {
        throw new ForbiddenException(
          `No "${requiredAction}" permission on "${moduleInfo.name}"`,
        );
      }
      return true;
    }

    // 4️⃣ Dynamic: check if user has ANY permission on this module
    const hasAny = await this.permissionService.hasAnyPermissionOnModule(
      user.id,
      moduleInfo.slug,
    );
    if (!hasAny) {
      throw new ForbiddenException(
        `No access to "${moduleInfo.name}"`,
      );
    }

    // Attach permissions to request for use in controllers/services
    const userPerms = await this.permissionService.getUserPermissionsForModule(
      user.id,
      moduleInfo.slug,
    );
    request.userPermissions = userPerms;

    return true;
  }
}