import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { TaskCard } from "../components/TaskCard";
import { deleteTask, updateTask } from "../services/taskService";
import { toast } from "sonner";
import { useEffect, useMemo, useState } from "react";
import { Circle, PlayCircle, Clock3, Eye, CheckCircle2, LayoutGrid, } from "lucide-react";
import { DeleteIcon } from "../../components/ui/delete-icon";
import { SimpleIconButton } from "../../editor/ui/SimpleIconButton";
import { cn } from "../../lib/utils";
import { useEditContext } from "../../editor/client/editContext";
import { normalizeTaskStatus, getTaskStatusLabel } from "../taskStatus";
import { FilterInput } from "../../components/FilterInput";
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, } from "../../components/ui/context-menu";
import { stripAgentConfigFromResultData } from "../taskAgentConfig";
const columns = [
    {
        status: "Todo",
        title: "Todo",
        icon: Circle,
        color: "text-neutral-grey-50",
    },
    {
        status: "InProgress",
        title: "In progress",
        icon: PlayCircle,
        color: "text-feedback-blue",
    },
    {
        status: "Waiting",
        title: "Waiting",
        icon: Clock3,
        color: "text-feedback-orange",
    },
    { status: "Review", title: "Review", icon: Eye, color: "text-highlight-100" },
    {
        status: "Done",
        title: "Done",
        icon: CheckCircle2,
        color: "text-feedback-green",
    },
];
export function KanbanView(props) {
    const { tasks, dependencies, selectedTaskId, onSelectTask, onTasksChanged, projectId, permission, } = props;
    const editContext = useEditContext();
    const [dragOver, setDragOver] = useState(null);
    const [filter, setFilter] = useState("");
    const [selectedTaskIds, setSelectedTaskIds] = useState(() => selectedTaskId ? new Set([selectedTaskId]) : new Set());
    const [selectionAnchorTaskId, setSelectionAnchorTaskId] = useState(selectedTaskId);
    const canEdit = permission === "Owner" || permission === "Editor";
    const taskById = useMemo(() => {
        const map = new Map();
        for (const t of tasks)
            map.set(t.taskId, t);
        return map;
    }, [tasks]);
    const dependencyTaskIdsByTask = useMemo(() => {
        const map = new Map();
        const toDisplayId = (taskId) => {
            const task = taskById.get(taskId);
            return task?.taskKey || taskId.slice(0, 8).toUpperCase();
        };
        for (const dep of dependencies) {
            const list = map.get(dep.taskId) || [];
            const displayId = toDisplayId(dep.dependsOnTaskId);
            if (!list.includes(displayId))
                list.push(displayId);
            map.set(dep.taskId, list);
        }
        return map;
    }, [dependencies, taskById]);
    const blockedTaskIds = useMemo(() => {
        const blocked = new Set();
        for (const task of tasks) {
            if ((task.executionBlockedByProjectIds?.length ?? 0) > 0) {
                blocked.add(task.taskId);
            }
        }
        for (const dep of dependencies) {
            if (dep.dependencyType !== "BlockedBy")
                continue;
            const blocker = taskById.get(dep.dependsOnTaskId);
            if (!blocker ||
                normalizeTaskStatus(blocker.status, blocker.executionState) !== "Done") {
                blocked.add(dep.taskId);
            }
        }
        return blocked;
    }, [dependencies, taskById]);
    const filteredTasks = useMemo(() => {
        const query = filter.trim().toLowerCase();
        if (!query)
            return tasks;
        return tasks.filter((task) => {
            return (task.title.toLowerCase().includes(query) ||
                (task.description || "").toLowerCase().includes(query) ||
                (task.taskKey || "").toLowerCase().includes(query) ||
                (task.assigneeDisplayName || "").toLowerCase().includes(query) ||
                (task.assigneeId || "").toLowerCase().includes(query));
        });
    }, [filter, tasks]);
    const orderedFilteredTasks = useMemo(() => {
        return [...filteredTasks].sort((a, b) => {
            if (a.sortOrder !== b.sortOrder)
                return a.sortOrder - b.sortOrder;
            return a.createdAt.localeCompare(b.createdAt);
        });
    }, [filteredTasks]);
    const filteredTaskIds = useMemo(() => orderedFilteredTasks.map((task) => task.taskId), [orderedFilteredTasks]);
    useEffect(() => {
        const taskIds = new Set(tasks.map((task) => task.taskId));
        setSelectedTaskIds((previous) => {
            const next = new Set();
            previous.forEach((taskId) => {
                if (taskIds.has(taskId))
                    next.add(taskId);
            });
            if (next.size === 0 && selectedTaskId && taskIds.has(selectedTaskId)) {
                next.add(selectedTaskId);
            }
            return next;
        });
        if (selectionAnchorTaskId && !taskIds.has(selectionAnchorTaskId)) {
            setSelectionAnchorTaskId(selectedTaskId);
        }
    }, [tasks, selectedTaskId, selectionAnchorTaskId]);
    const selectedCount = selectedTaskIds.size;
    const moveTaskIdsToStatus = async (taskIds, status) => {
        const uniqueTaskIds = [...new Set(taskIds)];
        if (uniqueTaskIds.length === 0)
            return;
        const moveCandidates = uniqueTaskIds.filter((taskId) => {
            const task = taskById.get(taskId);
            return task && task.status !== status;
        });
        if (moveCandidates.length === 0)
            return;
        const results = await Promise.all(moveCandidates.map((taskId) => updateTask({ taskId, status })));
        const failed = results.filter((result) => result.type !== "success");
        if (failed.length > 0) {
            toast.error(failed[0]?.summary ||
                `Failed to move ${failed.length === moveCandidates.length ? "tasks" : "some tasks"}`);
            return;
        }
        if (moveCandidates.length > 1) {
            toast.success(`Moved ${moveCandidates.length} tasks to ${getTaskStatusLabel(status)}`);
        }
        await onTasksChanged();
    };
    const handleTaskCardClick = (taskId, event) => {
        const isToggleSelect = event.ctrlKey || event.metaKey;
        const isRangeSelect = event.shiftKey;
        const anchor = selectionAnchorTaskId || selectedTaskId || taskId;
        if (isRangeSelect) {
            const anchorIndex = filteredTaskIds.indexOf(anchor);
            const clickedIndex = filteredTaskIds.indexOf(taskId);
            if (anchorIndex === -1 || clickedIndex === -1) {
                setSelectedTaskIds(new Set([taskId]));
            }
            else {
                const [start, end] = anchorIndex <= clickedIndex
                    ? [anchorIndex, clickedIndex]
                    : [clickedIndex, anchorIndex];
                const rangeSelection = new Set(filteredTaskIds.slice(start, end + 1));
                if (isToggleSelect) {
                    setSelectedTaskIds((previous) => {
                        const next = new Set(previous);
                        rangeSelection.forEach((id) => next.add(id));
                        return next;
                    });
                }
                else {
                    setSelectedTaskIds(rangeSelection);
                }
            }
            onSelectTask(taskId);
            return;
        }
        if (isToggleSelect) {
            setSelectedTaskIds((previous) => {
                const next = new Set(previous);
                if (next.has(taskId) && next.size > 1) {
                    next.delete(taskId);
                    return next;
                }
                next.add(taskId);
                return next;
            });
            setSelectionAnchorTaskId(taskId);
            onSelectTask(taskId);
            return;
        }
        setSelectedTaskIds(new Set([taskId]));
        setSelectionAnchorTaskId(taskId);
        onSelectTask(taskId);
    };
    const handleTaskAssigneeChange = async (task, selection) => {
        const result = await updateTask(selection
            ? {
                taskId: task.taskId,
                assigneeType: selection.assigneeType,
                assigneeId: selection.assigneeId,
                ...(selection.assigneeType === "Agent"
                    ? { resultData: stripAgentConfigFromResultData(task.resultData) }
                    : {}),
            }
            : {
                taskId: task.taskId,
                assigneeType: "user",
                assigneeId: "",
            });
        if (result.type !== "success") {
            toast.error(result.summary ||
                (selection
                    ? "Failed to update assignee"
                    : "Failed to clear assignee"));
            return;
        }
        if (!selection) {
            toast.success("Assignee cleared");
        }
        await onTasksChanged();
    };
    const handleDeleteTask = (task) => {
        const runDelete = async () => {
            const result = await deleteTask(task.taskId);
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to delete task");
                return;
            }
            toast.success("Task deleted");
            await onTasksChanged();
        };
        if (editContext?.confirm) {
            editContext.confirm({
                header: "Delete task",
                message: `Are you sure you want to delete "${task.title}"?\n\nThis action cannot be undone.`,
                acceptLabel: "Delete",
                showCancel: true,
                accept: () => {
                    void runDelete();
                },
            });
            return;
        }
        void runDelete();
    };
    const handleDeleteSelectedTasks = () => {
        const taskIds = [...selectedTaskIds];
        if (taskIds.length === 0)
            return;
        const singleTask = taskIds.length === 1 ? taskById.get(taskIds[0]) : undefined;
        const runDelete = async () => {
            const results = await Promise.all(taskIds.map((taskId) => deleteTask(taskId)));
            const failed = results.filter((result) => result.type !== "success");
            if (failed.length > 0) {
                toast.error(failed[0]?.summary ||
                    `Failed to delete ${failed.length === taskIds.length ? "tasks" : "some tasks"}`);
            }
            else if (taskIds.length === 1) {
                toast.success("Task deleted");
            }
            else {
                toast.success(`Deleted ${taskIds.length} tasks`);
            }
            if (taskIds.length - failed.length > 0) {
                setSelectedTaskIds(new Set());
            }
            await onTasksChanged();
        };
        if (editContext?.confirm) {
            editContext.confirm({
                header: taskIds.length === 1 ? "Delete task" : "Delete tasks",
                message: taskIds.length === 1
                    ? `Are you sure you want to delete "${singleTask?.title || "this task"}"?\n\nThis action cannot be undone.`
                    : `Are you sure you want to delete ${taskIds.length} selected tasks?\n\nThis action cannot be undone.`,
                acceptLabel: "Delete",
                showCancel: true,
                accept: () => {
                    void runDelete();
                },
            });
            return;
        }
        void runDelete();
    };
    const handleTaskContextMenu = (taskId) => {
        if (selectedTaskIds.has(taskId))
            return;
        setSelectedTaskIds(new Set([taskId]));
        setSelectionAnchorTaskId(taskId);
        onSelectTask(taskId);
    };
    return (_jsxs("div", { className: "flex min-h-0 min-w-0 flex-col select-none", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LayoutGrid, { className: "text-neutral-grey-50 h-4 w-4" }), _jsx("h2", { className: "text-base font-semibold tracking-tight", children: "Board" }), _jsx("div", { className: "rounded-badge bg-secondary badge-pad text-2xs text-secondary-foreground font-semibold", children: filteredTasks.length })] }), _jsx("div", { className: "flex items-center gap-2" })] }), _jsx("div", { className: "mb-4", children: _jsx(FilterInput, { value: filter, onChange: setFilter, placeholder: "Search or filter tasks...", className: "w-full sm:w-[320px]" }) }), _jsx("div", { className: "flex max-h-dvh w-full min-w-0 shrink-0 gap-3 overflow-x-auto pb-3", children: columns.map((col) => {
                    const colTasks = orderedFilteredTasks.filter((t) => normalizeTaskStatus(t.status, t.executionState) === col.status);
                    const Icon = col.icon;
                    return (_jsxs("div", { className: cn("bg-neutral-grey-5/50 flex w-68 shrink-0 flex-col rounded-xl border transition-colors", dragOver === col.status
                            ? "bg-primary/5 border-primary/20 ring-primary/20 ring-1"
                            : "border-transparent"), onDragOver: (e) => {
                            e.preventDefault();
                            setDragOver(col.status);
                        }, onDragLeave: () => setDragOver((prev) => (prev === col.status ? null : prev)), onDrop: async (e) => {
                            e.preventDefault();
                            const taskId = e.dataTransfer.getData("text/plain");
                            setDragOver(null);
                            if (!taskId)
                                return;
                            const taskIdsToMove = selectedTaskIds.has(taskId)
                                ? [...selectedTaskIds]
                                : [taskId];
                            await moveTaskIdsToStatus(taskIdsToMove, col.status);
                        }, children: [_jsx("div", { className: "flex items-center justify-between p-2.5 pb-1.5", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { className: cn("h-4 w-4", col.color) }), _jsx("span", { className: "text-neutral-grey-50 text-xs font-semibold tracking-wider", children: getTaskStatusLabel(col.status) }), _jsx("span", { className: "text-neutral-grey-50 ml-1 text-xs font-medium", children: colTasks.length })] }) }), _jsx("div", { className: "scrollbar-thin scrollbar-thumb-neutral-grey-10 flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto p-2", children: colTasks.length === 0 ? (_jsx("div", { className: "border-border-default flex flex-col items-center justify-center rounded-lg border border-dashed bg-white/50 py-6", children: _jsx("div", { className: "text-neutral-grey-50 text-[10px] font-medium tracking-widest", children: "No tasks" }) })) : (colTasks.map((t) => {
                                    const card = (_jsxs("div", { draggable: true, className: "group relative cursor-grab active:cursor-grabbing", onContextMenu: () => handleTaskContextMenu(t.taskId), onDragStart: (e) => {
                                            e.dataTransfer.setData("text/plain", t.taskId);
                                            e.dataTransfer.effectAllowed = "move";
                                            // Create a preview image or style for dragging
                                            if (e.currentTarget instanceof HTMLElement) {
                                                e.currentTarget.style.opacity = "0.5";
                                            }
                                        }, onDragEnd: (e) => {
                                            if (e.currentTarget instanceof HTMLElement) {
                                                e.currentTarget.style.opacity = "1";
                                            }
                                        }, children: [canEdit && (_jsx("span", { className: "absolute -top-2 -right-2 z-10 opacity-0 transition-opacity group-hover:opacity-100", onMouseDown: (e) => {
                                                    e.stopPropagation();
                                                    e.preventDefault();
                                                }, children: _jsx(SimpleIconButton, { icon: _jsx(DeleteIcon, { size: "md" }), label: "Delete task", className: "text-neutral-grey-50 border bg-white shadow-sm", onClick: (e) => {
                                                        e.stopPropagation();
                                                        handleDeleteTask(t);
                                                    } }) })), _jsx(TaskCard, { task: t, selected: selectedTaskIds.has(t.taskId), onClick: (event) => handleTaskCardClick(t.taskId, event), dependencyTaskIds: dependencyTaskIdsByTask.get(t.taskId) || [], isBlocked: blockedTaskIds.has(t.taskId), projectId: projectId, canEditAssignee: canEdit, onAssigneeChange: (selection) => handleTaskAssigneeChange(t, selection) })] }, t.taskId));
                                    if (!canEdit)
                                        return card;
                                    return (_jsxs(ContextMenu, { children: [_jsx(ContextMenuTrigger, { asChild: true, children: card }), _jsx(ContextMenuContent, { className: "w-44", children: _jsxs(ContextMenuItem, { onSelect: handleDeleteSelectedTasks, "data-testid": "taskboard-kanban-context-delete-selected", children: [_jsx(DeleteIcon, { size: "md" }), selectedCount > 1
                                                            ? `Delete selected (${selectedCount})`
                                                            : "Delete task"] }) })] }, `menu-${t.taskId}`));
                                })) })] }, col.status));
                }) })] }));
}
//# sourceMappingURL=KanbanView.js.map