import {
  Injectable,
  CanActivate,
  ExecutionContext,
  SetMetadata,
} from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { PermissionDeniedError } from "../shared/errors/application-error.js";
import type { AuthenticatedRequest } from "./auth.middleware.js";

export const Permissions = {
  MSG_NOTIFICATION_SEND: "MSG_NOTIFICATION_SEND" as const,
  MSG_NOTIFICATION_READ: "MSG_NOTIFICATION_READ" as const,
  MSG_NOTIFICATION_MANAGE: "MSG_NOTIFICATION_MANAGE" as const,
} as const;

export type Permission = (typeof Permissions)[keyof typeof Permissions];

export const PERMISSIONS_KEY = "permissions";
export const RequirePermission = (...permissions: Permission[]) =>
  SetMetadata(PERMISSIONS_KEY, permissions);

const ROLE_PERMISSIONS: Record<string, Permission[]> = {
  admin: [
    Permissions.MSG_NOTIFICATION_SEND,
    Permissions.MSG_NOTIFICATION_READ,
    Permissions.MSG_NOTIFICATION_MANAGE,
  ],
  teacher: [
    Permissions.MSG_NOTIFICATION_SEND,
    Permissions.MSG_NOTIFICATION_READ,
  ],
  student: [Permissions.MSG_NOTIFICATION_READ],
};

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

  canActivate(context: ExecutionContext): boolean {
    if (process.env.DEV_MODE === "true") {
      return true;
    }

    const requiredPermissions = this.reflector.getAllAndOverride<Permission[]>(
      PERMISSIONS_KEY,
      [context.getHandler(), context.getClass()],
    );

    if (!requiredPermissions || requiredPermissions.length === 0) {
      return true;
    }

    const request = context.switchToHttp().getRequest<AuthenticatedRequest>();
    const roles = request.userRoles ?? [];

    for (const role of roles) {
      const perms = ROLE_PERMISSIONS[role];
      if (perms && requiredPermissions.some((p) => perms.includes(p))) {
        return true;
      }
    }

    throw new PermissionDeniedError(requiredPermissions.join(", "));
  }
}
