export type Role = "owner" | "admin" | "editor" | "reviewer" | "viewer";

export const ROLES: readonly Role[] = [
  "owner",
  "admin",
  "editor",
  "reviewer",
  "viewer",
] as const;

export type Action =
  // Read
  | "cards.view"
  | "cards.export"
  | "events.view"
  | "people.view"
  | "reports.view"
  | "settings.view"
  // Review (reviewer+)
  | "cards.review"
  // Edit (editor+)
  | "cards.create"
  | "cards.edit"
  | "uploads.create"
  | "events.manage"
  // Admin (admin+)
  | "cards.delete"
  | "cards.assign"
  | "cards.reprocess"
  | "users.view"
  | "users.invite"
  | "settings.edit"
  | "integrations.manage"
  // Owner
  | "users.manage"
  | "org.manage";

const ROLE_HIERARCHY: Record<Role, number> = {
  owner: 5,
  admin: 4,
  editor: 3,
  reviewer: 2,
  viewer: 1,
};

const PERMISSION_MAP: Record<Action, Role> = {
  "cards.view": "viewer",
  "cards.export": "viewer",
  "events.view": "viewer",
  "people.view": "viewer",
  "reports.view": "viewer",
  "settings.view": "viewer",

  "cards.review": "reviewer",

  "cards.create": "editor",
  "cards.edit": "editor",
  "uploads.create": "editor",
  "events.manage": "editor",

  "cards.delete": "admin",
  "cards.assign": "admin",
  "cards.reprocess": "admin",
  "users.view": "admin",
  "users.invite": "admin",
  "settings.edit": "admin",
  "integrations.manage": "admin",

  "users.manage": "owner",
  "org.manage": "owner",
};

export function isRole(value: unknown): value is Role {
  return typeof value === "string" && value in ROLE_HIERARCHY;
}

export function roleLevel(role: string | null | undefined): number {
  if (!role) return 0;
  return ROLE_HIERARCHY[role as Role] ?? 0;
}

export function can(role: string | null | undefined, action: Action): boolean {
  if (!role) return false;
  const minRole = PERMISSION_MAP[action];
  if (!minRole) return false;
  return roleLevel(role) >= ROLE_HIERARCHY[minRole];
}

/**
 * True if role is admin or owner. Shorthand for admin-only UI gates.
 */
export function isAdminRole(role: string | null | undefined): boolean {
  return roleLevel(role) >= ROLE_HIERARCHY.admin;
}

/**
 * True if role can edit content (editor, admin, owner).
 */
export function canEditContent(role: string | null | undefined): boolean {
  return roleLevel(role) >= ROLE_HIERARCHY.editor;
}

export function requirePermission(
  role: string | undefined | null,
  action: Action
): void {
  if (!can(role, action)) {
    throw new PermissionError(`Missing permission: ${action}`);
  }
}

export class PermissionError extends Error {
  public readonly action?: Action;
  constructor(message: string, action?: Action) {
    super(message);
    this.name = "PermissionError";
    this.action = action;
  }
}
