"use client";

import { ChevronRight, Search } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";

import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state";
import { AdminLoadingInline } from "@/components/admin/admin-loading-state";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import { formatAdminCreditMajorDecimal } from "@/lib/money";
import type { AgentNodeRow } from "@/types/api/admin-agent";

function formatCredit(amount: number, currencyCode = "NPR"): string {
  return formatAdminCreditMajorDecimal(amount, currencyCode);
}

function nodeMatchesKeyword(
  node: AgentNodeRow,
  normalized: string,
  parentNameMap: Map<number, string>,
): boolean {
  if (normalized === "") {
    return true;
  }

  const parentName =
    node.parent_id !== null ? (parentNameMap.get(node.parent_id) ?? "") : "";

  return [node.name, node.code, node.username ?? "", parentName]
    .join(" ")
    .toLowerCase()
    .includes(normalized);
}

function pruneTreeForSearch(
  nodes: AgentNodeRow[],
  normalized: string,
  parentNameMap: Map<number, string>,
): AgentNodeRow[] {
  if (normalized === "") {
    return nodes;
  }

  const out: AgentNodeRow[] = [];

  for (const node of nodes) {
    const children = pruneTreeForSearch(node.children ?? [], normalized, parentNameMap);
    const selfMatch = nodeMatchesKeyword(node, normalized, parentNameMap);

    if (selfMatch || children.length > 0) {
      out.push({ ...node, children });
    }
  }

  return out;
}

function collectSearchExpandIds(
  nodes: AgentNodeRow[],
  normalized: string,
  parentNameMap: Map<number, string>,
): Set<number> {
  const ids = new Set<number>();

  const walk = (list: AgentNodeRow[], ancestors: number[]): void => {
    for (const node of list) {
      const children = node.children ?? [];
      const prunedChildren = pruneTreeForSearch(children, normalized, parentNameMap);
      const selfMatch = nodeMatchesKeyword(node, normalized, parentNameMap);

      if (selfMatch || prunedChildren.length > 0) {
        for (const id of ancestors) {
          ids.add(id);
        }
        if (prunedChildren.length > 0) {
          ids.add(node.id);
        }
        walk(prunedChildren, [...ancestors, node.id]);
      }
    }
  };

  walk(nodes, []);

  return ids;
}

export type AgentLineSidebarProps = {
  /** API 返回的嵌套树（含 children） */
  tree: AgentNodeRow[];
  parentNameMap: Map<number, string>;
  selectedId: number | null;
  keyword: string;
  loading?: boolean;
  onKeywordChange: (value: string) => void;
  onSelect: (node: AgentNodeRow) => void;
  errorMessage?: string | null;
  onRetry?: () => void;
};

type TreeRowProps = {
  node: AgentNodeRow;
  depth: number;
  selectedId: number | null;
  expandedIds: Set<number>;
  onToggleExpand: (id: number) => void;
  onSelect: (node: AgentNodeRow) => void;
};

function TreeRow({
  node,
  depth,
  selectedId,
  expandedIds,
  onToggleExpand,
  onSelect,
}: TreeRowProps): React.ReactElement {
  const { t } = useTranslation(["agents", "common"]);
  const children = node.children ?? [];
  const hasChildren = children.length > 0;
  const expanded = expandedIds.has(node.id);
  const active = selectedId === node.id;
  const indent = depth * 14;

  return (
    <li>
      <div
        className={cn(
          "flex w-full items-start gap-0.5 rounded-md py-1 pr-2 transition-colors",
          active ? "bg-primary/10 ring-1 ring-primary/25" : "hover:bg-muted/15",
        )}
        style={{ paddingLeft: `${6 + indent}px` }}
      >
        {hasChildren ? (
          <button
            type="button"
            aria-expanded={expanded}
            aria-label={expanded ? t("lineUi.collapse", { defaultValue: "收起" }) : t("lineUi.expand", { defaultValue: "展开" })}
            className="mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted"
            onClick={(e) => {
              e.stopPropagation();
              onToggleExpand(node.id);
            }}
          >
            <ChevronRight
              className={cn("size-3.5 transition-transform", expanded && "rotate-90")}
              aria-hidden
            />
          </button>
        ) : (
          <span className="mt-0.5 inline-block size-5 shrink-0" aria-hidden />
        )}
        <button
          type="button"
          role="option"
          aria-selected={active}
          className="min-w-0 flex-1 px-1 py-0.5 text-left"
          onClick={() => onSelect(node)}
        >
          <div className="truncate text-sm font-medium leading-5">{node.name}</div>
          <p className="truncate text-xs leading-5 text-muted-foreground">
            {node.username ?? node.code}
          </p>
        </button>
      </div>
      {hasChildren && expanded ? (
        <ul className="space-y-0.5">
          {children.map((child) => (
            <TreeRow
              key={child.id}
              node={child}
              depth={depth + 1}
              selectedId={selectedId}
              expandedIds={expandedIds}
              onToggleExpand={onToggleExpand}
              onSelect={onSelect}
            />
          ))}
        </ul>
      ) : null}
    </li>
  );
}

