"use client";

import { useCallback, useMemo, type ReactNode } from "react";
import Link from "next/link";
import { useParams, usePathname } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import {
  ChevronRight,
  CircleDot,
  FileText,
  Folder,
  FolderOpen,
  FolderPlus,
  MoreHorizontal,
  PenTool,
  Plus,
} from "lucide-react";

import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { getBaseUrl } from "@/lib/trpc";
import {
  isSidebarNodeExpanded,
  isSidebarSectionExpanded,
  useSidebarStore,
} from "@/lib/stores/sidebar-store";
import { useWorkspaceStore } from "@/lib/stores/workspace-store";
import { cn } from "@/lib/utils";

/** Matches server `ObjectTreeNode` shape from objects.getTree */
export type TreeNodeData = {
  id: string;
  title: string;
  type: string;
  icon: string | null;
  parentId: string | null;
  childCount: number;
  children: TreeNodeData[];
};

export type PartitionedTrees = {
  projects: TreeNodeData[];
  documents: TreeNodeData[];
  whiteboards: TreeNodeData[];
};

function hasDescendantType(node: TreeNodeData, type: string): boolean {
  if (node.type === type) return true;
  return node.children.some((c) => hasDescendantType(c, type));
}

export function partitionRoots(roots: TreeNodeData[]): PartitionedTrees {
  const projects: TreeNodeData[] = [];
  const documents: TreeNodeData[] = [];
  const whiteboards: TreeNodeData[] = [];

  for (const root of roots) {
    if (root.type === "project") {
      projects.push(root);
      continue;
    }
    if (root.type === "whiteboard") {
      whiteboards.push(root);
      continue;
    }
    if (root.type === "document") {
      documents.push(root);
      continue;
    }
    if (root.type === "group") {
      const hasWb = hasDescendantType(root, "whiteboard");
      const hasDoc = hasDescendantType(root, "document");
      if (hasWb && !hasDoc) {
        whiteboards.push(root);
      } else if (hasDoc) {
        documents.push(root);
      } else {
        projects.push(root);
      }
      continue;
    }
    projects.push(root);
  }
  return { projects, documents, whiteboards };
}

const EMPTY_PARTITIONED: PartitionedTrees = {
  projects: [],
  documents: [],
  whiteboards: [],
};

const MOCK_PARTITIONED: PartitionedTrees = {
  projects: [
    {
      id: "10000000-0000-4000-8000-000000000001",
      title: "Project Alpha",
      type: "project",
      icon: null,
      parentId: null,
      childCount: 2,
      children: [
        {
          id: "10000000-0000-4000-8000-000000000002",
          title: "Sprint 1",
          type: "group",
          icon: null,
          parentId: "10000000-0000-4000-8000-000000000001",
          childCount: 2,
          children: [
            {
              id: "10000000-0000-4000-8000-000000000003",
              title: "Task 1",
              type: "task",
              icon: null,
              parentId: "10000000-0000-4000-8000-000000000002",
              childCount: 0,
              children: [],
            },
            {
              id: "10000000-0000-4000-8000-000000000004",
              title: "Task 2",
              type: "task",
              icon: null,
              parentId: "10000000-0000-4000-8000-000000000002",
              childCount: 0,
              children: [],
            },
          ],
        },
        {
          id: "10000000-0000-4000-8000-000000000005",
          title: "Sprint 2",
          type: "group",
          icon: null,
          parentId: "10000000-0000-4000-8000-000000000001",
          childCount: 0,
          children: [],
        },
      ],
    },
    {
      id: "10000000-0000-4000-8000-000000000006",
      title: "Project Beta",
      type: "project",
      icon: null,
      parentId: null,
      childCount: 0,
      children: [],
    },
  ],
  documents: [
    {
      id: "20000000-0000-4000-8000-000000000001",
      title: "Documents",
      type: "group",
      icon: null,
      parentId: null,
      childCount: 2,
      children: [
        {
          id: "20000000-0000-4000-8000-000000000002",
          title: "Meeting Notes",
          type: "document",
          icon: null,
          parentId: "20000000-0000-4000-8000-000000000001",
          childCount: 0,
          children: [],
        },
        {
          id: "20000000-0000-4000-8000-000000000003",
          title: "Product Spec",
          type: "document",
          icon: null,
          parentId: "20000000-0000-4000-8000-000000000001",
          childCount: 0,
          children: [],
        },
      ],
    },
  ],
  whiteboards: [
    {
      id: "30000000-0000-4000-8000-000000000001",
      title: "Whiteboards",
      type: "group",
      icon: null,
      parentId: null,
      childCount: 1,
      children: [
        {
          id: "30000000-0000-4000-8000-000000000002",
          title: "Brainstorm",
          type: "whiteboard",
          icon: null,
          parentId: "30000000-0000-4000-8000-000000000001",
          childCount: 0,
          children: [],
        },
      ],
    },
  ],
};

