"use client";

import {
  Badge,
  Box,
  Group,
  Loader,
  ScrollArea,
  Text,
  TextInput,
  UnstyledButton,
} from "@mantine/core";
import { notifications } from "@mantine/notifications";
import {
  IconChevronDown,
  IconChevronRight,
  IconFolder,
  IconFolderOpen,
  IconMail,
  IconPhoto,
} from "@tabler/icons-react";
import React, { useCallback, useEffect, useState } from "react";
import { updateEDMFolder, updateEDMTemplate } from "@/lib/features/edm/action";
import { browseEDMFolder } from "@/lib/features/edm/query";
import type { EDMBrowseResult, EDMFolderAsset, EDMFolderTemplate } from "@/lib/features/edm/types";
import {
  WorkflowStatusDot,
  useWorkflowStatuses,
} from "@/components/WorkflowStatusBadge";
import type { WorkflowStatus } from "@/lib/features/workflow/types";

interface Props {
  onOpenTemplate: (t: EDMFolderTemplate) => void;
  onOpenAsset: (a: EDMFolderAsset) => void;
  activeTemplateId: string | null;
  /** Bumped by the parent to force a refetch after a save. */
  refreshToken: number;
  /** Scope the tree to one folder. null = whole store. */
  rootFolderId?: string | null;
  rootLabel?: string;
  /** Enables inline rename and drag-to-move. */
  canEdit?: boolean;
  /** Called after a move or rename so the parent can refresh other views. */
  onChanged?: () => void;
}

/**
 * File-tree sidebar.
 *
 * Each folder fetches its own contents the first time it is expanded and caches
 * them, so opening the workspace costs one request for the root rather than a
 * walk of the whole store. Collapsing keeps the cache — re-expanding is free.
 */
/** Private drag payload type, so a folder never reacts to an unrelated drag. */
const TEMPLATE_DRAG_TYPE = "application/x-edm-template";

/** Re-file a template. folderId null means the top level. */
async function moveTemplate(
  templateId: string,
  folderId: string | null,
  onDone: () => void,
) {
  const res = await updateEDMTemplate(templateId, { folder_id: folderId });
  notifications.show({
    color: res.success ? "green" : "red",
    message: res.success ? "Template moved" : res.message || "Move failed",
  });
  if (res.success) onDone();
}

export function WorkspaceTree({
  onOpenTemplate,
  onOpenAsset,
  activeTemplateId,
  refreshToken,
  rootFolderId = null,
  rootLabel = "All templates",
  canEdit = false,
  onChanged,
}: Props) {
  /**
   * Fetched once for the whole tree rather than per folder node: the tree is
   * recursive and nodes mount as they expand, so a per-node fetch would be one
   * request per expand for data that is the same list every time.
   */
  const templateWorkflow = useWorkflowStatuses("EDM_TEMPLATE", refreshToken);
  const folderWorkflow = useWorkflowStatuses("EDM_FOLDER", refreshToken);

  return (
    <Box style={{ height: "100%", overflow: "hidden" }}>
      <Text size="xs" fw={600} c="dimmed" px="sm" py={8}>
        EXPLORER
      </Text>
      <ScrollArea style={{ height: "calc(100% - 32px)" }}>
        <FolderNode
          folderId={rootFolderId}
          label={rootLabel}
          depth={0}
          defaultOpen
          onOpenTemplate={onOpenTemplate}
          onOpenAsset={onOpenAsset}
          activeTemplateId={activeTemplateId}
          refreshToken={refreshToken}
          canEdit={canEdit}
          onChanged={onChanged}
          templateStatuses={templateWorkflow.statuses}
          folderStatuses={folderWorkflow.statuses}
        />
      </ScrollArea>
    </Box>
  );
}

