import type { DecisionPolicy } from "./advanced.ts";

/** Narrows an assignment to a tenant. Absent means a global assignment. */
export interface AuthzScope {
  tenantId?: string;
}

export interface PermissionMeta {
  title?: string;
  description?: string;
  risk?: "low" | "medium" | "high";
  /** Granted to anonymous subjects. Every other permission denies without a user. */
  public?: boolean;
}

export interface AttributeMeta {
  description?: string;
}

/** One `app/authz/<name>.ts` declaration. */
export interface AuthzModule {
  permissions?: Record<string, PermissionMeta>;
  roles?: Record<string, string[]>;
  policies?: Record<string, DecisionPolicy<never, never>>;
  attributes?: Record<string, AttributeMeta>;
  /** permission id -> policy names that must pass for it. */
  bindings?: Record<string, string[]>;
}

/** The merged, frozen view of every declaration in the app. */
export interface AuthzCatalog {
  permissions: ReadonlyMap<string, PermissionMeta>;
  roles: ReadonlyMap<string, readonly string[]>;
  policies: ReadonlyMap<string, DecisionPolicy<never, never>>;
  attributes: ReadonlyMap<string, AttributeMeta>;
  bindings: ReadonlyMap<string, readonly string[]>;
}

export interface SubjectAssignments {
  roles: string[];
  /** Explicit allows, bypassing roles. */
  grants: string[];
  /** Explicit denies. Win over everything, including "*". */
  denies: string[];
}
