"use client";
import React, { useState, useEffect, useRef, useCallback } from "react";
import { useI18n } from "@/lib/i18n";
import { ContextMenu } from "@/components/ui/ContextMenu";
import { KanbanView } from "./KanbanView";
import { useUserPrefs } from "@/lib/useUserPrefs";
import { getDemoStore, saveDemoStore, MockTask } from "@/lib/mockData";

export interface Tag { id: string; name: string; color: string }

export interface Task {
  id: string;
  listId: string;
  parentId: string | null;
  title: string;
  note: string | null;
  completed: boolean;
  completedAt: string | null;
  dueDate: string | null;
  priority: number;
  sortOrder: number;
  createdAt: string;
  updatedAt: string;
  deletedAt?: string | null;
  isDeleted?: boolean;
  children: Task[];
  tags?: { tag: Tag }[];
}

export interface List { id: string; name: string; color: string; icon: string }
export interface User { id: string; name?: string | null; email?: string | null }

const PRIORITY_COLORS = ["transparent", "var(--priority-low)", "var(--priority-medium)", "var(--priority-high)"];

interface TaskItemProps {
  task: Task;
  depth?: number;
  isSelected: boolean;
  onSelect: (t: Task) => void;
  onToggle: (id: string, completed: boolean) => void;
  onUpdateTitle: (id: string, title: string) => void;
  onAddSubtask: (title: string, parentId: string) => void;
  onContextMenu: (x: number, y: number, task: Task) => void;
  isTrashMode?: boolean;
  onRestore?: (id: string) => void;
  onPermanentDelete?: (id: string) => void;
  onDragTask?: (draggedId: string, targetId: string, position: "before" | "after" | "inside") => void;
}