function FolderNode({
  folderId,
  label,
  depth,
  defaultOpen = false,
  onOpenTemplate,
  onOpenAsset,
  activeTemplateId,
  refreshToken,
  canEdit,
  onChanged,
  templateStatuses,
  folderStatuses,
}: {
  folderId: string | null;
  label: string;
  depth: number;
  defaultOpen?: boolean;
  onOpenTemplate: (t: EDMFolderTemplate) => void;
  onOpenAsset: (a: EDMFolderAsset) => void;
  activeTemplateId: string | null;
  refreshToken: number;
  canEdit?: boolean;
  onChanged?: () => void;
  templateStatuses: Record<string, WorkflowStatus>;
  folderStatuses: Record<string, WorkflowStatus>;
}) {
  const [open, setOpen] = useState(defaultOpen);
  const [data, setData] = useState<EDMBrowseResult | null>(null);
  const [loading, setLoading] = useState(false);
  const [renaming, setRenaming] = useState(false);
  const [renameValue, setRenameValue] = useState(label);
  const [dropTarget, setDropTarget] = useState(false);
  const [localToken, setLocalToken] = useState(0);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const res = await browseEDMFolder(folderId);
      if (res.success && res.data) setData(res.data);
    } finally {
      setLoading(false);
    }
  }, [folderId]);

  useEffect(() => {
    // Only fetch for folders the user has actually opened. An unopened folder
    // costs nothing until it is expanded.
    if (open && (!data || refreshToken || localToken)) void load();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, refreshToken, localToken]);

  const pad = 8 + depth * 12;

  return (
    <Box>
      <UnstyledButton
        onClick={() => { if (!renaming) setOpen((o) => !o); }}
        style={{
          display: "block",
          width: "100%",
          paddingLeft: pad,
          paddingRight: 8,
          backgroundColor: dropTarget ? "var(--mantine-color-blue-1)" : undefined,
          borderRadius: 4,
        }}
        onDragOver={(e) => {
          // Only our own template payload; a file drag belongs to the editor.
          if (!canEdit || !e.dataTransfer.types.includes(TEMPLATE_DRAG_TYPE)) return;
          e.preventDefault();
          e.dataTransfer.dropEffect = "move";
          setDropTarget(true);
        }}
        onDragLeave={() => setDropTarget(false)}
        onDrop={(e) => {
          if (!canEdit) return;
          const templateId = e.dataTransfer.getData(TEMPLATE_DRAG_TYPE);
          setDropTarget(false);
          if (!templateId) return;
          e.preventDefault();
          e.stopPropagation();
          void moveTemplate(templateId, folderId, () => {
            setLocalToken((n) => n + 1);
            onChanged?.();
          });
        }}
      >
        <Group gap={4} py={3} wrap="nowrap">
          {open ? <IconChevronDown size={12} /> : <IconChevronRight size={12} />}
          {open ? (
            <IconFolderOpen size={14} color="var(--mantine-color-blue-6)" />
          ) : (
            <IconFolder size={14} color="var(--mantine-color-blue-6)" />
          )}
          {renaming ? (
            <TextInput
              size="xs"
              value={renameValue}
              autoFocus
              variant="filled"
              style={{ flex: 1 }}
              onClick={(e) => e.stopPropagation()}
              onChange={(e) => setRenameValue(e.currentTarget.value)}
              onBlur={() => setRenaming(false)}
              onKeyDown={(e) => {
                e.stopPropagation();
                if (e.key === "Escape") { setRenameValue(label); setRenaming(false); }
                if (e.key === "Enter") {
                  const next = renameValue.trim();
                  setRenaming(false);
                  if (!next || next === label || !folderId) return;
                  void updateEDMFolder(folderId, { name: next }).then((res) => {
                    if (res.success) {
                      notifications.show({ color: "green", message: "Folder renamed" });
                      onChanged?.();
                    } else {
                      setRenameValue(label);
                      notifications.show({ color: "red", message: res.message || "Rename failed" });
                    }
                  });
                }
              }}
            />
          ) : (
            <Text
              size="xs"
              fw={500}
              truncate
              style={{ flex: 1 }}
              // Double-click to rename: matches how a file manager behaves, and
              // keeps single-click free for expanding the folder.
              onDoubleClick={(e) => {
                if (!canEdit || !folderId) return;
                e.stopPropagation();
                setRenameValue(label);
                setRenaming(true);
              }}
            >
              {label}
            </Text>
          )}
          {folderId && <WorkflowStatusDot status={folderStatuses[folderId]} />}
          {loading && <Loader size={10} />}
        </Group>
      </UnstyledButton>

      {open && data && (
        <Box>
          {data.folders.map((f) => (
            <FolderNode
              key={f.id}
              folderId={f.id}
              label={f.name}
              depth={depth + 1}
              onOpenTemplate={onOpenTemplate}
              onOpenAsset={onOpenAsset}
              activeTemplateId={activeTemplateId}
              refreshToken={refreshToken}
              canEdit={canEdit}
              onChanged={onChanged}
              templateStatuses={templateStatuses}
              folderStatuses={folderStatuses}
            />
          ))}

          {data.templates.map((t) => (
            <UnstyledButton
              key={t.id}
              onClick={() => onOpenTemplate(t)}
              draggable={canEdit}
              onDragStart={(e) => {
                e.dataTransfer.setData(TEMPLATE_DRAG_TYPE, t.id);
                e.dataTransfer.effectAllowed = "move";
              }}
              style={{
                display: "block",
                width: "100%",
                paddingLeft: pad + 16,
                paddingRight: 8,
                backgroundColor:
                  activeTemplateId === t.id ? "var(--mantine-color-blue-0)" : undefined,
              }}
            >
              <Group gap={4} py={3} wrap="nowrap">
                <IconMail size={13} color="var(--mantine-color-grape-6)" />
                <Text size="xs" truncate style={{ flex: 1 }}>{t.name}</Text>
                {/* Unpublished means no active version, so the mail worker has
                    nothing to render and it cannot be sent. */}
                {!t.active_version_id && (
                  <Badge size="xs" color="orange" variant="light" px={4}>draft</Badge>
                )}
                <WorkflowStatusDot status={templateStatuses[t.id]} />
              </Group>
            </UnstyledButton>
          ))}

          {data.assets.map((a) => (
            <UnstyledButton
              key={a.path}
              onClick={() => onOpenAsset(a)}
              style={{ display: "block", width: "100%", paddingLeft: pad + 16, paddingRight: 8 }}
            >
              <Group gap={4} py={3} wrap="nowrap">
                <IconPhoto size={13} color="var(--mantine-color-teal-6)" />
                <Text size="xs" c="dimmed" truncate>
                  {a.path.split("/").pop()}
                </Text>
              </Group>
            </UnstyledButton>
          ))}

          {data.folders.length === 0 &&
            data.templates.length === 0 &&
            data.assets.length === 0 && (
              <Text size="xs" c="dimmed" pl={pad + 16} py={3} fs="italic">
                empty
              </Text>
            )}
        </Box>
      )}
    </Box>
  );
}
