import { useMemo } from 'react';
import { useRoleConfig, type RoleConfig } from '@/context/role-config-provider';
import type { RoleConfigRole, HierarchyEntry } from '@/utills/constant';

// ── Return type ─────────────────────────────────────────────────────────────

export interface UseRolesReturn {
  /** Is the given role below the current user in the hierarchy? */
  isChildRole: (roleId: number) => boolean;
  /** Is the given role a manager (i.e. it has subordinates)? */
  isManagerRole: (roleId: number) => boolean;
  /** Is the given role a leaf (i.e. it has no subordinates)? */
  isLeafRole: (roleId: number) => boolean;
  /** Look up a role's config by its numeric ID */
  getRoleById: (roleId: number) => RoleConfigRole | undefined;
  /** Look up a role's config by its name (case-insensitive) */
  getRoleByName: (name: string) => RoleConfigRole | undefined;
  /**
   * Returns an ordered list of manager roles below the current user,
   * suitable for building progressive / cascading dropdown selectors.
   * The list is sorted from the role directly under the user down to the
   * deepest manager role.
   */
  getDropdownChain: () => RoleConfigRole[];
  /** Can the current user drill down to this role in the hierarchy? */
  canCurrentUserSee: (roleId: number) => boolean;
  /** Raw config from the provider (roles, hierarchy, etc.) */
  config: RoleConfig;
}

// ── Helpers ─────────────────────────────────────────────────────────────────

/**
 * Build an ordered chain of manager roles below `startRoleId`.
 * Each entry is a role that itself manages at least one other role.
 * The list is BFS-ordered (closest to `startRoleId` first).
 */
function buildDropdownChain(
  startRoleId: number,
  hierarchy: HierarchyEntry[],
  roles: RoleConfigRole[],
  managerRoles: number[],
): RoleConfigRole[] {
  const chain: RoleConfigRole[] = [];
  const visited = new Set<number>();
  const queue: number[] = [startRoleId];

  while (queue.length > 0) {
    const current = queue.shift()!;
    const directChildren = hierarchy
      .filter((h) => h.parent_role_id === current)
      .map((h) => h.child_role_id);

    for (const childId of directChildren) {
      if (visited.has(childId)) continue;
      visited.add(childId);

      // Only include if the child is itself a manager
      if (managerRoles.includes(childId)) {
        const role = roles.find((r) => r.id === childId);
        if (role) {
          chain.push(role);
        }
      }
      queue.push(childId);
    }
  }

  return chain;
}

// ── Hook ────────────────────────────────────────────────────────────────────

export function useRoles(): UseRolesReturn {
  const config = useRoleConfig();
  const { roles, hierarchy, currentUserRole, childRoles, managerRoles } = config;

  // Build a Set for fast child-role lookups
  const childRoleSet = useMemo(() => new Set(childRoles), [childRoles]);
  const managerRoleSet = useMemo(() => new Set(managerRoles), [managerRoles]);

  // Set of all role IDs that are a parent of at least one other role
  const parentRoleIds = useMemo(() => {
    const ids = new Set<number>();
    for (const h of hierarchy) {
      ids.add(h.parent_role_id);
    }
    return ids;
  }, [hierarchy]);

  const isChildRole = (roleId: number): boolean => {
    return childRoleSet.has(roleId);
  };

  const isManagerRole = (roleId: number): boolean => {
    return managerRoleSet.has(roleId);
  };

  const isLeafRole = (roleId: number): boolean => {
    return !parentRoleIds.has(roleId);
  };

  const getRoleById = (roleId: number): RoleConfigRole | undefined => {
    return roles.find((r) => r.id === roleId);
  };

  const getRoleByName = (name: string): RoleConfigRole | undefined => {
    const lower = name.toLowerCase();
    return roles.find((r) => r.name.toLowerCase() === lower);
  };

  const getDropdownChain = (): RoleConfigRole[] => {
    if (currentUserRole == null) return [];
    return buildDropdownChain(currentUserRole, hierarchy, roles, managerRoles);
  };

  const canCurrentUserSee = (roleId: number): boolean => {
    if (currentUserRole == null) return false;
    // The user can always see their own role level
    if (roleId === currentUserRole) return true;
    return childRoleSet.has(roleId);
  };

  return {
    isChildRole,
    isManagerRole,
    isLeafRole,
    getRoleById,
    getRoleByName,
    getDropdownChain,
    canCurrentUserSee,
    config,
  };
}

export default useRoles;