export function AgentLineSidebar({
  tree,
  parentNameMap,
  selectedId,
  keyword,
  loading = false,
  onKeywordChange,
  onSelect,
  errorMessage = null,
  onRetry,
}: AgentLineSidebarProps): React.ReactElement {
  const { t } = useTranslation(["agents", "common"]);
  const [expandedIds, setExpandedIds] = useState<Set<number>>(() => new Set());

  const normalizedKeyword = keyword.trim().toLowerCase();

  const displayForest = useMemo(() => {
    return pruneTreeForSearch(tree, normalizedKeyword, parentNameMap);
  }, [normalizedKeyword, parentNameMap, tree]);

  useEffect(() => {
    if (tree.length === 0) {
      setExpandedIds(new Set());
      return;
    }

    setExpandedIds((prev) => {
      const next = new Set(prev);
      for (const node of tree) {
        if ((node.children?.length ?? 0) > 0) {
          next.add(node.id);
        }
      }
      return next;
    });
  }, [tree]);

  useEffect(() => {
    if (selectedId === null) {
      return;
    }

    setExpandedIds((prev) => {
      const next = new Set(prev);
      const walk = (nodes: AgentNodeRow[], ancestors: number[]): boolean => {
        for (const node of nodes) {
          const chain = [...ancestors, node.id];
          if (node.id === selectedId) {
            for (const id of ancestors) {
              next.add(id);
            }

            return true;
          }
          if (walk(node.children ?? [], chain)) {
            return true;
          }
        }

        return false;
      };
      walk(tree, []);

      return next;
    });
  }, [selectedId, tree]);

  useEffect(() => {
    if (normalizedKeyword === "") {
      return;
    }

    const expandIds = collectSearchExpandIds(tree, normalizedKeyword, parentNameMap);
    if (expandIds.size === 0) {
      return;
    }

    setExpandedIds((prev) => new Set([...prev, ...expandIds]));
  }, [normalizedKeyword, parentNameMap, tree]);

  const toggleExpand = useCallback((id: number) => {
    setExpandedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }

      return next;
    });
  }, []);

  const hasAnyAgent = displayForest.length > 0;

  return (
    <aside className="flex min-h-0 h-full w-full flex-col lg:w-[18rem] lg:shrink-0 lg:border-r lg:border-border/70">
      <div className="space-y-3 border-b border-border/60 px-4 py-4">
        <div className="relative">
          <Search className="pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground" />
          <Input
            value={keyword}
            onChange={(e) => onKeywordChange(e.target.value)}
            className="h-9 pl-8 text-sm"
            placeholder={t("lineUi.searchPlaceholder", {
              defaultValue: "搜索名称或登录名",
            })}
          />
        </div>
      </div>

      <div className="min-h-0 flex-1 overflow-y-auto px-2 py-2">
        {loading ? (
          <AdminLoadingInline className="py-10" />
        ) : !hasAnyAgent && errorMessage ? (
          <div className="space-y-3 px-2 py-8 text-center">
            <p className="text-sm text-destructive">{errorMessage}</p>
            {onRetry ? (
              <Button type="button" size="sm" variant="outline" onClick={onRetry}>
                {t("common:actions.retry", { defaultValue: "重试" })}
              </Button>
            ) : null}
          </div>
        ) : !hasAnyAgent ? (
          <AdminNoResourceState className="px-2 py-8 text-center text-sm text-muted-foreground" />
        ) : (
          <ul className="space-y-0.5" role="listbox" aria-label={t("listTitle", { defaultValue: "代理列表" })}>
            {displayForest.map((node) => (
              <TreeRow
                key={node.id}
                node={node}
                depth={0}
                selectedId={selectedId}
                expandedIds={expandedIds}
                onToggleExpand={toggleExpand}
                onSelect={onSelect}
              />
            ))}
          </ul>
        )}
      </div>
    </aside>
  );
}

export { formatCredit };
