// #region PermissionsModule [C:3] [TYPE Module] [SEMANTICS auth, rbac, permission, role, guard]
// @BRIEF Shared frontend RBAC utilities for route guards, permission checks, and menu visibility based on user roles.
// @RELATION DEPENDS_ON -> [AuthStore]

// #region Permissions:Module [TYPE Function]
// @SEMANTICS: auth, permissions, rbac, roles
// @PURPOSE: Shared frontend RBAC utilities for route guards and menu visibility.
// @LAYER Domain
// @RELATION DEPENDS_ON -> [EXT:frontend:authStore]
// @INVARIANT: Admin role always bypasses explicit permission checks.

interface UserRole {
    name?: string;
    permissions?: (string | PermissionObject)[];
}

interface PermissionObject {
    resource?: string;
    action?: string;
}

interface User {
    roles?: UserRole[];
}

interface NormalizedPermission {
    resource: string | null;
    action: string;
}

const KNOWN_ACTIONS = new Set(["READ", "WRITE", "EXECUTE", "DELETE"]);

function normalizeAction(action: string, fallback = "READ"): string {
  const normalized = String(action || "").trim().toUpperCase();
  if (!normalized) return fallback;
  return normalized;
}

// #region normalizePermissionRequirement:Function [TYPE Function]
// @PURPOSE: Convert permission requirement string to canonical resource/action tuple.
// @PRE: Permission can be "resource" or "resource:ACTION" where resource itself may contain ":".
// @POST: Returns normalized object with action in uppercase.
export function normalizePermissionRequirement(permission: string, defaultAction = "READ"): NormalizedPermission {
  const fallbackAction = normalizeAction(defaultAction, "READ");
  const rawPermission = String(permission || "").trim();

  if (!rawPermission) {
    return { resource: null, action: fallbackAction };
  }

  const parts = rawPermission.split(":");
  if (parts.length > 1) {
    const tail = normalizeAction(parts[parts.length - 1], fallbackAction);
    if (KNOWN_ACTIONS.has(tail)) {
      const resource = parts.slice(0, -1).join(":");
      return { resource, action: tail };
    }
  }

  return { resource: rawPermission, action: fallbackAction };
}
// #endregion normalizePermissionRequirement:Function

// #region isAdminUser:Function [TYPE Function]
// @PURPOSE: Determine whether user has Admin role.
// @PRE: user can be null or partially populated.
// @POST: Returns true when at least one role name equals "Admin" (case-insensitive).
export function isAdminUser(user: User | null | undefined): boolean {
  const roles = Array.isArray(user?.roles) ? user.roles : [];
  return roles.some(
    (role) => String(role?.name || "").trim().toLowerCase() === "admin",
  );
}
// #endregion isAdminUser:Function

// #region hasPermission:Function [TYPE Function]
// @PURPOSE: Check if user has a required resource/action permission.
// @PRE: user contains roles with permissions from /api/auth/me payload.
// @POST: Returns true when requirement is empty, user is admin, or matching permission exists.
export function hasPermission(user: User | null | undefined, requirement: string, action = "READ"): boolean {
  if (!requirement) return true;
  if (!user) return false;
  if (isAdminUser(user)) return true;

  const { resource, action: requiredAction } = normalizePermissionRequirement(
    requirement,
    action,
  );
  if (!resource) return true;

  const roles = Array.isArray(user.roles) ? user.roles : [];
  for (const role of roles) {
    const permissions = Array.isArray(role?.permissions) ? role.permissions : [];
    for (const permission of permissions) {
      if (typeof permission === "string") {
        const normalized = normalizePermissionRequirement(
          permission,
          requiredAction,
        );
        if (
          normalized.resource === resource &&
          normalized.action === requiredAction
        ) {
          return true;
        }
        continue;
      }

      const permissionResource = String(permission?.resource || "").trim();
      const permissionAction = normalizeAction(permission?.action || "", "");
      if (
        permissionResource === resource &&
        permissionAction === requiredAction
      ) {
        return true;
      }
    }
  }

  return false;
}
// #endregion hasPermission:Function

// #endregion Permissions:Module
// #endregion PermissionsModule