function TypeIcon({ type }: { type: string }) {
  switch (type) {
    case "project":
      return <Folder className="size-3.5 shrink-0 text-amber-600/90 dark:text-amber-400/90" />;
    case "group":
      return <FolderOpen className="size-3.5 shrink-0 text-muted-foreground" />;
    case "document":
      return <FileText className="size-3.5 shrink-0 text-muted-foreground" />;
    case "whiteboard":
      return <PenTool className="size-3.5 shrink-0 text-muted-foreground" />;
    case "task":
      return <CircleDot className="size-3.5 shrink-0 text-muted-foreground" />;
    default:
      return <Folder className="size-3.5 shrink-0 text-muted-foreground" />;
  }
}

async function fetchObjectsTree(workspaceId: string): Promise<{ tree: TreeNodeData[] }> {
  const input = encodeURIComponent(JSON.stringify({ json: { workspaceId } }));
  const res = await fetch(`${getBaseUrl()}/api/trpc/objects.getTree?input=${input}`, {
    credentials: "include",
    headers: { Accept: "application/json" },
  });
  if (!res.ok) {
    throw new Error(`getTree failed: ${res.status}`);
  }
  const payload = (await res.json()) as unknown;
  const tree = extractTreeFromTrpcPayload(payload);
  if (!tree) {
    throw new Error("getTree: unexpected response shape");
  }
  return { tree };
}

function extractTreeFromTrpcPayload(payload: unknown): TreeNodeData[] | null {
  if (Array.isArray(payload)) {
    const first = payload[0] as { result?: { data?: { json?: { tree?: TreeNodeData[] } } } };
    return first?.result?.data?.json?.tree ?? null;
  }
  const single = payload as { result?: { data?: { json?: { tree?: TreeNodeData[] } } } };
  return single.result?.data?.json?.tree ?? null;
}

function useObjectsTreeQuery(workspaceId: string | undefined) {
  return useQuery({
    queryKey: ["objects", "getTree", workspaceId],
    queryFn: () => fetchObjectsTree(workspaceId!),
    enabled: Boolean(workspaceId),
    retry: false,
  });
}

function countNodes(roots: TreeNodeData[]): number {
  let n = 0;
  const walk = (nodes: TreeNodeData[]) => {
    for (const node of nodes) {
      n += 1;
      walk(node.children);
    }
  };
  walk(roots);
  return n;
}

function CollapsibleBody({
  open,
  children,
}: {
  open: boolean;
  children: ReactNode;
}) {
  return (
    <div
      className={cn(
        "grid transition-[grid-template-rows] duration-200 ease-out",
        open ? "grid-rows-[1fr]" : "grid-rows-[0fr]",
      )}
    >
      <div className="overflow-hidden">{children}</div>
    </div>
  );
}

