/**
 * CASL authorization constants.
 *
 * Maps our existing `{resource}:{action}` permission codes into CASL
 * `Action` + `Subject` pairs.
 *
 * ## Two-layer permission model
 *
 * 1. **Exact code** — `Access PermissionCode:<code>` grants the specific
 *    `resource:action` code. Every code a user holds (preset or custom)
 *    gets an exact-code ability. PermissionGuard checks exact codes.
 *
 * 2. **Domain level** — only strictly equivalent CRUD codes
 *    (`view|read|create|edit|update|delete`) create broad Subject abilities.
 *    Workflow-specific operations remain exact-code-only.
 *
 * Unknown/custom codes (e.g. "student:nuke") get only layer 1, never
 * layer 2 — no domain ability is inferred.
 */

/** CASL action strings. */
export const CaslAction = {
  Manage: 'manage',
  Create: 'create',
  Read: 'read',
  Update: 'update',
  Delete: 'delete',
  /** Check exact permission code (e.g. "bill:export-excel").
   *  Used by PermissionGuard so workflow-specific operations remain distinct. */
  Access: 'access',
} as const;
export type CaslAction = (typeof CaslAction)[keyof typeof CaslAction];

/** Subject names for every entity we protect. */
export const SubjectName = {
  all: 'all',
  Student: 'Student',
  Room: 'Room',
  Occupancy: 'Occupancy',
  Expense: 'Expense',
  Bill: 'Bill',
  Deposit: 'Deposit',
  Classroom: 'Classroom',
  Organization: 'Organization',
  ClassRental: 'ClassRental',
  Class: 'Class',
  Schedule: 'Schedule',
  Attendance: 'Attendance',
  Dashboard: 'Dashboard',
  Profile: 'Profile',
  Notification: 'Notification',
  OperationLog: 'OperationLog',
  User: 'User',
  Role: 'Role',
  Learning: 'Learning',
  Exam: 'Exam',
  Sync: 'Sync',
  Integration: 'Integration',
  Department: 'Department',
  AiConfig: 'AiConfig',
} as const;
export type SubjectName = (typeof SubjectName)[keyof typeof SubjectName];

/** Build the exact-code CASL subject string for a permission code. */
export function permissionCodeSubject(code: string): string {
  return `PermissionCode:${code}`;
}

// ---------------------------------------------------------------------------
//  Domain-level action mapping: permission code → CASL action
//  Used ONLY for the domain layer — not for exact-code access checks.
// ---------------------------------------------------------------------------

function permissionToAction(permission: string): CaslAction | null {
  const actionSegment = permission.split(':')[1] ?? permission;

  // Only strictly equivalent CRUD/read permission codes create broad domain
  // abilities. Workflow-specific operations remain exact-code-only so that,
  // for example, export cannot satisfy read and approve cannot satisfy update.
  switch (actionSegment) {
    case 'create':
      return CaslAction.Create;
    case 'view':
    case 'read':
      return CaslAction.Read;
    case 'edit':
    case 'update':
      return CaslAction.Update;
    case 'delete':
      return CaslAction.Delete;
    default:
      return null;
  }
}

function permissionToSubject(resource: string): SubjectName | null {
  switch (resource) {
    case 'dashboard':
      return SubjectName.Dashboard;
    case 'profile':
      return SubjectName.Profile;
    case 'notification':
      return SubjectName.Notification;
    case 'student':
      return SubjectName.Student;
    case 'room':
      return SubjectName.Room;
    case 'occupancy':
      return SubjectName.Occupancy;
    case 'expense':
      return SubjectName.Expense;
    case 'bill':
      return SubjectName.Bill;
    case 'deposit':
      return SubjectName.Deposit;
    case 'classroom':
      return SubjectName.Classroom;
    case 'organization':
      return SubjectName.Organization;
    case 'rental':
      return SubjectName.ClassRental;
    case 'log':
      return SubjectName.OperationLog;
    case 'user':
      return SubjectName.User;
    case 'role':
      return SubjectName.Role;
    case 'class':
      return SubjectName.Class;
    case 'schedule':
      return SubjectName.Schedule;
    case 'attendance':
      return SubjectName.Attendance;
    case 'learning':
      return SubjectName.Learning;
    case 'exam':
      return SubjectName.Exam;
    case 'sync':
      return SubjectName.Sync;
    case 'integration':
      return SubjectName.Integration;
    case 'department':
      return SubjectName.Department;
    case 'ai':
      return SubjectName.AiConfig;
    default:
      return null;
  }
}

export interface AbilityPermissionRule {
  action: CaslAction;
  subject: SubjectName;
}

/**
 * Map a known `resource:action` permission code to a domain-level
 * CASL rule, or `null` if the resource segment is unrecognised.
 *
 * Domain-level rules are used by services for data-scoping checks.
 * They are NOT used for exact-code access control — use
 * {@link permissionCodeSubject} for that.
 */
export function mapPermissionCode(code: string): AbilityPermissionRule | null {
  const [resource] = code.split(':');
  const subject = permissionToSubject(resource ?? '');
  if (!subject) return null;
  const action = permissionToAction(code);
  if (!action) return null;
  return { action, subject };
}

/**
 * Whether the permission code is "known" — i.e. the resource maps to a
 * recognised subject.
 */
export function isKnownPermissionCode(code: string): boolean {
  const [resource] = code.split(':');
  return permissionToSubject(resource ?? '') !== null;
}
