export function collectOrganizationEmployees(node) {
  const employees = [];
  const seenKeys = new Set();

  collectFromNode(node, node, employees, seenKeys, []);
  return employees;
}

export function countOrganizationEmployees(node) {
  return collectOrganizationEmployees(node).length;
}

function collectFromNode(node, parentNode, employees, seenKeys, pathParts) {
  if (!node) {
    return;
  }

  if (isEmployeeNode(node)) {
    appendEmployee(node, parentNode, employees, seenKeys, pathParts);
    return;
  }

  const currentPathParts = [...pathParts, nodeLabel(node)].filter(Boolean);

  for (const employee of Array.isArray(node.employees) ? node.employees : []) {
    appendEmployee(employee, node, employees, seenKeys, currentPathParts);
  }

  for (const child of Array.isArray(node.children) ? node.children : []) {
    if (isOrganizationNode(child)) {
      collectFromNode(child, child, employees, seenKeys, currentPathParts);
    } else if (isEmployeeNode(child)) {
      appendEmployee(child, node, employees, seenKeys, currentPathParts);
    }
  }
}

function appendEmployee(employee, parentNode, employees, seenKeys, pathParts) {
  const key = employeeKey(employee);
  if (!key || seenKeys.has(key)) {
    return;
  }

  const organizationPathParts = Array.isArray(employee.organization_path_parts) && employee.organization_path_parts.length
    ? employee.organization_path_parts
    : pathParts;

  seenKeys.add(key);
  employees.push({
    ...employee,
    parent_node_id: employee.parent_node_id ?? nodeId(parentNode),
    parent_node_label: employee.parent_node_label ?? nodeLabel(parentNode),
    organization_path_parts: organizationPathParts,
    organization_path: employee.organization_path || organizationPathParts.join(" / ")
  });
}

function isOrganizationNode(node) {
  return Boolean(node) && node.node_type !== "EMPLOYEE" && !node.employee_id;
}

function isEmployeeNode(node) {
  return Boolean(node) && (node.node_type === "EMPLOYEE" || Boolean(node.employee_id));
}

function employeeKey(employee) {
  return String(employee?.employee_id ?? employee?.user_id ?? employee?.username ?? employee?.mobile ?? employee?.phone ?? "");
}

function nodeId(node) {
  return node?.node_id ?? node?.id ?? node?.value ?? "";
}

function nodeLabel(node) {
  return node?.node_label || node?.label || node?.name || "";
}
