"use client";

import {
  Box,
  Group,
  ScrollArea,
  Text,
  UnstyledButton,
} from "@mantine/core";
import {
  IconChevronDown,
  IconChevronRight,
  IconFolder,
  IconFolderOpen,
  IconStack2,
} from "@tabler/icons-react";
import React, { useMemo, useState } from "react";
import type { EDMFolder } from "@/lib/features/edm/types";
import { WorkflowStatusDot } from "@/components/WorkflowStatusBadge";
import type { WorkflowStatus } from "@/lib/features/workflow/types";

interface Props {
  folders: EDMFolder[];
  activeId: string | null;
  onSelect: (id: string | null) => void;
  /** Approval state per folder id, for the dot beside each name. */
  statuses?: Record<string, WorkflowStatus>;
}

/**
 * Whole-tree navigation next to the folder listing.
 *
 * The listing on its own shows one level, which is fine for walking into a
 * folder and hopeless for "where am I and what else is there". This is built
 * from the flat folder list the browser already fetches for its move picker —
 * no extra request, and no per-node fetching, so expanding is instant.
 */
export function EDMFolderTreePane({
  folders,
  activeId,
  onSelect,
  statuses = {},
}: Props) {
  const { byParent, orphans } = useMemo(() => {
    const ids = new Set(folders.map((f) => f.id));
    const map = new Map<string | null, EDMFolder[]>();
    // A folder whose parent is missing would never be reached by the walk and
    // would silently disappear from navigation.
    const detached: EDMFolder[] = [];

    for (const f of folders) {
      const parent = f.parent_id ?? null;
      if (parent !== null && !ids.has(parent)) {
        detached.push(f);
        continue;
      }
      map.set(parent, [...(map.get(parent) ?? []), f]);
    }
    for (const list of map.values()) {
      list.sort(
        (a, b) => a.sort_order - b.sort_order || a.name.localeCompare(b.name),
      );
    }
    return { byParent: map, orphans: detached };
  }, [folders]);

  /**
   * Which folders are expanded.
   *
   * Ancestors of the open folder start expanded, so navigating from anywhere
   * leaves the tree showing where you landed rather than collapsed at the root.
   */
  const [expanded, setExpanded] = useState<Set<string>>(new Set());
  const ancestorsOfActive = useMemo(() => {
    const byId = new Map(folders.map((f) => [f.id, f]));
    const out = new Set<string>();
    let cursor = activeId ? byId.get(activeId) : undefined;
    while (cursor?.parent_id) {
      out.add(cursor.parent_id);
      cursor = byId.get(cursor.parent_id);
    }
    return out;
  }, [folders, activeId]);

  const isOpen = (id: string) => expanded.has(id) || ancestorsOfActive.has(id);

  const toggle = (id: string) =>
    setExpanded((prev) => {
      const next = new Set(prev);
      // An ancestor of the active folder is open without being in the set, so
      // collapsing it means explicitly adding it and taking it back out.
      if (next.has(id)) next.delete(id);
      else if (ancestorsOfActive.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });

  const renderLevel = (parent: string | null, depth: number): React.ReactNode =>
    (byParent.get(parent) ?? []).map((f) => {
      const children = byParent.get(f.id) ?? [];
      const open = isOpen(f.id);
      return (
        <Box key={f.id}>
          <UnstyledButton
            onClick={() => onSelect(f.id)}
            style={{
              display: "block",
              width: "100%",
              paddingLeft: 8 + depth * 12,
              paddingRight: 8,
              borderRadius: 6,
              backgroundColor:
                activeId === f.id ? "var(--mantine-color-blue-0)" : undefined,
            }}
          >
            <Group gap={4} py={4} wrap="nowrap">
              <Box
                component="span"
                onClick={(e) => {
                  // Expanding is not navigating — otherwise there is no way to
                  // peek into a folder without leaving the one you are in.
                  e.stopPropagation();
                  if (children.length) toggle(f.id);
                }}
                style={{
                  display: "inline-flex",
                  width: 14,
                  cursor: children.length ? "pointer" : "default",
                }}
              >
                {children.length > 0 &&
                  (open ? (
                    <IconChevronDown size={12} />
                  ) : (
                    <IconChevronRight size={12} />
                  ))}
              </Box>
              {open && children.length > 0 ? (
                <IconFolderOpen size={14} color="var(--mantine-color-blue-6)" />
              ) : (
                <IconFolder size={14} color="var(--mantine-color-blue-6)" />
              )}
              <Text
                size="xs"
                fw={activeId === f.id ? 600 : 400}
                truncate
                style={{ flex: 1 }}
              >
                {f.name}
              </Text>
              <WorkflowStatusDot status={statuses[f.id]} />
            </Group>
          </UnstyledButton>
          {open && renderLevel(f.id, depth + 1)}
        </Box>
      );
    });

  return (
    <Box
      style={{
        border: "1px solid var(--mantine-color-gray-3)",
        borderRadius: 12,
        overflow: "hidden",
        height: "100%",
      }}
    >
      <Text size="xs" fw={600} c="dimmed" px="sm" py={8}>
        FOLDERS
      </Text>
      <ScrollArea.Autosize mah={520}>
        <Box pb="xs">
          <UnstyledButton
            onClick={() => onSelect(null)}
            style={{
              display: "block",
              width: "100%",
              paddingLeft: 8,
              paddingRight: 8,
              borderRadius: 6,
              backgroundColor:
                activeId === null ? "var(--mantine-color-blue-0)" : undefined,
            }}
          >
            <Group gap={4} py={4} wrap="nowrap">
              <Box component="span" style={{ width: 14 }} />
              <IconStack2 size={14} color="var(--mantine-color-gray-6)" />
              <Text size="xs" fw={activeId === null ? 600 : 400}>
                All templates
              </Text>
            </Group>
          </UnstyledButton>

          {renderLevel(null, 1)}

          {orphans.map((o) => (
            <UnstyledButton
              key={o.id}
              onClick={() => onSelect(o.id)}
              style={{ display: "block", width: "100%", paddingLeft: 20 }}
            >
              <Group gap={4} py={4} wrap="nowrap">
                <IconFolder size={14} color="var(--mantine-color-orange-6)" />
                <Text size="xs" c="orange.8" truncate>
                  {o.name} (detached)
                </Text>
              </Group>
            </UnstyledButton>
          ))}

          {folders.length === 0 && (
            <Text size="xs" c="dimmed" px="sm" py={4} fs="italic">
              no folders yet
            </Text>
          )}
        </Box>
      </ScrollArea.Autosize>
    </Box>
  );
}