export function TreeNode({
  node,
  level,
  collapsed,
  base,
  pathname,
}: {
  node: TreeNodeData;
  level: number;
  collapsed: boolean;
  base: string;
  pathname: string | null;
}) {
  const expandedNodes = useSidebarStore((s) => s.expandedNodes);
  const toggleNode = useSidebarStore((s) => s.toggleNode);

  const hasChildren = node.children.length > 0;
  const expanded = isSidebarNodeExpanded(expandedNodes, node.id);
  const href = `${base}/o/${node.id}`;
  const active =
    pathname === href ||
    (pathname?.startsWith(`${base}/o/${node.id}/`) ?? false);

  const onToggleExpand = useCallback(
    (e: React.MouseEvent) => {
      e.preventDefault();
      e.stopPropagation();
      toggleNode(node.id);
    },
    [node.id, toggleNode],
  );

  if (collapsed) {
    const link = (
      <Link
        href={href}
        className={cn(
          "flex h-8 w-full items-center justify-center rounded-md text-sidebar-foreground transition-colors duration-150",
          "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
          active &&
            "bg-sidebar-accent text-sidebar-accent-foreground shadow-[inset_3px_0_0_0_hsl(var(--primary))]",
        )}
      >
        <TypeIcon type={node.type} />
      </Link>
    );
    return (
      <div className="w-full">
        <Tooltip delayDuration={0}>
          <TooltipTrigger asChild>{link}</TooltipTrigger>
          <TooltipContent side="right" className="max-w-[240px] font-medium">
            {node.title}
          </TooltipContent>
        </Tooltip>
        {hasChildren ? (
          <div className="flex flex-col gap-px border-l border-sidebar-border/60 pl-1">
            {node.children.map((ch) => (
              <TreeNode
                key={ch.id}
                node={ch}
                level={level + 1}
                collapsed={collapsed}
                base={base}
                pathname={pathname}
              />
            ))}
          </div>
        ) : null}
      </div>
    );
  }

  const indentPx = 8 + level * 16;

  return (
    <div className="select-none">
      <div
        className="group relative flex min-h-7 items-center gap-0.5 rounded-md pr-1 transition-colors duration-150"
        style={{ paddingLeft: indentPx }}
      >
        <div className="flex min-h-7 min-w-0 flex-1 items-center gap-0.5">
          {hasChildren ? (
            <button
              type="button"
              onClick={onToggleExpand}
              className="flex size-6 shrink-0 items-center justify-center rounded-sm text-muted-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
              aria-expanded={expanded}
              aria-label={expanded ? "Collapse" : "Expand"}
            >
              <ChevronRight
                className={cn(
                  "size-3.5 transition-transform duration-200",
                  expanded && "rotate-90",
                )}
              />
            </button>
          ) : (
            <span className="size-6 shrink-0" aria-hidden />
          )}

          <Link
            href={href}
            className={cn(
              "flex min-h-7 min-w-0 flex-1 items-center gap-2 rounded-sm py-1 pl-0.5 pr-2 text-sm text-sidebar-foreground transition-colors duration-150",
              "hover:bg-sidebar-accent/80 hover:text-sidebar-accent-foreground",
              active &&
                "bg-sidebar-accent text-sidebar-accent-foreground shadow-[inset_3px_0_0_0_hsl(var(--primary))]",
            )}
          >
            <TypeIcon type={node.type} />
            <span className="min-w-0 flex-1 truncate font-medium">{node.title}</span>
            {node.childCount > 0 ? (
              <span className="shrink-0 tabular-nums text-[10px] text-muted-foreground">
                {node.childCount}
              </span>
            ) : null}
          </Link>
        </div>

        <div
          className={cn(
            "pointer-events-none flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity duration-150",
            "group-hover:pointer-events-auto group-hover:opacity-100",
          )}
        >
          <Tooltip delayDuration={0}>
            <TooltipTrigger asChild>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className="size-6 text-muted-foreground hover:text-sidebar-accent-foreground"
                onClick={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                }}
              >
                <Plus className="size-3.5" />
              </Button>
            </TooltipTrigger>
            <TooltipContent side="top">Add child</TooltipContent>
          </Tooltip>

          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className="size-6 text-muted-foreground hover:text-sidebar-accent-foreground"
                onClick={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                }}
              >
                <MoreHorizontal className="size-3.5" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="w-44" onClick={(e) => e.stopPropagation()}>
              <DropdownMenuItem>Rename</DropdownMenuItem>
              <DropdownMenuItem>Duplicate</DropdownMenuItem>
              <DropdownMenuSeparator />
              <DropdownMenuItem className="text-destructive focus:text-destructive">Archive</DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </div>

      {hasChildren ? (
        <CollapsibleBody open={expanded}>
          <div className="flex flex-col gap-px pb-0.5">
            {node.children.map((ch) => (
              <TreeNode
                key={ch.id}
                node={ch}
                level={level + 1}
                collapsed={collapsed}
                base={base}
                pathname={pathname}
              />
            ))}
          </div>
        </CollapsibleBody>
      ) : null}
    </div>
  );
}