// Recursive Task Tree Item (Supports 1st, 2nd, 3rd, N-level sub-tasks seamlessly)
function RecursiveTaskItem({
  task,
  depth = 0,
  isSelected,
  onSelect,
  onToggle,
  onUpdateTitle,
  onAddSubtask,
  onContextMenu,
  isTrashMode = false,
  onRestore,
  onPermanentDelete,
  onDragTask,
}: TaskItemProps) {
  const { t, lang } = useI18n();
  const [expanded, setExpanded] = useState(true);
  const [editingTitle, setEditingTitle] = useState(false);
  const [tempTitle, setTempTitle] = useState(task.title);

  const [addingSubtask, setAddingSubtask] = useState(false);
  const [subtaskInput, setSubtaskInput] = useState("");

  // Touch swipe support
  const touchStartX = useRef<number | null>(null);
  const [swipeOffset, setSwipeOffset] = useState(0);

  const editInputRef = useRef<HTMLInputElement>(null);
  const subInputRef = useRef<HTMLInputElement>(null);

  const completedChildren = task.children?.filter((c) => c.completed).length || 0;
  const totalChildren = task.children?.length || 0;

  useEffect(() => {
    setTempTitle(task.title);
  }, [task.title]);

  useEffect(() => {
    if (editingTitle) {
      editInputRef.current?.focus();
      editInputRef.current?.select();
    }
  }, [editingTitle]);

  useEffect(() => {
    if (addingSubtask) {
      subInputRef.current?.focus();
    }
  }, [addingSubtask]);

  // 마감일 상태 반환: label + 색상
  const getDueDateInfo = (d: string | null): { label: string; color: string } | null => {
    if (!d) return null;
    const date = new Date(d);
    const now = new Date();
    const isToday = date.toDateString() === now.toDateString();
    const isTomorrow = date.toDateString() === new Date(now.getTime() + 86400000).toDateString();
    const isPast = date < now && !isToday;
    if (isToday) return { label: t("today"), color: "#EF4444" };
    if (isTomorrow) return { label: t("tomorrow"), color: "#F97316" };
    if (isPast) return { label: date.toLocaleDateString(lang === "ko" ? "ko-KR" : lang === "ja" ? "ja-JP" : "en-US", { month: "short", day: "numeric" }), color: "#DC2626" };
    return { label: date.toLocaleDateString(lang === "ko" ? "ko-KR" : lang === "ja" ? "ja-JP" : "en-US", { month: "short", day: "numeric" }), color: "var(--text-tertiary)" };
  };

  const priorityLabels = [t("priorityNone"), t("priorityLow"), t("priorityMedium"), t("priorityHigh")];

  const handleSaveTitle = () => {
    const trimmed = tempTitle.trim();
    if (trimmed && trimmed !== task.title) {
      onUpdateTitle(task.id, trimmed);
    } else {
      setTempTitle(task.title);
    }
    setEditingTitle(false);
  };

  const handleCreateSubtask = (e: React.FormEvent) => {
    e.preventDefault();
    const trimmed = subtaskInput.trim();
    if (trimmed) {
      onAddSubtask(trimmed, task.id);
      setSubtaskInput("");
      setAddingSubtask(false);
      setExpanded(true);
    }
  };

  // Touch Swipe handlers
  const handleTouchStart = (e: React.TouchEvent) => {
    if (isTrashMode) return;
    touchStartX.current = e.touches[0].clientX;
  };

  const handleTouchMove = (e: React.TouchEvent) => {
    if (touchStartX.current === null) return;
    const deltaX = e.touches[0].clientX - touchStartX.current;
    if (Math.abs(deltaX) < 120) {
      setSwipeOffset(deltaX);
    }
  };

  const handleTouchEnd = () => {
    if (swipeOffset > 70) {
      // Swiped Right -> Toggle Complete
      onToggle(task.id, !task.completed);
    }
    setSwipeOffset(0);
    touchStartX.current = null;
  };

  const [dragOverPos, setDragOverPos] = useState<"top" | "bottom" | "inside" | null>(null);

  return (
    <div style={{ paddingLeft: depth > 0 ? 24 : 0, position: "relative" }}>
      <div
        className={`task-item${task.completed ? " completed" : ""}${isSelected ? " selected" : ""}${dragOverPos ? ` drag-over-${dragOverPos}` : ""}`}
        onClick={() => onSelect(task)}
        tabIndex={0}
        onKeyDown={(e) => {
          if (e.key === "F2" && !isTrashMode) {
            e.preventDefault();
            e.stopPropagation();
            setEditingTitle(true);
          }
        }}
        onTouchStart={handleTouchStart}
        onTouchMove={handleTouchMove}
        onTouchEnd={handleTouchEnd}
        onContextMenu={(e) => {
          e.preventDefault();
          e.stopPropagation();
          onContextMenu(e.clientX, e.clientY, task);
        }}
        onDragOver={(e) => {
          if (isTrashMode) return;
          e.preventDefault();
          e.dataTransfer.dropEffect = "move";
          const rect = e.currentTarget.getBoundingClientRect();
          const relY = e.clientY - rect.top;
          const h = rect.height;
          if (relY < h * 0.25) {
            setDragOverPos("top");
          } else if (relY > h * 0.75) {
            setDragOverPos("bottom");
          } else {
            setDragOverPos("inside");
          }
        }}
        onDragLeave={() => setDragOverPos(null)}
        onDrop={(e) => {
          if (isTrashMode) return;
          e.preventDefault();
          const draggedId = e.dataTransfer.getData("text/plain");
          if (draggedId && draggedId !== task.id && onDragTask) {
            const pos: "before" | "after" | "inside" =
              dragOverPos === "top" ? "before" : dragOverPos === "bottom" ? "after" : "inside";
            onDragTask(draggedId, task.id, pos);
          }
          setDragOverPos(null);
        }}
        id={`task-${task.id}`}
        style={{
          borderLeft: depth > 0 ? "2px solid var(--border)" : "none",
          marginLeft: depth > 0 ? 8 : 0,
          transform: `translateX(${swipeOffset}px)`,
          transition: swipeOffset === 0 ? "transform 0.2s cubic-bezier(0.16, 1, 0.3, 1)" : "none",
          outline: dragOverPos === "inside" ? "2px dashed var(--accent)" : undefined,
          outlineOffset: -2,
          background: dragOverPos === "inside" ? "var(--accent-light, rgba(75, 123, 245, 0.12))" : undefined,
        }}
      >
        {/* Notion-style 6-dot Drag Handle */}
        {!isTrashMode && (
          <div
            className="task-drag-handle"
            draggable="true"
            onDragStart={(e) => {
              e.stopPropagation();
              e.dataTransfer.setData("text/plain", task.id);
              e.dataTransfer.setData("application/task-id", task.id);
              e.dataTransfer.effectAllowed = "move";
            }}
            title="Drag to reorder"
            onClick={(e) => e.stopPropagation()}
          >
            <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
              <circle cx="5" cy="3" r="1.5" />
              <circle cx="11" cy="3" r="1.5" />
              <circle cx="5" cy="8" r="1.5" />
              <circle cx="11" cy="8" r="1.5" />
              <circle cx="5" cy="13" r="1.5" />
              <circle cx="11" cy="13" r="1.5" />
            </svg>
          </div>
        )}

        {/* Toggle Expand Arrow if has children */}
        {totalChildren > 0 ? (
          <button
            type="button"
            className="icon-btn"
            style={{ width: 18, height: 18, flexShrink: 0, padding: 0, opacity: 0.6 }}
            onClick={(e) => {
              e.stopPropagation();
              setExpanded((p) => !p);
            }}
            title="Expand/Collapse"
          >
            <svg
              width="10"
              height="10"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="2.5"
              style={{ transform: expanded ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.15s" }}
            >
              <polyline points="9 18 15 12 9 6" />
            </svg>
          </button>
        ) : depth > 0 ? (
          <span style={{ width: 12, flexShrink: 0 }} />
        ) : null}

        {/* Check button (hidden in trash mode) */}
        {!isTrashMode ? (
          <button
            className={`task-check-btn${task.completed ? " checked" : ""}`}
            onClick={(e) => {
              e.stopPropagation();
              onToggle(task.id, !task.completed);
            }}
            aria-label={task.completed ? "Mark incomplete" : "Mark complete"}
            type="button"
            style={{ width: depth > 0 ? 17 : 19, height: depth > 0 ? 17 : 19, flexShrink: 0 }}
          />
        ) : (
          <span style={{ fontSize: 13, opacity: 0.5, flexShrink: 0 }}>🗑️</span>
        )}

        {/* Title, Meta and Tags */}
        <div className="task-body">
          {editingTitle && !isTrashMode ? (
            <input
              ref={editInputRef}
              className="form-input"
              value={tempTitle}
              onChange={(e) => setTempTitle(e.target.value)}
              onBlur={handleSaveTitle}
              onKeyDown={(e) => {
                if (e.key === "Enter") handleSaveTitle();
                if (e.key === "Escape") {
                  setTempTitle(task.title);
                  setEditingTitle(false);
                }
              }}
              onClick={(e) => e.stopPropagation()}
              style={{ padding: "2px 6px", fontSize: depth > 0 ? 13 : 14, fontWeight: 500, height: 26, width: "100%" }}
            />
          ) : (
            <div
              className="task-title"
              onDoubleClick={(e) => {
                if (isTrashMode) return;
                e.stopPropagation();
                setEditingTitle(true);
              }}
              title="Double click or press F2 to edit"
              style={{ fontSize: depth > 0 ? 13 : 14, fontWeight: depth === 0 ? 600 : 500 }}
            >
              {task.title}
            </div>
          )}

          <div className="task-meta" style={{ flexWrap: "wrap", gap: 6 }}>
            {task.priority > 0 && !isTrashMode && (
              <div
                className="task-priority-dot"
                style={{ background: PRIORITY_COLORS[task.priority] }}
                title={priorityLabels[task.priority]}
              />
            )}
            {task.dueDate && !isTrashMode && (() => {
              const dueDateInfo = getDueDateInfo(task.dueDate);
              if (!dueDateInfo) return null;
              return (
                <span
                  className="task-due"
                  style={{ color: task.completed ? undefined : dueDateInfo.color, fontWeight: (dueDateInfo.color !== "var(--text-tertiary)" && !task.completed) ? 600 : undefined }}
                >
                  <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                    <rect x="3" y="4" width="18" height="18" rx="2" /><line x1="16" y1="2" x2="16" y2="6" /><line x1="8" y1="2" x2="8" y2="6" /><line x1="3" y1="10" x2="21" y2="10" />
                  </svg>
                  {dueDateInfo.label}
                </span>
              );
            })()}
            {totalChildren > 0 && !isTrashMode && (
              <span
                className="task-sub-count"
                onClick={(e) => {
                  e.stopPropagation();
                  setExpanded((p) => !p);
                }}
                style={{ cursor: "pointer" }}
              >
                {completedChildren}/{totalChildren}
              </span>
            )}

            {/* Tags Badges */}
            {task.tags && task.tags.length > 0 && (
              <div style={{ display: "flex", gap: 4 }}>
                {task.tags.map((tg) => (
                  <span
                    key={tg.tag.id}
                    className="badge"
                    style={{
                      background: tg.tag.color + "22",
                      color: tg.tag.color,
                      fontSize: 10,
                      padding: "1px 6px",
                      borderRadius: 4,
                      fontWeight: 600,
                    }}
                  >
                    #{tg.tag.name}
                  </span>
                ))}
              </div>
            )}
          </div>

          {task.note && !task.completed && depth === 0 && (
            <div className="task-note-preview">{task.note.replace(/[#*`]/g, "").slice(0, 80)}</div>
          )}
        </div>

        {/* Right Actions: Subtask Add Button & Trash Mode Controls */}
        {isTrashMode ? (
          <div style={{ display: "flex", gap: 6, marginLeft: "auto" }}>
            <button
              className="btn btn-ghost btn-sm"
              style={{ fontSize: 11, padding: "2px 8px" }}
              onClick={(e) => {
                e.stopPropagation();
                if (onRestore) onRestore(task.id);
              }}
              title="Restore task"
              type="button"
            >
              ↩️ Restore
            </button>
            <button
              className="btn btn-ghost btn-sm"
              style={{ fontSize: 11, padding: "2px 8px", color: "var(--danger)" }}
              onClick={(e) => {
                e.stopPropagation();
                if (onPermanentDelete) onPermanentDelete(task.id);
              }}
              title="Delete permanently"
              type="button"
            >
              ❌
            </button>
          </div>
        ) : (
          <div className="task-actions-right">
            <button
              className="badge badge-neutral"
              style={{
                cursor: "pointer",
                fontSize: 11,
                padding: "2px 8px",
                border: "1px solid var(--border)",
                background: "var(--bg-secondary)",
              }}
              onClick={(e) => {
                e.stopPropagation();
                setAddingSubtask(true);
                setExpanded(true);
              }}
              title="Add subtask"
              type="button"
            >
              + {t("subtasks")}
            </button>
          </div>
        )}
      </div>

      {/* Recursive Children (N-Depth Sub-tasks) */}
      {totalChildren > 0 && expanded && (
        <div className="subtask-recursive-tree">
          {task.children.map((child) => (
            <RecursiveTaskItem
              key={child.id}
              task={child}
              depth={depth + 1}
              isSelected={isSelected}
              onSelect={onSelect}
              onToggle={onToggle}
              onUpdateTitle={onUpdateTitle}
              onAddSubtask={onAddSubtask}
              onContextMenu={onContextMenu}
              isTrashMode={isTrashMode}
              onRestore={onRestore}
              onPermanentDelete={onPermanentDelete}
              onDragTask={onDragTask}
            />
          ))}
        </div>
      )}

      {/* Inline Add Subtask form for this node */}
      {addingSubtask && !isTrashMode && (
        <form
          onSubmit={handleCreateSubtask}
          style={{ display: "flex", gap: 6, padding: "4px 0 4px 32px" }}
          onClick={(e) => e.stopPropagation()}
        >
          <span style={{ color: "var(--accent)", fontSize: 13, lineHeight: "26px" }}>↳</span>
          <input
            ref={subInputRef}
            className="form-input"
            placeholder={t("addSubtaskPlaceholder")}
            value={subtaskInput}
            onChange={(e) => setSubtaskInput(e.target.value)}
            onBlur={() => {
              if (!subtaskInput.trim()) setAddingSubtask(false);
            }}
            onKeyDown={(e) => {
              if (e.key === "Escape") setAddingSubtask(false);
            }}
            style={{ height: 26, fontSize: 12.5, padding: "2px 8px", flex: 1 }}
          />
          <button className="btn btn-primary btn-sm" type="submit" style={{ padding: "2px 8px", fontSize: 11 }}>
            {t("add")}
          </button>
        </form>
      )}
    </div>
  );
}

interface Props {
  user: User;
  listId: string | null;
  lists: List[];
  tasks: Task[];
  setTasks: React.Dispatch<React.SetStateAction<Task[]>>;
  selectedTaskId: string | null;
  onTaskSelect: (t: Task | null) => void;
  showCompleted: boolean;
  onToggleCompleted: () => void;
  onMenuOpen: () => void;
  onRefresh: () => void;
  isDemo?: boolean;
  isTrashActive?: boolean;
  selectedTag?: string | null;
  onEmptyTrash?: () => void;
  onRestoreTask?: (id: string) => void;
  onPermanentDeleteTask?: (id: string) => void;
  onDemoAddTask?: (
    title: string,
    listId: string,
    parentId?: string | null,
    meta?: { dueDate?: string | null; priority?: number; tags?: { tag: Tag }[] }
  ) => void;
  onDemoToggleTask?: (id: string, completed: boolean) => void;
  onUpdateTaskTitle?: (id: string, title: string) => void;
  onUpdateListName?: (id: string, name: string) => void;
  onDeleteTaskWithUndo?: (task: Task) => void;
  onDeleteTask?: (id: string) => void;
}

export function TaskList({
  user: _user,
  listId,
  lists,
  tasks,
  setTasks,
  selectedTaskId,
  onTaskSelect,
  showCompleted,
  onToggleCompleted,
  onMenuOpen,
  onRefresh,
  isDemo = false,
  isTrashActive = false,
  selectedTag = null,
  onEmptyTrash,
  onRestoreTask,
  onPermanentDeleteTask,
  onDemoAddTask,
  onDemoToggleTask,
  onUpdateTaskTitle,
  onUpdateListName,
  onDeleteTaskWithUndo,
  onDeleteTask,
}: Props) {
  const { t } = useI18n();
  const [newTaskTitle, setNewTaskTitle] = useState("");
  const [loading, setLoading] = useState(false);
  const [editingHeader, setEditingHeader] = useState(false);
  const [headerTitle, setHeaderTitle] = useState("");
  const [contextMenu, setContextMenu] = useState<{ x: number; y: number; task: Task } | null>(null);

  const { prefs, updatePrefs } = useUserPrefs();
  // Only show kanban if the Labs flag is explicitly enabled
  const kanbanEnabled = Boolean(prefs.labs?.kanbanBoard);
  const viewMode = kanbanEnabled ? (prefs.viewMode || "list") : "list";

  const handleToggleViewMode = () => {
    const nextMode = viewMode === "kanban" ? "list" : "kanban";
    updatePrefs({ viewMode: nextMode });
  };

  // TickTick-style Quick Add Preset states
  const [quickDueDate, setQuickDueDate] = useState<string | null>(null);
  const [quickPriority, setQuickPriority] = useState<number>(0);
  const [showQuickDue, setShowQuickDue] = useState(false);
  const [showQuickPriority, setShowQuickPriority] = useState(false);

  const priorityLabels = [t("priorityNone"), t("priorityLow"), t("priorityMedium"), t("priorityHigh")];

  const inputRef = useRef<HTMLInputElement>(null);
  const headerInputRef = useRef<HTMLInputElement>(null);
  const currentList = lists.find((l) => l.id === listId);

  useEffect(() => {
    if (currentList) setHeaderTitle(currentList.name);
  }, [currentList]);

  useEffect(() => {
    if (editingHeader) {
      headerInputRef.current?.focus();
      headerInputRef.current?.select();
    }
  }, [editingHeader]);

  const fetchTasks = useCallback(async () => {
    if (!listId || isDemo || isTrashActive || selectedTag) return;
    setLoading(true);
    try {
      const res = await fetch(`/api/tasks?listId=${listId}&showCompleted=${showCompleted}`);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const data = await res.json();
      setTasks(Array.isArray(data) ? data : []);
    } catch (err) {
      console.error("[TaskList] fetchTasks failed", err);
    } finally {
      setLoading(false);
    }
  }, [listId, showCompleted, isDemo, isTrashActive, selectedTag, setTasks]);

  useEffect(() => {
    fetchTasks();
  }, [fetchTasks]);

  useEffect(() => {
    const handler = () => inputRef.current?.focus();
    document.addEventListener("checkflow:addTask", handler);
    return () => document.removeEventListener("checkflow:addTask", handler);
  }, []);

  // Recursive update helper for local tree optimistic state
  const updateTaskCompletedInTree = (tree: Task[], targetId: string, isComp: boolean): Task[] => {
    return tree.map((node) => {
      if (node.id === targetId) {
        return {
          ...node,
          completed: isComp,
          completedAt: isComp ? new Date().toISOString() : null,
          children: node.children ? updateTaskCompletedInTree(node.children, targetId, isComp) : [],
        };
      }
      if (node.children && node.children.length > 0) {
        return {
          ...node,
          children: updateTaskCompletedInTree(node.children, targetId, isComp),
        };
      }
      return node;
    });
  };

  const handleToggle = useCallback(
    async (id: string, completed: boolean) => {
      // 1. Optimistic UI update immediately
      setTasks((prev) => {
        const updated = updateTaskCompletedInTree(prev, id, completed);
        return showCompleted ? updated : updated.filter((t) => t.id !== id || !completed);
      });

      if (isDemo) {
        if (onDemoToggleTask) onDemoToggleTask(id, completed);
        return;
      }

      try {
        const res = await fetch(`/api/tasks/${id}`, {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ completed }),
        });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        onRefresh();
      } catch (err) {
        console.error("[TaskList] handleToggle failed", err);
        // Rollback on failure
        fetchTasks();
      }
    },
    [isDemo, onDemoToggleTask, onRefresh, showCompleted, setTasks, fetchTasks]
  );

  const handleAddTask = async (e: React.FormEvent) => {
    e.preventDefault();
    const title = newTaskTitle.trim();
    if (!title || !listId) return;

    const meta = {
      dueDate: quickDueDate,
      priority: quickPriority,
    };

    if (isDemo) {
      if (onDemoAddTask) onDemoAddTask(title, listId, null, meta);
      setNewTaskTitle("");
      setQuickDueDate(null);
      setQuickPriority(0);
      return;
    }

    try {
      const res = await fetch("/api/tasks", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ title, listId, ...meta }),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const task = await res.json();
      setTasks((prev) => [...prev, task]);
      setNewTaskTitle("");
      setQuickDueDate(null);
      setQuickPriority(0);
      onRefresh();
    } catch (err) {
      console.error("[TaskList] handleAddTask failed", err);
    }
  };

  const insertSubtaskInTree = (tree: Task[], pId: string, subtask: Task): Task[] => {
    return tree.map((node) => {
      if (node.id === pId) {
        const currentChildren = node.children || [];
        return { ...node, children: [...currentChildren, subtask] };
      }
      if (node.children && node.children.length > 0) {
        return { ...node, children: insertSubtaskInTree(node.children, pId, subtask) };
      }
      return node;
    });
  };

  const handleAddSubtaskInline = async (title: string, parentId: string) => {
    if (!listId) return;

    const tempId = "temp-subtask-" + Date.now();
    const tempSubtask: Task = {
      id: tempId,
      listId,
      parentId,
      title: title.trim(),
      note: null,
      completed: false,
      completedAt: null,
      dueDate: null,
      priority: 0,
      sortOrder: 999,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      children: [],
      tags: [],
    };

    // Optimistic insert
    setTasks((prev) => insertSubtaskInTree(prev, parentId, tempSubtask));

    if (isDemo) {
      if (onDemoAddTask) onDemoAddTask(title, listId, parentId);
      return;
    }

    try {
      const res = await fetch("/api/tasks", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ title, listId, parentId }),
      });
      if (res.ok) {
        const createdTask = await res.json();
        // Replace temp subtask with actual created task
        setTasks((prev) => {
          const replaceTemp = (nodes: Task[]): Task[] => {
            return nodes.map((n) => {
              if (n.id === tempId) return createdTask;
              if (n.children && n.children.length > 0) {
                return { ...n, children: replaceTemp(n.children) };
              }
              return n;
            });
          };
          return replaceTemp(prev);
        });
        onRefresh();
      } else {
        fetchTasks();
      }
    } catch (err) {
      console.error("Failed to add subtask inline", err);
      fetchTasks();
    }
  };

  const handleSaveHeaderTitle = () => {
    const trimmed = headerTitle.trim();
    if (trimmed && listId && onUpdateListName && trimmed !== currentList?.name) {
      onUpdateListName(listId, trimmed);
    } else if (currentList) {
      setHeaderTitle(currentList.name);
    }
    setEditingHeader(false);
  };

  // Helper: check if targetId is inside the subtree of ancestorId (prevents circular nesting / node disappearing)
  const isDescendantNode = (nodes: Task[], ancestorId: string, targetId: string): boolean => {
    for (const node of nodes) {
      if (node.id === ancestorId) {
        const checkChildren = (children: Task[]): boolean => {
          for (const c of children) {
            if (c.id === targetId) return true;
            if (c.children && c.children.length > 0 && checkChildren(c.children)) return true;
          }
          return false;
        };
        return checkChildren(node.children || []);
      }
      if (node.children && node.children.length > 0) {
        if (isDescendantNode(node.children, ancestorId, targetId)) return true;
      }
    }
    return false;
  };

  // Robust Tree-aware reordering function (1st, 2nd, 3rd depth task reordering, promoting to top-level, and demoting into subtask)
  const handleReorderTasks = useCallback((draggedId: string, targetId: string, position: "before" | "after" | "inside") => {
    // Prevent dropping onto itself or into its own subtree (which causes loops/disappearing tasks)
    if (draggedId === targetId) return;

    setTasks((prev) => {
      if (isDescendantNode(prev, draggedId, targetId)) {
        return prev;
      }

      // 1. Extract and remove the dragged node from its current position
      let extractedNode: Task | null = null;
      const removeNode = (nodes: Task[]): Task[] => {
        const result: Task[] = [];
        for (const node of nodes) {
          if (node.id === draggedId) {
            extractedNode = { ...node };
          } else {
            const updatedNode = { ...node };
            if (updatedNode.children && updatedNode.children.length > 0) {
              updatedNode.children = removeNode(updatedNode.children);
            }
            result.push(updatedNode);
          }
        }
        return result;
      };

      const treeWithoutDragged = removeNode(prev);
      if (!extractedNode) return prev;
      const safeExtractedNode: Task = extractedNode;

      let determinedParentId: string | null = null;

      // 2. Insert into the target position
      if (position === "inside") {
        determinedParentId = targetId;
        const insertInside = (nodes: Task[]): { list: Task[]; inserted: boolean } => {
          let hasInserted = false;
          const newNodes = nodes.map((node) => {
            if (node.id === targetId) {
              hasInserted = true;
              const nodeWithNewParent: Task = { ...safeExtractedNode, parentId: targetId };
              return {
                ...node,
                children: [...(node.children || []), nodeWithNewParent],
              };
            }
            if (node.children && node.children.length > 0) {
              const res = insertInside(node.children);
              if (res.inserted) {
                hasInserted = true;
                return { ...node, children: res.list };
              }
            }
            return node;
          });
          return { list: newNodes, inserted: hasInserted };
        };

        const result = insertInside(treeWithoutDragged);
        const finalTree = result.inserted ? result.list : [...treeWithoutDragged, { ...safeExtractedNode, parentId: null }];

        if (isDemo && typeof window !== "undefined") {
          const store = getDemoStore();
          saveDemoStore(store.lists, finalTree as unknown as MockTask[]);
        } else {
          fetch(`/api/tasks/${draggedId}`, {
            method: "PATCH",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ parentId: determinedParentId }),
          }).catch((err) => console.error("Failed to update parentId", err));
        }
        return finalTree;
      } else {
        // Drop before/after as sibling (if target is at root level, parentId becomes null -> promoted to 1st level)
        const insertSibling = (nodes: Task[], currentParentId: string | null): { list: Task[]; inserted: boolean } => {
          const idx = nodes.findIndex((n) => n.id === targetId);
          if (idx !== -1) {
            determinedParentId = currentParentId;
            const insertIdx = position === "before" ? idx : idx + 1;
            const nodeWithNewParent: Task = { ...safeExtractedNode, parentId: currentParentId };
            const newNodes = [...nodes];
            newNodes.splice(insertIdx, 0, nodeWithNewParent);
            return { list: newNodes, inserted: true };
          }

          let hasInserted = false;
          const newNodes = nodes.map((node) => {
            if (!hasInserted && node.children && node.children.length > 0) {
              const res = insertSibling(node.children, node.id);
              if (res.inserted) {
                hasInserted = true;
                return { ...node, children: res.list };
              }
            }
            return node;
          });

          return { list: newNodes, inserted: hasInserted };
        };

        const result = insertSibling(treeWithoutDragged, null);
        const finalTree = result.inserted ? result.list : [...treeWithoutDragged, { ...safeExtractedNode, parentId: null }];

        if (isDemo && typeof window !== "undefined") {
          const store = getDemoStore();
          saveDemoStore(store.lists, finalTree as unknown as MockTask[]);
        } else {
          fetch(`/api/tasks/${draggedId}`, {
            method: "PATCH",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ parentId: determinedParentId }),
          }).catch((err) => console.error("Failed to update sibling parentId", err));
        }
        return finalTree;
      }
    });
  }, [isDemo, setTasks]);

  const handleDeleteTask = useCallback((task: Task) => {
    if (onDeleteTaskWithUndo) {
      onDeleteTaskWithUndo(task);
    } else if (onDeleteTask) {
      onDeleteTask(task.id);
    }
  }, [onDeleteTaskWithUndo, onDeleteTask]);

  if (!listId && !isTrashActive && !selectedTag) {
    return (
      <div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%", color: "var(--text-tertiary)" }}>
        <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" style={{ opacity: 0.3, marginBottom: 12 }}>
          <path d="M9 11l3 3L22 4" /><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" />
        </svg>
        <p>{t("selectListToStart")}</p>
      </div>
    );
  }

  // Filter top-level vs completed
  const incompleteTasks = tasks.filter((t) => !t.completed);
  const completedTasks = tasks.filter((t) => t.completed);

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
      {/* Header */}
      <div className="main-header" style={{ justifyContent: "space-between" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, flex: 1, minWidth: 0, marginRight: 12 }}>
          <button className="icon-btn mobile-only" id="menu-btn" onClick={onMenuOpen} aria-label="Menu" type="button">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" />
            </svg>
          </button>

          {/* Header Title / Trash Header / Tag Header */}
          {isTrashActive ? (
            <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
              <span style={{ fontSize: 18, fontWeight: 700, color: "var(--danger)" }}>🗑️ {t("trash") || "Trash"}</span>
              <span style={{ fontSize: 12, color: "var(--text-tertiary)" }}>({tasks.length})</span>
            </div>
          ) : selectedTag ? (
            <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
              <span style={{ fontSize: 18, fontWeight: 700, color: "var(--accent)" }}>🏷️ #{selectedTag}</span>
              <span style={{ fontSize: 12, color: "var(--text-tertiary)" }}>({tasks.length})</span>
            </div>
          ) : editingHeader ? (
            <input
              ref={headerInputRef}
              id="header-rename-input"
              className="form-input"
              value={headerTitle}
              onChange={(e) => setHeaderTitle(e.target.value)}
              onBlur={handleSaveHeaderTitle}
              onKeyDown={(e) => {
                if (e.key === "Enter") handleSaveHeaderTitle();
                if (e.key === "Escape") {
                  if (currentList) setHeaderTitle(currentList.name);
                  setEditingHeader(false);
                }
              }}
              onClick={(e) => e.stopPropagation()}
              autoFocus
              style={{ fontSize: 18, fontWeight: 700, height: 36, padding: "2px 10px", width: "100%", maxWidth: 320 }}
            />
          ) : (
            <div
              className="main-header-title"
              id="main-header-title"
              style={{
                color: currentList?.color,
                cursor: "pointer",
                display: "flex",
                alignItems: "center",
                gap: 8,
                padding: "4px 8px",
                borderRadius: "var(--radius-sm)",
                transition: "background var(--dur-fast)",
                minWidth: 0,
                overflow: "hidden",
                textOverflow: "ellipsis",
                whiteSpace: "nowrap",
              }}
              onClick={(e) => {
                e.stopPropagation();
                setEditingHeader(true);
              }}
              title="Click to rename list"
            >
              <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{currentList?.name || t("tasks")}</span>
              <span style={{ fontSize: 12, color: "var(--text-tertiary)", fontWeight: 400, flexShrink: 0 }}>
                ({incompleteTasks.length})
              </span>
            </div>
          )}
        </div>

        {/* Header Actions */}
        <div className="main-header-actions" style={{ flexShrink: 0, marginLeft: "auto", display: "flex", alignItems: "center", gap: 8 }}>
          {/* View Switcher: Minimal & Matte Single Toggle (Only shown when Kanban is enabled in Labs) */}
          {!isTrashActive && !selectedTag && kanbanEnabled && (
            <button
              type="button"
              className={`view-switcher-toggle-btn${viewMode === "kanban" ? " active" : ""}`}
              onClick={handleToggleViewMode}
              title={viewMode === "kanban" ? `${t("listView")} (Switch to List)` : `${t("kanbanView")} (Switch to Kanban)`}
              style={{
                display: "inline-flex",
                alignItems: "center",
                gap: 5,
                padding: "4px 8px",
                fontSize: 12,
                fontWeight: 600,
                background: viewMode === "kanban" ? "var(--accent-light)" : "var(--bg-secondary)",
                color: viewMode === "kanban" ? "var(--accent)" : "var(--text-secondary)",
                border: "1px solid var(--border)",
                borderRadius: "var(--radius-sm)",
                cursor: "pointer",
                transition: "all var(--dur-fast)",
              }}
            >
              <span>{viewMode === "kanban" ? "📊" : "📋"}</span>
              <span style={{ fontSize: 11.5 }}>
                {viewMode === "kanban" ? t("kanbanView") : t("listView")}
              </span>
            </button>
          )}

          {isTrashActive ? (
            <button
              id="empty-trash-btn"
              className="btn btn-ghost btn-sm"
              style={{ color: "var(--danger)" }}
              onClick={onEmptyTrash}
              type="button"
            >
              🧹 {t("emptyTrash") || "Empty Trash"}
            </button>
          ) : (
            <button
              id="toggle-completed-btn"
              className="btn btn-ghost btn-sm"
              onClick={onToggleCompleted}
              title={showCompleted ? t("hideDone") : t("showDone")}
              type="button"
            >
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <polyline points="20 6 9 17 4 12" />
              </svg>
              <span className="desktop-only">{showCompleted ? t("hideDone") : t("showDone")}</span>
            </button>
          )}
        </div>
      </div>

      {/* Main Task View (List View vs Kanban View) */}
      {viewMode === "kanban" && !isTrashActive && !selectedTag ? (
        <div style={{ flex: 1, minHeight: 0, overflow: "hidden" }}>
          <KanbanView
            tasks={tasks}
            selectedTaskId={selectedTaskId}
            onSelectTask={onTaskSelect}
            onToggleTask={handleToggle}
            onAddTask={(title, priority = 0) => {
              if (!listId) return;
              if (isDemo && onDemoAddTask) {
                onDemoAddTask(title, listId, null, { priority });
              } else if (!isDemo) {
                fetch("/api/tasks", {
                  method: "POST",
                  headers: { "Content-Type": "application/json" },
                  body: JSON.stringify({ title, listId, priority }),
                }).then(() => onRefresh());
              }
            }}
          />
        </div>
      ) : (
        /* Task list container */
        <div
          className="task-list-container"
          onContextMenu={(e) => {
            if (e.target === e.currentTarget) {
              e.preventDefault();
            }
          }}
        >
          {loading && (
            <div style={{ padding: "20px", textAlign: "center", color: "var(--text-tertiary)" }}>{t("loading")}</div>
          )}
          {!loading && tasks.length === 0 && (
            <div className="task-list-empty">
              <svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
                <path d="M9 11l3 3L22 4" /><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" />
              </svg>
              <p>{isTrashActive ? "Trash is empty" : selectedTag ? "No tasks with this tag" : t("noTasksYet")}</p>
            </div>
          )}

        {/* Tasks Tree */}
        {(isTrashActive ? tasks : incompleteTasks).map((task) => (
          <RecursiveTaskItem
            key={task.id}
            task={task}
            depth={0}
            isSelected={selectedTaskId === task.id}
            onSelect={onTaskSelect}
            onToggle={handleToggle}
            onUpdateTitle={(id, title) => onUpdateTaskTitle && onUpdateTaskTitle(id, title)}
            onAddSubtask={handleAddSubtaskInline}
            onContextMenu={(x, y, tItem) => setContextMenu({ x, y, task: tItem })}
            isTrashMode={isTrashActive}
            onRestore={onRestoreTask}
            onPermanentDelete={onPermanentDeleteTask}
            onDragTask={handleReorderTasks}
          />
        ))}

        {/* Completed Tasks */}
        {!isTrashActive && showCompleted && completedTasks.length > 0 && (
          <div>
            <div
              style={{
                padding: "16px 20px 6px",
                fontSize: 11,
                fontWeight: 600,
                color: "var(--text-tertiary)",
                textTransform: "uppercase",
                letterSpacing: "0.5px",
              }}
            >
              {t("completedSection")} ({completedTasks.length})
            </div>
            {completedTasks.map((task) => (
              <RecursiveTaskItem
                key={task.id}
                task={task}
                depth={0}
                isSelected={selectedTaskId === task.id}
                onSelect={onTaskSelect}
                onToggle={handleToggle}
                onUpdateTitle={(id, title) => onUpdateTaskTitle && onUpdateTaskTitle(id, title)}
                onAddSubtask={handleAddSubtaskInline}
                onContextMenu={(x, y, tItem) => setContextMenu({ x, y, task: tItem })}
                isTrashMode={isTrashActive}
                onRestore={onRestoreTask}
                onPermanentDelete={onPermanentDeleteTask}
                onDragTask={handleReorderTasks}
              />
            ))}
          </div>
        )}
      </div>
      )}

      {/* Full-featured Context Menu */}
      {contextMenu && !isTrashActive && (
        <ContextMenu
          x={contextMenu.x}
          y={contextMenu.y}
          items={[
            {
              label: contextMenu.task.completed ? t("showDone") : t("completedSection"),
              icon: contextMenu.task.completed ? "↩️" : "✅",
              onClick: () => handleToggle(contextMenu.task.id, !contextMenu.task.completed),
            },
            {
              label: t("taskTitlePlaceholder"),
              icon: "✏️",
              onClick: () => onTaskSelect(contextMenu.task),
            },
            {
              label: t("subtasks"),
              icon: "↳",
              onClick: () => {
                onTaskSelect(contextMenu.task);
              },
            },
            { divider: true, label: "" },
            {
              label: t("deleteTaskConfirm").split("?")[0],
              icon: "🗑️",
              danger: true,
              onClick: () => handleDeleteTask(contextMenu.task),
            },
          ]}
          onClose={() => setContextMenu(null)}
        />
      )}

      {/* Add task bar with TickTick-style Quick Presets (hidden in trash mode) */}
      {!isTrashActive && !selectedTag && (
        <div className="add-task-bar" style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          <form onSubmit={handleAddTask} style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
            <button className="task-check-btn" style={{ opacity: 0.4, flexShrink: 0 }} aria-hidden="true" type="button" />
            <input
              ref={inputRef}
              id="add-task-input"
              className="add-task-input"
              placeholder={t("addTaskPlaceholder")}
              value={newTaskTitle}
              onChange={(e) => setNewTaskTitle(e.target.value)}
            />
            {newTaskTitle.trim() && (
              <button type="submit" className="btn btn-primary btn-sm" id="add-task-btn">
                {t("add")}
              </button>
            )}
          </form>

          {/* TickTick-style Preset Toolbar (Due Date, Priority) */}
          <div style={{ display: "flex", alignItems: "center", gap: 8, paddingLeft: 28, flexWrap: "wrap" }}>
            {/* Due Date Preset */}
            <div style={{ position: "relative" }}>
              <button
                type="button"
                className={`tick-meta-chip${quickDueDate ? " active" : ""}`}
                onClick={() => setShowQuickDue((p) => !p)}
                style={{
                  fontSize: 11,
                  padding: "2px 8px",
                  borderRadius: "var(--radius-sm)",
                  color: quickDueDate ? "var(--accent)" : "var(--text-tertiary)",
                  borderColor: quickDueDate ? "var(--accent)" : "transparent",
                }}
                title={t("selectDate")}
              >
                📅 {quickDueDate ? new Date(quickDueDate).toLocaleDateString(undefined, { month: "short", day: "numeric" }) : t("selectDate")}
              </button>

              {showQuickDue && (
                <div
                  className="dropdown"
                  style={{ left: 0, bottom: "calc(100% + 6px)", minWidth: 150, padding: 6, zIndex: 120 }}
                  onClick={(e) => e.stopPropagation()}
                >
                  <div
                    className="context-menu-item"
                    style={{ padding: "4px 8px", fontSize: 12, cursor: "pointer" }}
                    onClick={() => {
                      setQuickDueDate(new Date().toISOString().split("T")[0]);
                      setShowQuickDue(false);
                    }}
                  >
                    ⚡ {t("quickToday")}
                  </div>
                  <div
                    className="context-menu-item"
                    style={{ padding: "4px 8px", fontSize: 12, cursor: "pointer" }}
                    onClick={() => {
                      const tm = new Date(Date.now() + 86400000).toISOString().split("T")[0];
                      setQuickDueDate(tm);
                      setShowQuickDue(false);
                    }}
                  >
                    🌅 {t("quickTomorrow")}
                  </div>
                  <div
                    className="context-menu-item"
                    style={{ padding: "4px 8px", fontSize: 12, cursor: "pointer" }}
                    onClick={() => {
                      const nw = new Date(Date.now() + 7 * 86400000).toISOString().split("T")[0];
                      setQuickDueDate(nw);
                      setShowQuickDue(false);
                    }}
                  >
                    🗓️ {t("quickNextWeek")}
                  </div>
                  <div style={{ borderTop: "1px solid var(--border)", margin: "4px 0", paddingTop: 4 }}>
                    <input
                      type="date"
                      className="form-input"
                      style={{ fontSize: 11, padding: "2px 6px", width: "100%" }}
                      value={quickDueDate || ""}
                      onChange={(e) => {
                        setQuickDueDate(e.target.value || null);
                        setShowQuickDue(false);
                      }}
                    />
                  </div>
                  {quickDueDate && (
                    <div
                      className="context-menu-item"
                      style={{ padding: "4px 8px", fontSize: 11, color: "var(--danger)", cursor: "pointer" }}
                      onClick={() => {
                        setQuickDueDate(null);
                        setShowQuickDue(false);
                      }}
                    >
                      ✕ {t("clear")}
                    </div>
                  )}
                </div>
              )}
            </div>

            {/* Priority Preset */}
            <div style={{ position: "relative" }}>
              <button
                type="button"
                className={`tick-meta-chip${quickPriority > 0 ? " active" : ""}`}
                onClick={() => setShowQuickPriority((p) => !p)}
                style={{
                  fontSize: 11,
                  padding: "2px 8px",
                  borderRadius: "var(--radius-sm)",
                  color: quickPriority > 0 ? PRIORITY_COLORS[quickPriority] : "var(--text-tertiary)",
                  borderColor: quickPriority > 0 ? PRIORITY_COLORS[quickPriority] : "transparent",
                }}
                title={t("selectPriority")}
              >
                🚩 {quickPriority > 0 ? priorityLabels[quickPriority] : t("selectPriority")}
              </button>

              {showQuickPriority && (
                <div
                  className="dropdown"
                  style={{ left: 0, bottom: "calc(100% + 6px)", minWidth: 120, padding: 4, zIndex: 120 }}
                  onClick={(e) => e.stopPropagation()}
                >
                  {[0, 1, 2, 3].map((pVal) => (
                    <div
                      key={pVal}
                      className="context-menu-item"
                      style={{
                        padding: "4px 8px",
                        fontSize: 12,
                        cursor: "pointer",
                        color: pVal > 0 ? PRIORITY_COLORS[pVal] : "inherit",
                        fontWeight: quickPriority === pVal ? 700 : 400,
                      }}
                      onClick={() => {
                        setQuickPriority(pVal);
                        setShowQuickPriority(false);
                      }}
                    >
                      {pVal === 0 ? `○ ${t("priorityNone")}` : `● ${priorityLabels[pVal]}`}
                    </div>
                  ))}
                </div>
              )}
            </div>

            {/* Quick Helper Text */}
            {(quickDueDate || quickPriority > 0) && (
              <button
                type="button"
                className="btn btn-ghost btn-sm"
                style={{ fontSize: 10, padding: "1px 6px", opacity: 0.6 }}
                onClick={() => {
                  setQuickDueDate(null);
                  setQuickPriority(0);
                }}
              >
                {t("clear")}
              </button>
            )}
          </div>
        </div>
      )}
    </div>
  );
}