import type { TenantSummary } from "./adminApi";

export type TenantNode = TenantSummary & {
  children: TenantNode[];
  recursiveMemberCount: number;
};

/**
 * Builds a hierarchical tree from a flat list of tenants and calculates
 * direct and recursive member counts for each node.
 */
export function buildTenantFullTree(
  allTenants: TenantSummary[],
  rootId?: string,
  isSearchActive?: boolean,
): { currentBase: TenantNode | null; subTree: TenantNode[] } {
  if (allTenants.length === 0) return { currentBase: null, subTree: [] };

  const tenantMap = new Map<string, TenantNode>();
  for (const t of allTenants) {
    tenantMap.set(t.id, {
      ...t,
      children: [],
      recursiveMemberCount: Number(t.totalMemberCount ?? t.memberCount) || 0,
    });
  }

  // Build initial children relations and prevent simple cycles
  for (const t of allTenants) {
    if (t.parentId && t.parentId !== t.id) {
      const parent = tenantMap.get(t.parentId);
      const child = tenantMap.get(t.id);
      if (parent && child) {
        // Simple cycle prevention during build: don't add if it creates an immediate loop
        parent.children.push(child);
      }
    }
  }

  const visitedForCalc = new Set<string>();
  // Function to calculate recursive counts with cycle protection
  const calculateRecursive = (node: TenantNode): number => {
    if (visitedForCalc.has(node.id)) {
      console.warn(
        `Circular dependency detected in tenant tree for ID: ${node.id}`,
      );
      return 0; // Prevent infinite loop
    }
    visitedForCalc.add(node.id);

    if (typeof node.totalMemberCount === "number") {
      node.recursiveMemberCount = Number(node.totalMemberCount) || 0;
      return node.recursiveMemberCount;
    }

    let total = Number(node.memberCount) || 0;
    for (const child of node.children) {
      total += calculateRecursive(child);
    }
    node.recursiveMemberCount = total;

    return total;
  };

  // If a specific rootId is provided AND search is not active, find and return its subtree.
  // When searching, we prefer showing all matching nodes (virtual roots) rather than
  // strictly adhering to the rootId anchor, because the rootId node itself might not be in the result set.
  if (rootId && !isSearchActive) {
    const base = tenantMap.get(rootId);
    if (base) {
      visitedForCalc.clear();
      calculateRecursive(base);
      return { currentBase: base, subTree: base.children };
    }
    return { currentBase: null, subTree: [] };
  }

  // Identify roots: nodes with no parent, or nodes whose parent is not in the current set (virtual roots during search)
  const roots = Array.from(tenantMap.values()).filter((n) => {
    if (isSearchActive) {
      return !n.parentId || !tenantMap.get(n.parentId);
    }
    return !n.parentId;
  });

  // Calculate for all identified roots
  for (const root of roots) {
    visitedForCalc.clear();
    calculateRecursive(root);
  }

  return { currentBase: null, subTree: roots };
}