function SectionHeader({
  title,
  sectionKey,
  collapsed,
}: {
  title: string;
  sectionKey: string;
  collapsed: boolean;
}) {
  const expandedSections = useSidebarStore((s) => s.expandedSections);
  const toggleSection = useSidebarStore((s) => s.toggleSection);
  const open = isSidebarSectionExpanded(expandedSections, sectionKey);

  if (collapsed) {
    return (
      <div className="flex justify-center py-1">
        <Tooltip delayDuration={0}>
          <TooltipTrigger asChild>
            <Button
              type="button"
              variant="ghost"
              size="icon"
              className="size-8 text-muted-foreground hover:bg-sidebar-accent"
              onClick={() => toggleSection(sectionKey)}
            >
              <ChevronRight
                className={cn("size-3.5 transition-transform", open && "rotate-90")}
              />
            </Button>
          </TooltipTrigger>
          <TooltipContent side="right">{title}</TooltipContent>
        </Tooltip>
      </div>
    );
  }

  return (
    <Button
      type="button"
      variant="ghost"
      className="mb-0.5 flex h-7 w-full items-center justify-between rounded-md px-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
      onClick={() => toggleSection(sectionKey)}
    >
      <span>{title}</span>
      <ChevronRight
        className={cn("size-3.5 shrink-0 transition-transform duration-200", open && "rotate-90")}
      />
    </Button>
  );
}

