import { useMemo, useState } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import type { RuleAccount } from "@/lib/account-rules";

export type TreeAccount = RuleAccount & { account_types: { code?: string; name?: string; category: string } | null };

export type TreeNode<T extends RuleAccount> = { account: T; depth: number; children: TreeNode<T>[] };

/** Builds a parent/child tree ordered by account code. */
export function buildAccountTree<T extends RuleAccount>(accounts: T[]): TreeNode<T>[] {
  const byId = new Map(accounts.map((a) => [a.id, { account: a, depth: 0, children: [] } as TreeNode<T>]));
  const roots: TreeNode<T>[] = [];
  for (const node of byId.values()) {
    const parent = node.account.parent_id ? byId.get(node.account.parent_id) : undefined;
    if (parent && parent !== node) parent.children.push(node);
    else roots.push(node);
  }
  const sortRec = (nodes: TreeNode<T>[], depth: number) => {
    nodes.sort((a, b) => a.account.code.localeCompare(b.account.code));
    for (const n of nodes) {
      n.depth = depth;
      sortRec(n.children, depth + 1);
    }
  };
  sortRec(roots, 0);
  return roots;
}

export function flattenTree<T extends RuleAccount>(
  nodes: TreeNode<T>[],
  collapsed: Set<string>,
): TreeNode<T>[] {
  const out: TreeNode<T>[] = [];
  const walk = (list: TreeNode<T>[]) => {
    for (const n of list) {
      out.push(n);
      if (n.children.length && !collapsed.has(n.account.id)) walk(n.children);
    }
  };
  walk(nodes);
  return out;
}

export function useAccountTree<T extends RuleAccount>(accounts: T[]) {
  const tree = useMemo(() => buildAccountTree(accounts), [accounts]);
  const [collapsed, setCollapsed] = useState<Set<string>>(new Set());
  const toggle = (id: string) =>
    setCollapsed((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  const collapseAll = () => {
    const ids = new Set<string>();
    const walk = (nodes: TreeNode<T>[]) => {
      for (const n of nodes) {
        if (n.children.length) ids.add(n.account.id);
        walk(n.children);
      }
    };
    walk(tree);
    setCollapsed(ids);
  };
  const expandAll = () => setCollapsed(new Set());
  return { tree, collapsed, toggle, collapseAll, expandAll, rows: flattenTree(tree, collapsed) };
}

export function TreeToggle({
  hasChildren,
  open,
  depth,
  onToggle,
}: {
  hasChildren: boolean;
  open: boolean;
  depth: number;
  onToggle: () => void;
}) {
  return (
    <span className="inline-flex items-center" style={{ paddingLeft: depth * 16 }}>
      {hasChildren ? (
        <Button
          size="icon"
          variant="ghost"
          className="size-6 shrink-0"
          aria-label={open ? "Collapse sub-accounts" : "Expand sub-accounts"}
          onClick={onToggle}
        >
          {open ? <ChevronDown className="size-4" /> : <ChevronRight className="size-4" />}
        </Button>
      ) : (
        <span className="inline-block size-6" aria-hidden />
      )}
    </span>
  );
}

/** Selectable tree used by the parent-account picker. */
export function AccountTreePicker({
  accounts,
  value,
  onChange,
  disabledIds = new Set<string>(),
  emptyLabel = "No eligible parent accounts for this type.",
}: {
  accounts: TreeAccount[];
  value: string | null;
  onChange: (id: string | null) => void;
  disabledIds?: Set<string>;
  emptyLabel?: string;
}) {
  const { rows, collapsed, toggle } = useAccountTree(accounts);
  return (
    <div className="max-h-56 overflow-y-auto rounded-md border border-border">
      <button
        type="button"
        onClick={() => onChange(null)}
        className={cn(
          "flex w-full items-center gap-2 px-2 py-1.5 text-left text-sm hover:bg-muted",
          value === null && "bg-primary/10 font-medium",
        )}
      >
        No parent (top level)
      </button>
      {rows.length === 0 ? (
        <p className="px-3 py-3 text-xs text-muted-foreground">{emptyLabel}</p>
      ) : (
        rows.map(({ account, depth, children }) => {
          const disabled = disabledIds.has(account.id);
          return (
            <div key={account.id} className="flex items-center border-t border-border/60">
              <TreeToggle
                hasChildren={children.length > 0}
                open={!collapsed.has(account.id)}
                depth={depth}
                onToggle={() => toggle(account.id)}
              />
              <button
                type="button"
                disabled={disabled}
                onClick={() => onChange(account.id)}
                className={cn(
                  "flex-1 px-2 py-1.5 text-left text-sm hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
                  value === account.id && "bg-primary/10 font-medium",
                )}
              >
                <span className="num mr-2 text-muted-foreground">{account.code}</span>
                {account.name}
              </button>
            </div>
          );
        })
      )}
    </div>
  );
}
