import permissionConfig from "@/lib/listPermission.json";
import {
  ActionIcon,
  Checkbox,
  Collapse,
  Group,
  Stack,
  Text,
} from "@mantine/core";
import { IconChevronDown, IconChevronRight } from "@tabler/icons-react";
import { useState } from "react";

interface Node {
  label: string;
  key: string;
  children?: Node[];
}

export default function PermissionTree({
  selected,
  onChange,
}: {
  selected: string[];
  onChange: (val: string[]) => void;
}) {
  // Ambil semua child dari node
  const [openNodes, setOpenNodes] = useState<Record<string, boolean>>({});

  function toggleNode(label: string) {
    setOpenNodes((prev) => ({ ...prev, [label]: !prev[label] }));
  }

  function getAllChildKeys(node: Node): string[] {
    let result: string[] = [];
    if (node.children) {
      node.children.forEach((c) => {
        result.push(c.key);
        result = [...result, ...getAllChildKeys(c)];
      });
    }
    return result;
  }

  // Dapatkan parentKey, jika ada
  function getParentKey(key: string) {
    const split = key.split(".");
    if (split.length <= 1) return null;
    split.pop();
    return split.join(".");
  }

  // Update parent ke atas secara rekursif
  function updateParent(next: string[], parentKey: string | null): string[] {
    if (!parentKey) return next;

    const allChildKeys = findAllChildKeysFromKey(parentKey);

    const selectedChild = allChildKeys.filter((c) => next.includes(c));

    if (selectedChild.length === 0) {
      // Semua child uncheck → parent uncheck
      next = next.filter((x) => x !== parentKey);
    } else if (selectedChild.length === allChildKeys.length) {
      // Semua child check → parent check
      if (!next.includes(parentKey)) {
        next.push(parentKey);
      }
    } else {
      // Sebagian child check → parent intermediate (checked = true, rendered sebagai indeterminate)
      if (!next.includes(parentKey)) {
        next.push(parentKey);
      }
    }

    // Rekursif naik ke atas
    return updateParent(next, getParentKey(parentKey));
  }

  // dapatkan child dari string key
  function findAllChildKeysFromKey(parentKey: string) {
    const list: string[] = [];

    function traverse(nodes: Node[]) {
      nodes.forEach((n) => {
        if (n.key.startsWith(parentKey + ".") && n.key !== parentKey) {
          list.push(n.key);
        }
        if (n.children) traverse(n.children);
      });
    }

    traverse(permissionConfig.menus);
    return list;
  }

  const RenderMenu = ({ menu }: { menu: Node }) => {
    const hasChild = menu.children && menu.children.length > 0;
    const open = openNodes[menu.label] ?? false;
    const childKeys = getAllChildKeys(menu);
    const isChecked = selected.includes(menu.key);
    const isIndeterminate =
      !isChecked &&
      selected.some(
        (x) => typeof x === "string" && x.startsWith(menu.key + "."),
      );

    function handleCheck() {
      let next = [...selected];

      if (childKeys.length > 0) {
        // klik parent
        if (!isChecked) {
          next = [...new Set([...next, menu.key, ...childKeys])];
        } else {
          next = next.filter((x) => x !== menu.key && !childKeys.includes(x));
        }

        next = updateParent(next, getParentKey(menu.key));
        onChange(next);
        return;
      }

      // klik child
      if (isChecked) {
        next = next.filter((x) => x !== menu.key);
      } else {
        next.push(menu.key);
      }

      next = updateParent(next, getParentKey(menu.key));
      onChange(next);
    }

    return (
      <Stack gap={4}>
        <Group gap="xs">
          {menu.children && menu.children.length > 0 ? (
            <ActionIcon variant="subtle" onClick={() => toggleNode(menu.label)}>
              {openNodes[menu.label] ? (
                <IconChevronDown size={16} />
              ) : (
                <IconChevronRight size={16} />
              )}
            </ActionIcon>
          ) : (
            <div style={{ width: 28 }} />
          )}

          <Checkbox
            label={menu.label}
            checked={isChecked}
            indeterminate={isIndeterminate}
            onChange={handleCheck}
          />
        </Group>

        {menu.children && (
          <Collapse in={open}>
            <Stack gap={4} pl="md">
              {menu.children.map((child) => (
                <RenderMenu key={child.key} menu={child} />
              ))}
            </Stack>
          </Collapse>
        )}
      </Stack>
    );
  };

  return (
    <Stack>
      <Text size="sm">Hak Akses</Text>
      {permissionConfig.menus
        .filter(
          (menu: Node) =>
            !menu.key.startsWith("api") && !menu.key.startsWith("credential"),
        )
        .map((menu: Node) => (
          <RenderMenu key={menu.key} menu={menu} />
        ))}
    </Stack>
  );
}