export function NavTree({
  collapsed,
  trees: treesProp,
}: {
  collapsed: boolean;
  trees?: PartitionedTrees;
}) {
  const pathname = usePathname();
  const params = useParams();
  const workspace = useWorkspaceStore((s) => s.currentWorkspace);
  const slugParam =
    typeof params?.workspaceSlug === "string" ? params.workspaceSlug : "";
  const base = workspace?.slug
    ? `/${workspace.slug}`
    : slugParam
      ? `/${slugParam}`
      : "";

  const workspaceId = workspace?.id;
  const { data, isLoading, isError } = useObjectsTreeQuery(workspaceId);

  const partitioned = useMemo(() => {
    if (treesProp) return treesProp;
    if (!workspaceId) return MOCK_PARTITIONED;
    if (isLoading) return EMPTY_PARTITIONED;
    if (isError || !data?.tree) return MOCK_PARTITIONED;
    return partitionRoots(data.tree);
  }, [treesProp, workspaceId, isLoading, isError, data?.tree]);

  const totalCount =
    countNodes(partitioned.projects) +
    countNodes(partitioned.documents) +
    countNodes(partitioned.whiteboards);

  const liveEmpty =
    Boolean(workspaceId) &&
    !isLoading &&
    !isError &&
    data?.tree &&
    data.tree.length === 0;

  const showLoading = Boolean(workspaceId) && isLoading && !treesProp;

  const expandedSections = useSidebarStore((s) => s.expandedSections);

  const projectsOpen = isSidebarSectionExpanded(expandedSections, "projects");
  const documentsOpen = isSidebarSectionExpanded(expandedSections, "documents");
  const whiteboardsOpen = isSidebarSectionExpanded(expandedSections, "whiteboards");

  if (showLoading) {
    return (
      <ScrollArea className="flex-1">
        <div className="flex flex-col gap-2 px-3 pb-4 pt-2">
          <div className="h-7 animate-pulse rounded-md bg-sidebar-accent/50" />
          <div className="h-7 animate-pulse rounded-md bg-sidebar-accent/40" />
          <div className="h-7 animate-pulse rounded-md bg-sidebar-accent/30" />
          <div className="h-7 animate-pulse rounded-md bg-sidebar-accent/25" />
        </div>
      </ScrollArea>
    );
  }

  return (
    <ScrollArea className="flex-1">
      <div className="flex flex-col gap-0.5 px-2 pb-4 pt-1">
        {liveEmpty ? (
          <div className="rounded-md border border-dashed border-sidebar-border px-3 py-6 text-center text-xs text-muted-foreground">
            No projects, documents, or whiteboards yet.
            <br />
            <span className="text-[10px]">Create a project to get started.</span>
          </div>
        ) : null}

        {!liveEmpty && totalCount === 0 ? (
          <div className="rounded-md border border-dashed border-sidebar-border px-3 py-6 text-center text-xs text-muted-foreground">
            Nothing to show yet.
          </div>
        ) : null}

        {!liveEmpty && totalCount > 0 ? (
          <>
            <div>
              <SectionHeader title="Projects" sectionKey="projects" collapsed={collapsed} />
              <CollapsibleBody open={projectsOpen || collapsed}>
                <div className={cn("flex flex-col gap-px", collapsed && "items-center")}>
                  {partitioned.projects.map((node) => (
                    <TreeNode
                      key={node.id}
                      node={node}
                      level={0}
                      collapsed={collapsed}
                      base={base}
                      pathname={pathname}
                    />
                  ))}
                </div>
                {!collapsed ? (
                  <Button
                    type="button"
                    variant="ghost"
                    className="mt-1 h-7 w-full justify-start gap-2 px-2 text-xs font-medium text-muted-foreground hover:text-sidebar-accent-foreground"
                    onClick={() => {
                      /* api.objects.create — wire when AppRouter includes objects */
                    }}
                  >
                    <FolderPlus className="size-3.5" />
                    New Project
                  </Button>
                ) : (
                  <div className="mt-1 flex justify-center">
                    <Tooltip delayDuration={0}>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="size-8 text-muted-foreground"
                          onClick={() => {}}
                        >
                          <FolderPlus className="size-4" />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="right">New Project</TooltipContent>
                    </Tooltip>
                  </div>
                )}
              </CollapsibleBody>
            </div>

            <div>
              <SectionHeader title="Documents" sectionKey="documents" collapsed={collapsed} />
              <CollapsibleBody open={documentsOpen || collapsed}>
                <div className={cn("flex flex-col gap-px", collapsed && "items-center")}>
                  {partitioned.documents.map((node) => (
                    <TreeNode
                      key={node.id}
                      node={node}
                      level={0}
                      collapsed={collapsed}
                      base={base}
                      pathname={pathname}
                    />
                  ))}
                </div>
              </CollapsibleBody>
            </div>

            <div>
              <SectionHeader title="Whiteboards" sectionKey="whiteboards" collapsed={collapsed} />
              <CollapsibleBody open={whiteboardsOpen || collapsed}>
                <div className={cn("flex flex-col gap-px", collapsed && "items-center")}>
                  {partitioned.whiteboards.map((node) => (
                    <TreeNode
                      key={node.id}
                      node={node}
                      level={0}
                      collapsed={collapsed}
                      base={base}
                      pathname={pathname}
                    />
                  ))}
                </div>
              </CollapsibleBody>
            </div>
          </>
        ) : null}
      </div>
    </ScrollArea>
  );
}
