import { MongoAbility } from '@casl/ability';
import { CaslAction } from './casl.constants';

// ---------------------------------------------------------------------------
//  Subject type union — all entity classes we protect with CASL.
// ---------------------------------------------------------------------------

// CASL expects the subject to be either the class constructor or a string.
// We use string subjects (SubjectName) for simplicity when no instance is
// available, and concrete instance types for per-resource checks.
export type AppSubject = string | Record<string, unknown>;

export type AppAbility = MongoAbility<[CaslAction, AppSubject]>;

// ---------------------------------------------------------------------------
//  Authenticated user — what the JWT strategy places on `request.user`.
// ---------------------------------------------------------------------------

export interface AuthenticatedUser {
  id: number;
  username: string;
  /** Flat list of `resource:action` permission codes. */
  permissions: string[];
  /** Whether the user has a super-admin role. */
  isSuperAdmin: boolean;
  /** Role names (display/debug only — NEVER used for authorization). */
  roles: string[];
}

/**
 * Minimum authorization principal — the subset of AuthenticatedUser
 * needed by CaslAbilityFactory and AuthorizationService.
 */
export type AuthPrincipal = { readonly permissions: readonly string[]; readonly isSuperAdmin: boolean };

/** Request-like carrier populated only by the trusted authentication layer. */
export interface AuthorizationRequest {
  user?: AuthPrincipal;
}

// ---------------------------------------------------------------------------
//  Policy handler types for @CheckPolicies()
// ---------------------------------------------------------------------------

/**
 * Interface for class-based policy handlers.
 *
 * Implement this interface in a class to create a testable,
 * NestJS-official CASL policy handler:
 *
 * ```ts
 * class ReadStudentPolicyHandler implements IPolicyHandler {
 *   handle(ability: AppAbility) {
 *     return ability.can('read', 'Student');
 *   }
 * }
 * ```
 */
export interface IPolicyHandler {
  handle(ability: AppAbility): boolean;
}

/**
 * A policy handler — either a callback or a class implementing
 * {@link IPolicyHandler}.
 */
export type PolicyHandler = ((ability: AppAbility) => boolean) | IPolicyHandler;
