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 type Permission =
  "CLASSES_CREATE" | "CLASSES_READ" | "CLASSES_UPDATE" | "CLASSES_DELETE";

export const Permissions = {
  CLASSES_CREATE: "CLASSES_CREATE" as const,
  CLASSES_READ: "CLASSES_READ" as const,
  CLASSES_UPDATE: "CLASSES_UPDATE" as const,
  CLASSES_DELETE: "CLASSES_DELETE" as const,
};

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

const ROLE_PERMISSIONS: Record<string, Permission[]> = {
  admin: [
    Permissions.CLASSES_CREATE,
    Permissions.CLASSES_READ,
    Permissions.CLASSES_UPDATE,
    Permissions.CLASSES_DELETE,
  ],
  teacher: [
    Permissions.CLASSES_CREATE,
    Permissions.CLASSES_READ,
    Permissions.CLASSES_UPDATE,
  ],
  student: [Permissions.CLASSES_READ],
  parent: [Permissions.CLASSES_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(", "));
  }
}
