import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useCallback, useMemo, useState, useEffect } from "react";
import { toast } from "sonner";
import { Button } from "../../components/ui/button";
import { Badge } from "../../components/ui/badge";
import { Label } from "../../components/ui/label";
import { Textarea } from "../../components/ui/textarea";
import { Select } from "../../components/ui/select";
import { Plus, Link as LinkIcon, Trash2, X, Loader2, MessageSquare, CheckCircle2, GitBranch, Play, Maximize2, } from "lucide-react";
import { useEditContext } from "../../editor/client/editContext";
import { addComment, applyDecision, updateTask, deleteTask, removeDependency, } from "../services/taskService";
import { CommentsList } from "./CommentsList";
import { TaskCard } from "./TaskCard";
import { CreateTaskDialog } from "./CreateTaskDialog";
import { AddDependencyDialog } from "./AddDependencyDialog";
import { TaskReviewActions } from "./TaskReviewActions";
import { TaskAttachmentsSection } from "./TaskAttachmentsSection";
import { getTaskExecutionDisplay } from "../taskExecutionStatus";
import { getLinkedAgentId } from "../taskAgentLink";
import { getTaskExecutionRecordFromTask } from "../taskExecutionRecords";
import { TaskAssigneePicker } from "./TaskAssigneePicker";
import { stripAgentConfigFromResultData } from "../taskAgentConfig";
import { TaskboardPersistentLogPanel } from "./TaskboardPersistentLogPanel";
const statuses = [
    { value: "Todo", label: "Todo" },
    { value: "Waiting", label: "Waiting" },
    { value: "InProgress", label: "In progress" },
    { value: "Review", label: "Review" },
    { value: "Done", label: "Done" },
];
const priorities = [
    { value: "none", label: "No priority" },
    { value: "Low", label: "Low" },
    { value: "Medium", label: "Medium" },
    { value: "High", label: "High" },
    { value: "Critical", label: "Critical" },
];
const sectionHeadingClass = "text-xs font-bold tracking-wider text-slate-500 uppercase";
const subsectionHeadingClass = "text-xs font-bold tracking-wider text-slate-400 uppercase";
const blockedSubsectionHeadingClass = "text-[11px] font-bold tracking-wider text-slate-400 uppercase";
function RelationshipRow(props) {
    const { entry, compact, canEdit, isRemoving, dependencyTaskIds, onSelectTask, onRemove, } = props;
    const removeButton = canEdit ? (_jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7 shrink-0 text-slate-400 hover:bg-red-50 hover:text-red-600", onClick: (event) => {
            event.stopPropagation();
            void onRemove(entry.dependency);
        }, disabled: isRemoving, title: "Remove relationship", "data-testid": `taskboard-task-detail-remove-dependency-${entry.dependency.dependencyId}`, children: isRemoving ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(Trash2, { className: "h-3.5 w-3.5" })) })) : null;
    if (compact) {
        return (_jsxs("div", { className: "group flex items-center gap-2 rounded-md border border-slate-200 bg-white pr-2 transition-colors hover:border-slate-300 hover:bg-slate-50", children: [_jsxs("button", { type: "button", onClick: () => onSelectTask(entry.task.taskId), className: "flex min-w-0 flex-1 items-center gap-2 px-3 py-2 text-left", children: [_jsx(Badge, { variant: "outline", className: "h-4 border-slate-200 bg-slate-50 px-1 text-[8px] font-bold text-slate-400 group-hover:border-slate-300", children: entry.task.taskKey || entry.task.taskId.slice(0, 4) }), _jsx("span", { className: "truncate text-xs font-medium text-slate-700", children: entry.task.title }), entry.task.status === "Done" && (_jsx(CheckCircle2, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-emerald-600" }))] }), removeButton] }));
    }
    return (_jsxs("div", { className: "relative", children: [_jsx(TaskCard, { task: entry.task, selected: false, onClick: () => onSelectTask(entry.task.taskId), dependencyTaskIds: dependencyTaskIds, showDoneCheckmark: true }), canEdit ? (_jsx("div", { className: "absolute top-2 right-2 z-10", children: removeButton })) : null] }));
}
export function TaskDetailPanel(props) {
    const { project, projects = [], task, allTasks, dependencies, onTaskChanged, onSelectTask, onClose, variant = "panel", agentLaunch, collapsed, onToggleCollapsed, } = props;
    const isCollapsed = collapsed === true;
    const [commentText, setCommentText] = useState("");
    const [commentRefreshKey, setCommentRefreshKey] = useState(0);
    const [isCreateSubtaskOpen, setIsCreateSubtaskOpen] = useState(false);
    const [isAddDependencyOpen, setIsAddDependencyOpen] = useState(false);
    const [removingDependencyId, setRemovingDependencyId] = useState(null);
    const [localDescription, setLocalDescription] = useState(task?.description ?? "");
    const [localResultData, setLocalResultData] = useState(task?.resultData ?? "");
    const [selectedDecisionTemplateIds, setSelectedDecisionTemplateIds] = useState([]);
    const [applyingDecision, setApplyingDecision] = useState(false);
    const editContext = useEditContext();
    const canEdit = project?.permission === "Owner" || project?.permission === "Editor";
    const isPlanTask = useMemo(() => {
        const taskType = task?.taskType;
        if (typeof taskType === "string" && taskType.toLowerCase() === "plan") {
            return true;
        }
        return (task?.title ?? "").trim() === "Project Plan";
    }, [task?.taskType, task?.title]);
    const isDecisionPointTask = useMemo(() => String(task?.taskType ?? "").toLowerCase() === "decisionpoint", [task?.taskType]);
    const decisionPointData = useMemo(() => {
        if (!isDecisionPointTask || !task?.decisionData)
            return null;
        try {
            return JSON.parse(task.decisionData);
        }
        catch {
            return null;
        }
    }, [isDecisionPointTask, task?.decisionData]);
    // Sync local state when the task changes
    useEffect(() => {
        setLocalDescription(task?.description ?? "");
    }, [task?.taskId, task?.description]);
    useEffect(() => {
        setLocalResultData(task?.resultData ?? "");
    }, [task?.taskId, task?.resultData]);
    useEffect(() => {
        setSelectedDecisionTemplateIds(decisionPointData?.selectedTemplateIds?.filter(Boolean) ?? []);
    }, [decisionPointData, task?.taskId]);
    const saveDescription = useCallback(async () => {
        if (!task)
            return;
        const trimmed = localDescription.trim();
        if (trimmed === (task.description ?? "").trim())
            return;
        const result = await updateTask({
            taskId: task.taskId,
            description: trimmed || undefined,
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to update description");
            return;
        }
        await onTaskChanged();
    }, [task, localDescription, onTaskChanged]);
    const saveResultData = useCallback(async () => {
        if (!task)
            return;
        const trimmed = localResultData.trim();
        if (trimmed === (task.resultData ?? "").trim())
            return;
        const result = await updateTask({
            taskId: task.taskId,
            resultData: trimmed || null,
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to update plan");
            return;
        }
        await onTaskChanged();
    }, [task, localResultData, onTaskChanged]);
    const title = useMemo(() => task?.title ?? "Task details", [task?.title]);
    const displayTaskId = useMemo(() => {
        if (!task)
            return null;
        return task.taskKey || task.taskId.slice(0, 8).toUpperCase();
    }, [task]);
    const formatTaskLabel = useCallback((item) => {
        const id = item.taskKey || item.taskId.slice(0, 8).toUpperCase();
        return `${id} - ${item.title}`;
    }, []);
    const getDependencyTaskIds = useCallback((taskId) => {
        const ids = [];
        for (const dep of dependencies) {
            if (dep.taskId !== taskId)
                continue;
            const linked = allTasks.find((t) => t.taskId === dep.dependsOnTaskId);
            const displayId = linked?.taskKey || dep.dependsOnTaskId.slice(0, 8).toUpperCase();
            if (!ids.includes(displayId))
                ids.push(displayId);
        }
        return ids;
    }, [allTasks, dependencies]);
    const compactPanel = variant === "panel";
    const decisionIsResolved = !!decisionPointData?.decidedAt;
    const materializedDecisionTasks = useMemo(() => {
        if (!decisionPointData?.selectedTemplateIds?.length)
            return [];
        const selectedTemplateIds = new Set(decisionPointData.selectedTemplateIds);
        return allTasks.filter((candidate) => candidate.taskId !== task?.taskId &&
            !!candidate.sourceTaskTemplateId &&
            selectedTemplateIds.has(candidate.sourceTaskTemplateId));
    }, [allTasks, decisionPointData?.selectedTemplateIds, task?.taskId]);
    // Calculate related tasks
    const childTasks = useMemo(() => {
        if (!task)
            return [];
        return allTasks.filter((t) => t.parentTaskId === task.taskId);
    }, [task, allTasks]);
    const blockedByTasks = useMemo(() => {
        if (!task)
            return [];
        const blockingDeps = dependencies.filter((d) => d.taskId === task.taskId && d.dependencyType === "BlockedBy");
        return blockingDeps
            .map((dep) => {
            const linkedTask = allTasks.find((t) => t.taskId === dep.dependsOnTaskId);
            return linkedTask ? { dependency: dep, task: linkedTask } : null;
        })
            .filter((entry) => entry !== null);
    }, [task, dependencies, allTasks]);
    const relatedTasks = useMemo(() => {
        if (!task)
            return [];
        const relatedDeps = dependencies.filter((d) => d.taskId === task.taskId && d.dependencyType === "RelatedTo");
        return relatedDeps
            .map((dep) => {
            const linkedTask = allTasks.find((t) => t.taskId === dep.dependsOnTaskId);
            return linkedTask ? { dependency: dep, task: linkedTask } : null;
        })
            .filter((entry) => entry !== null);
    }, [task, dependencies, allTasks]);
    const blockingTasks = useMemo(() => {
        if (!task)
            return [];
        // Tasks that are blocked by this task
        const blockingDeps = dependencies.filter((d) => d.dependsOnTaskId === task.taskId && d.dependencyType === "BlockedBy");
        return blockingDeps
            .map((dep) => {
            const linkedTask = allTasks.find((t) => t.taskId === dep.taskId);
            return linkedTask ? { dependency: dep, task: linkedTask } : null;
        })
            .filter((entry) => entry !== null);
    }, [task, dependencies, allTasks]);
    const blockedByProjects = useMemo(() => {
        if (!task)
            return [];
        const blockedProjectIds = task.executionBlockedByProjectIds || [];
        return blockedProjectIds.map((projectId) => {
            const linkedProject = projects.find((entry) => entry.project.projectId === projectId);
            return {
                projectId,
                title: linkedProject?.project.title || projectId,
            };
        });
    }, [projects, task]);
    const setStatus = async (status) => {
        if (!task)
            return;
        const result = await updateTask({ taskId: task.taskId, status });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to update task");
            return;
        }
        await onTaskChanged();
    };
    const setPriority = async (priority) => {
        if (!task)
            return;
        const nextPriority = priority === "none" ? null : priority;
        const result = await updateTask({
            taskId: task.taskId,
            priority: nextPriority,
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to update task");
            return;
        }
        await onTaskChanged();
    };
    const setAssignee = async (assignee) => {
        if (!task)
            return;
        const nextAssigneeId = assignee?.userName ?? null;
        const currentAssigneeId = task.assigneeType === "user" ? (task.assigneeId ?? null) : null;
        if (nextAssigneeId === currentAssigneeId)
            return;
        const result = await updateTask({
            taskId: task.taskId,
            assigneeType: "user",
            assigneeId: nextAssigneeId ?? "",
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to assign user");
            return;
        }
        if (!assignee) {
            toast.success("Assignee cleared");
        }
        await onTaskChanged();
    };
    const upsertAssignee = async (selection) => {
        if (!task)
            return;
        if (!selection) {
            const clear = await updateTask({
                taskId: task.taskId,
                assigneeType: "user",
                assigneeId: "",
            });
            if (clear.type !== "success") {
                toast.error(clear.summary || "Failed to clear assignee");
                return;
            }
            toast.success("Assignee cleared");
            return;
        }
        if (selection.assigneeType === "user") {
            await setAssignee({
                userName: selection.assigneeId,
                displayName: selection.displayName,
            });
            return;
        }
        const result = await updateTask({
            taskId: task.taskId,
            assigneeType: "Agent",
            assigneeId: selection.assigneeId,
            resultData: stripAgentConfigFromResultData(task.resultData),
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to assign agent profile");
            return;
        }
        await onTaskChanged();
    };
    const toggleDecisionSelection = useCallback((templateId) => {
        if (!templateId)
            return;
        const decisionMode = String(decisionPointData?.decisionMode ?? "").toLowerCase() ===
            "singleselect"
            ? "SingleSelect"
            : "MultiSelect";
        setSelectedDecisionTemplateIds((current) => {
            if (decisionMode === "SingleSelect") {
                return [templateId];
            }
            return current.includes(templateId)
                ? current.filter((id) => id !== templateId)
                : [...current, templateId];
        });
    }, [decisionPointData?.decisionMode]);
    const handleApplyDecision = useCallback(async () => {
        if (!task)
            return;
        if (!selectedDecisionTemplateIds.length) {
            toast.error("Select at least one decision option");
            return;
        }
        setApplyingDecision(true);
        try {
            const result = await applyDecision({
                decisionTaskId: task.taskId,
                selectedTemplateIds: selectedDecisionTemplateIds,
            });
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to apply decision");
                return;
            }
            toast.success("Decision applied");
            await onTaskChanged();
        }
        finally {
            setApplyingDecision(false);
        }
    }, [onTaskChanged, selectedDecisionTemplateIds, task]);
    const submitComment = async () => {
        if (!task)
            return;
        if (!commentText.trim())
            return;
        const result = await addComment({
            taskId: task.taskId,
            text: commentText.trim(),
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to add comment");
            return;
        }
        setCommentText("");
        setCommentRefreshKey((k) => k + 1);
        toast.success("Comment added");
        await onTaskChanged();
    };
    const removeRelationship = useCallback(async (dependency) => {
        setRemovingDependencyId(dependency.dependencyId);
        try {
            const result = await removeDependency({
                dependencyId: dependency.dependencyId,
            });
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to remove relationship");
                return;
            }
            const response = result.data;
            const removedCount = response?.removedCount ?? 1;
            if (removedCount <= 0) {
                toast.error("Relationship not found");
                return;
            }
            toast.success("Relationship removed");
            await onTaskChanged();
        }
        finally {
            setRemovingDependencyId((current) => current === dependency.dependencyId ? null : current);
        }
    }, [onTaskChanged]);
    const parentOptions = useMemo(() => {
        if (!task)
            return [];
        // Get all tasks except the current one
        const otherTasks = allTasks.filter((t) => t.taskId !== task.taskId);
        // Build options from available tasks
        const options = otherTasks.map((t) => ({
            value: t.taskId,
            label: formatTaskLabel(t),
        }));
        // If there's a parent task that's not in the options, add it
        if (task.parentTaskId) {
            const parentExists = options.some((opt) => opt.value === task.parentTaskId);
            if (!parentExists) {
                // Parent task not found in allTasks - add a placeholder
                options.push({
                    value: task.parentTaskId,
                    label: `[Parent: ${task.parentTaskId.substring(0, 8)}...]`,
                });
            }
        }
        return [{ value: "none", label: "None" }, ...options];
    }, [allTasks, formatTaskLabel, task]);
    // Compute the current parent value - ensure it's valid
    const currentParentValue = useMemo(() => {
        if (!task)
            return "none";
        if (!task.parentTaskId)
            return "none";
        // Check if the parent task ID exists in the options
        const exists = parentOptions.some((opt) => opt.value === task.parentTaskId);
        return exists ? task.parentTaskId : "none";
    }, [task, parentOptions]);
    const setParent = async (newParentId) => {
        if (!task)
            return;
        const result = await updateTask({
            taskId: task.taskId,
            parentTaskId: newParentId === "none" ? null : newParentId,
        });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to update parent task");
            return;
        }
        toast.success("Parent task updated");
        await onTaskChanged();
    };
    // Count all descendant tasks (including nested subtasks)
    const descendantCount = useMemo(() => {
        if (!task)
            return 0;
        const countDescendants = (parentId) => {
            const directChildren = allTasks.filter((t) => t.parentTaskId === parentId);
            let count = directChildren.length;
            for (const child of directChildren) {
                count += countDescendants(child.taskId);
            }
            return count;
        };
        return countDescendants(task.taskId);
    }, [task, allTasks]);
    const handleDelete = async () => {
        if (!task || !editContext)
            return;
        let message = `Are you sure you want to delete "${task.title}"?`;
        if (descendantCount > 0) {
            message += `\n\nThis will also delete ${descendantCount} ${descendantCount === 1 ? "subtask" : "subtasks"} (including nested subtasks).`;
        }
        message += "\n\nThis action cannot be undone.";
        editContext.confirm({
            header: "Delete task",
            message,
            acceptLabel: "Delete",
            showCancel: true,
            accept: async () => {
                const result = await deleteTask(task.taskId);
                if (result.type !== "success") {
                    toast.error(result.summary || "Failed to delete task");
                    return;
                }
                toast.success("Task deleted");
                onClose();
                await onTaskChanged();
            },
        });
    };
    const executionDisplay = useMemo(() => {
        if (!task)
            return null;
        return getTaskExecutionDisplay(getTaskExecutionRecordFromTask(task));
    }, [task]);
    return (_jsxs("div", { "data-testid": "taskboard-task-detail-panel", className: `flex h-full flex-col bg-slate-50/50 ${variant === "panel" ? "border-t" : ""}`, children: [_jsx("div", { className: "flex flex-col border-b bg-white p-4 shadow-sm", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [task && (_jsx(Badge, { variant: "outline", className: "h-5 shrink-0 border-slate-200 bg-slate-50 px-1.5 text-[10px] font-bold tracking-tight text-slate-500 uppercase", children: displayTaskId })), _jsx("h2", { className: "truncate text-base leading-none font-bold tracking-tight text-slate-900", "data-testid": "taskboard-task-detail-title", children: title }), isDecisionPointTask && (_jsxs(Badge, { variant: "outline", className: "h-5 shrink-0 border-violet-200 bg-violet-50 px-1.5 text-[10px] font-bold tracking-tight text-violet-700 uppercase", children: [_jsx(GitBranch, { className: "mr-1 h-3 w-3" }), "Decision Point"] }))] }), task ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-1", children: [_jsx(Select, { "data-testid": "taskboard-task-detail-status-select", value: task.status, onValueChange: (v) => setStatus(v), disabled: !canEdit, options: statuses, className: "h-7 w-[130px] text-xs font-medium" }), _jsx(Select, { "data-testid": "taskboard-task-detail-priority-select", value: task.priority ?? "none", onValueChange: (v) => setPriority(v), disabled: !canEdit, options: priorities, className: "h-7 w-[140px] text-xs font-medium" }), !isPlanTask && project && (_jsx(TaskAssigneePicker, { projectId: project.project.projectId, assigneeType: task.assigneeType ?? null, value: task.assigneeId ?? null, displayValue: task.assigneeDisplayName ?? task.assigneeId ?? null, disabled: !canEdit, onChange: upsertAssignee, placeholder: "Assign user or agent", buttonTestId: "taskboard-task-detail-assignee-select" })), agentLaunch && (_jsxs(Button, { variant: "default", size: "sm", onClick: () => void agentLaunch.onClick(), disabled: agentLaunch.disabled, title: agentLaunch.disabled
                                                ? agentLaunch.disabledReason
                                                : undefined, className: "h-7 px-2 text-xs", "data-testid": "taskboard-task-detail-launch-button", children: [_jsx(Play, { className: "mr-1 h-3.5 w-3.5" }), agentLaunch.label] })), executionDisplay && (_jsxs(Badge, { variant: executionDisplay.variant, className: `h-5 gap-1 text-[10px] font-bold tracking-wider uppercase ${executionDisplay.className || ""}`, children: [executionDisplay.showSpinner && (_jsx(Loader2, { className: "h-2.5 w-2.5 animate-spin" })), executionDisplay.label] }))] })) : (_jsx("div", { className: "text-muted-foreground truncate text-sm italic", children: "No task selected" })), task ? (_jsx(TaskReviewActions, { task: task, agentId: getLinkedAgentId(task), canEdit: canEdit, onTaskChanged: onTaskChanged, className: "flex flex-wrap items-center gap-2 pt-2" })) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [task && canEdit && (_jsx(Button, { variant: "ghost", size: "icon", onClick: handleDelete, className: "hover:text-destructive hover:bg-destructive/5 h-8 w-8 text-slate-400", title: "Delete task", "data-testid": "taskboard-task-detail-delete-button", children: _jsx(Trash2, { className: "h-4 w-4" }) })), task && onToggleCollapsed && isCollapsed && (_jsx(Button, { variant: "ghost", size: "icon", onClick: onToggleCollapsed, className: "h-8 w-8 text-slate-400 hover:bg-slate-100 hover:text-slate-600", title: "Show details", "data-testid": "taskboard-task-detail-expand-toggle", children: _jsx(Maximize2, { className: "h-4 w-4" }) })), _jsx(Button, { variant: "ghost", size: "icon", onClick: onClose, className: "h-8 w-8 text-slate-400 hover:bg-slate-100 hover:text-slate-600", title: "Close", "data-testid": "taskboard-task-detail-close-button", children: _jsx(X, { className: "h-4 w-4" }) })] })] }) }), _jsx("div", { className: isCollapsed && task
                    ? "min-h-0 flex-1 overflow-auto bg-slate-50/30 px-4 py-3"
                    : compactPanel
                        ? "min-h-0 flex-1 overflow-auto bg-slate-50/30 p-4"
                        : "min-h-0 flex-1 overflow-auto bg-slate-50/30 p-6", children: !task ? (_jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center text-sm italic", children: "Select a task to view details." })) : isCollapsed ? (_jsxs("div", { className: "flex items-start gap-3", "data-testid": "taskboard-task-detail-collapsed-body", children: [_jsx("div", { className: "min-w-0 flex-1", children: task.description && task.description.trim().length > 0 ? (_jsx("p", { className: "line-clamp-3 text-[13px] leading-relaxed text-slate-700", children: task.description })) : (_jsx("p", { className: "text-[13px] italic text-slate-400", children: "No description" })) }), _jsx("div", { className: "shrink-0", children: _jsx(TaskboardPersistentLogPanel, { scope: "task", projectId: task.projectId, taskId: task.taskId, title: "Execution Log", emptyMessage: "No task-scoped log entries yet.", refreshKey: `${task.taskId}:${task.executionUpdatedAt ?? task.updatedAt ?? ""}:${task.executionState}:${task.status}`, testId: "taskboard-task-detail-log-panel" }) })] })) : (_jsxs("div", { className: compactPanel ? "grid gap-6" : "grid gap-8", children: [_jsxs("div", { className: "grid gap-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx(Label, { className: sectionHeadingClass, children: "Description" }), _jsx(TaskboardPersistentLogPanel, { scope: "task", projectId: task.projectId, taskId: task.taskId, title: "Execution Log", emptyMessage: "No task-scoped log entries yet.", refreshKey: `${task.taskId}:${task.executionUpdatedAt ?? task.updatedAt ?? ""}:${task.executionState}:${task.status}`, testId: "taskboard-task-detail-log-panel" })] }), _jsx(Textarea, { "data-testid": "taskboard-task-detail-description", value: localDescription, onChange: (e) => setLocalDescription(e.target.value), onBlur: () => void saveDescription(), rows: compactPanel ? 2 : 3, placeholder: "Add a description\u2026", disabled: !canEdit, className: "resize-none bg-white text-[13px] leading-relaxed shadow-sm focus-visible:ring-1" })] }), isDecisionPointTask && (_jsxs("div", { className: "grid gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: sectionHeadingClass, children: "Decision" }), _jsx(Badge, { variant: "outline", className: "border-violet-200 bg-violet-50 text-[10px] uppercase text-violet-700", children: String(decisionPointData?.decisionMode ?? "").toLowerCase() ===
                                                "singleselect"
                                                ? "Single Select"
                                                : "Multi Select" })] }), !decisionPointData ? (_jsx("div", { className: "rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800", children: "Decision metadata is missing for this task." })) : decisionIsResolved ? (_jsxs("div", { className: "grid gap-3 rounded-lg border border-violet-100 bg-violet-50/70 p-3", "data-testid": "taskboard-decision-point-panel", children: [_jsx("div", { className: "text-sm font-medium text-violet-900", children: "Decision applied" }), _jsxs("div", { className: "text-xs text-violet-800", children: [decisionPointData.selectedTemplateIds?.length
                                                    ? `Selected ${decisionPointData.selectedTemplateIds.length} option${decisionPointData.selectedTemplateIds.length === 1 ? "" : "s"}`
                                                    : "No options were selected", decisionPointData.decidedBy
                                                    ? ` by ${decisionPointData.decidedBy}`
                                                    : "", decisionPointData.decidedAt
                                                    ? ` at ${new Date(decisionPointData.decidedAt).toLocaleString()}`
                                                    : "", "."] }), materializedDecisionTasks.length > 0 ? (_jsx("div", { className: "grid gap-1.5", children: materializedDecisionTasks.map((materializedTask) => (_jsxs("button", { type: "button", onClick: () => onSelectTask(materializedTask.taskId), className: "flex items-center gap-2 rounded-md border border-violet-200 bg-white px-3 py-2 text-left text-xs text-slate-700 hover:border-violet-300 hover:bg-violet-50", children: [_jsx(Badge, { variant: "outline", className: "h-4 border-slate-200 bg-slate-50 px-1 text-[8px] font-bold text-slate-400", children: materializedTask.taskKey ||
                                                            materializedTask.taskId.slice(0, 4) }), _jsx("span", { className: "truncate font-medium", children: materializedTask.title })] }, materializedTask.taskId))) })) : null] })) : (_jsxs("div", { className: "grid gap-4 rounded-lg border border-violet-100 bg-violet-50/70 p-4", "data-testid": "taskboard-decision-point-panel", children: [_jsx("div", { className: "text-xs leading-relaxed text-violet-900", children: "Choose which direct dependency branches should be materialized into the project." }), task?.assigneeType === "Agent" ? (_jsx("div", { className: "rounded-lg border border-blue-200 bg-blue-50 px-4 py-3 text-xs leading-relaxed text-blue-800", children: "This Decision Point is assigned to an agent profile and can be resolved automatically by the orchestrator." })) : null, _jsx("div", { className: "grid gap-3", children: (decisionPointData.optionRoots ?? []).map((option) => {
                                                const checked = selectedDecisionTemplateIds.includes(option.templateId);
                                                const inputType = String(decisionPointData.decisionMode ?? "").toLowerCase() ===
                                                    "singleselect"
                                                    ? "radio"
                                                    : "checkbox";
                                                return (_jsxs("label", { className: "flex cursor-pointer items-start gap-3 rounded-lg border border-violet-200 bg-white px-4 py-3 text-sm shadow-sm transition-colors hover:border-violet-300", children: [_jsx("input", { type: inputType, name: `decision-point-${task.taskId}`, checked: checked, onChange: () => toggleDecisionSelection(option.templateId), disabled: applyingDecision || !canEdit, className: "mt-0.5 shrink-0", "data-testid": `taskboard-decision-option-${option.templateId}` }), _jsxs("span", { className: "grid min-w-0 gap-1", children: [_jsx("span", { className: "font-medium leading-none text-slate-900", children: option.title || "Untitled option" }), option.description ? (_jsx("span", { className: "text-xs leading-relaxed text-slate-500", children: option.description })) : null] })] }, option.templateId));
                                            }) }), _jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-violet-100 pt-3", children: [_jsxs("div", { className: "text-xs font-medium text-violet-800", children: [selectedDecisionTemplateIds.length, " option", selectedDecisionTemplateIds.length === 1 ? "" : "s", " selected"] }), _jsx(Button, { type: "button", onClick: () => void handleApplyDecision(), disabled: applyingDecision ||
                                                        !canEdit ||
                                                        selectedDecisionTemplateIds.length === 0 ||
                                                        task?.assigneeType === "Agent", "data-testid": "taskboard-apply-decision-button", className: "min-w-40", children: applyingDecision ? "Applying..." : "Apply decision" })] })] }))] })), isPlanTask && (_jsxs("div", { className: "grid gap-2", children: [_jsx(Label, { className: sectionHeadingClass, children: "Plan" }), _jsx(Textarea, { "data-testid": "taskboard-task-detail-plan", value: localResultData, onChange: (e) => setLocalResultData(e.target.value), onBlur: () => void saveResultData(), rows: compactPanel ? 6 : 10, placeholder: "Write the plan\u2026", disabled: !canEdit, className: "min-h-[200px] bg-white font-mono text-[12px] leading-relaxed shadow-sm focus-visible:ring-1" }), _jsxs("div", { className: "rounded border border-blue-100 bg-blue-50/50 px-2 py-1.5 text-[11px] text-slate-500", "data-testid": "taskboard-task-plan-approval-hint", children: [_jsx("span", { className: "font-semibold text-blue-700", children: "Approval:" }), " ", "Move this plan task to", " ", _jsx("span", { className: "font-bold text-blue-800", children: "Done" }), " to approve."] })] })), compactPanel && (_jsxs("div", { className: "grid gap-6 border-t border-slate-200/60 pt-6", children: [_jsxs("div", { className: "grid gap-2", children: [_jsxs(Label, { className: `flex items-center justify-between ${sectionHeadingClass}`, children: ["Subtasks ", childTasks.length > 0 && `(${childTasks.length})`, canEdit && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6 text-slate-400 hover:text-slate-600", onClick: () => setIsCreateSubtaskOpen(true), title: "Add subtask", children: _jsx(Plus, { className: "h-3 w-3" }) }))] }), childTasks.length > 0 ? (_jsx("div", { className: "grid gap-1.5", children: childTasks.map((child) => (_jsxs("button", { type: "button", onClick: () => onSelectTask(child.taskId), className: "group flex items-center gap-2 truncate rounded-md border border-slate-200 bg-white px-3 py-2 text-left text-xs transition-colors hover:border-slate-300 hover:bg-slate-50", children: [_jsx(Badge, { variant: "outline", className: "h-4 border-slate-200 bg-slate-50 px-1 text-[8px] font-bold text-slate-400 group-hover:border-slate-300", children: child.taskKey || child.taskId.slice(0, 4) }), _jsx("span", { className: "truncate font-medium text-slate-700", children: child.title })] }, child.taskId))) })) : (_jsx("div", { className: "text-[11px] text-slate-400 italic", children: "No subtasks." }))] }), _jsxs("div", { className: "grid gap-2", children: [_jsxs(Label, { className: `flex items-center justify-between ${sectionHeadingClass}`, children: ["Dependencies", canEdit && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6 text-slate-400 hover:text-slate-600", onClick: () => setIsAddDependencyOpen(true), title: "Add relationship", children: _jsx(Plus, { className: "h-3 w-3" }) }))] }), blockedByTasks.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: blockedSubsectionHeadingClass, children: "Blocked By" }), _jsx("div", { className: "grid gap-1.5", children: blockedByTasks.map((blocking) => (_jsx(RelationshipRow, { entry: blocking, compact: true, canEdit: canEdit, isRemoving: removingDependencyId ===
                                                            blocking.dependency.dependencyId, dependencyTaskIds: getDependencyTaskIds(blocking.task.taskId), onSelectTask: onSelectTask, onRemove: removeRelationship }, blocking.dependency.dependencyId))) })] })), blockedByProjects.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: blockedSubsectionHeadingClass, children: "Blocked By Project" }), _jsx("div", { className: "grid gap-1.5", children: blockedByProjects.map((blockingProject) => (_jsx("div", { className: "rounded-md border border-slate-200 bg-slate-50 px-3 py-2 text-xs text-slate-700", children: blockingProject.title }, blockingProject.projectId))) })] })), blockingTasks.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: blockedSubsectionHeadingClass, children: "Blocks" }), _jsx("div", { className: "grid gap-1.5", children: blockingTasks.map((blocked) => (_jsx(RelationshipRow, { entry: blocked, compact: true, canEdit: canEdit, isRemoving: removingDependencyId ===
                                                            blocked.dependency.dependencyId, dependencyTaskIds: getDependencyTaskIds(blocked.task.taskId), onSelectTask: onSelectTask, onRemove: removeRelationship }, blocked.dependency.dependencyId))) })] })), relatedTasks.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: subsectionHeadingClass, children: "Related To" }), _jsx("div", { className: "grid gap-1.5", children: relatedTasks.map((related) => (_jsx(RelationshipRow, { entry: related, compact: true, canEdit: canEdit, isRemoving: removingDependencyId ===
                                                            related.dependency.dependencyId, dependencyTaskIds: getDependencyTaskIds(related.task.taskId), onSelectTask: onSelectTask, onRemove: removeRelationship }, related.dependency.dependencyId))) })] })), blockedByTasks.length === 0 &&
                                            blockedByProjects.length === 0 &&
                                            blockingTasks.length === 0 &&
                                            relatedTasks.length === 0 && (_jsx("div", { className: "text-[11px] text-slate-400 italic", children: "No dependencies." }))] })] })), !compactPanel && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-2", children: [_jsx(Label, { className: sectionHeadingClass, children: "Parent Task" }), _jsx(Select, { value: currentParentValue, onValueChange: setParent, disabled: !canEdit, options: parentOptions, className: "bg-white text-[13px] shadow-sm" })] }), _jsxs("div", { className: "grid gap-2 pt-2", children: [_jsxs(Label, { className: `flex items-center justify-between ${sectionHeadingClass}`, children: ["Subtasks ", childTasks.length > 0 && `(${childTasks.length})`, canEdit && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6 text-slate-400 hover:text-slate-600", onClick: () => setIsCreateSubtaskOpen(true), title: "Add subtask", children: _jsx(Plus, { className: "h-3 w-3" }) }))] }), childTasks.length > 0 ? (_jsx("div", { className: "grid gap-2", children: childTasks.map((child) => (_jsx(TaskCard, { task: child, selected: false, onClick: () => onSelectTask(child.taskId), dependencyTaskIds: getDependencyTaskIds(child.taskId) }, child.taskId))) })) : (_jsx("div", { className: "text-[11px] text-slate-400 italic", children: "No subtasks." }))] }), _jsxs("div", { className: "grid gap-4 border-t border-slate-200/60 pt-6", children: [_jsxs(Label, { className: `flex items-center justify-between ${sectionHeadingClass}`, children: ["Relationships", canEdit && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6 text-slate-400 hover:text-slate-600", onClick: () => setIsAddDependencyOpen(true), title: "Add relationship", children: _jsx(LinkIcon, { className: "h-3 w-3" }) }))] }), _jsxs("div", { className: "grid gap-6", children: [blockedByTasks.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: blockedSubsectionHeadingClass, children: "Blocked By" }), _jsx("div", { className: "grid gap-2", children: blockedByTasks.map((blocking) => (_jsx(RelationshipRow, { entry: blocking, compact: false, canEdit: canEdit, isRemoving: removingDependencyId ===
                                                                    blocking.dependency.dependencyId, dependencyTaskIds: getDependencyTaskIds(blocking.task.taskId), onSelectTask: onSelectTask, onRemove: removeRelationship }, blocking.dependency.dependencyId))) })] })), blockedByProjects.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: blockedSubsectionHeadingClass, children: "Blocked By Project" }), _jsx("div", { className: "grid gap-2", children: blockedByProjects.map((blockingProject) => (_jsx("div", { className: "rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-700", children: blockingProject.title }, blockingProject.projectId))) })] })), blockingTasks.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: blockedSubsectionHeadingClass, children: "Blocks" }), _jsx("div", { className: "grid gap-2", children: blockingTasks.map((blocked) => (_jsx(RelationshipRow, { entry: blocked, compact: false, canEdit: canEdit, isRemoving: removingDependencyId ===
                                                                    blocked.dependency.dependencyId, dependencyTaskIds: getDependencyTaskIds(blocked.task.taskId), onSelectTask: onSelectTask, onRemove: removeRelationship }, blocked.dependency.dependencyId))) })] })), relatedTasks.length > 0 && (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: subsectionHeadingClass, children: "Related To" }), _jsx("div", { className: "grid gap-2", children: relatedTasks.map((related) => (_jsx(RelationshipRow, { entry: related, compact: false, canEdit: canEdit, isRemoving: removingDependencyId ===
                                                                    related.dependency.dependencyId, dependencyTaskIds: getDependencyTaskIds(related.task.taskId), onSelectTask: onSelectTask, onRemove: removeRelationship }, related.dependency.dependencyId))) })] })), blockedByTasks.length === 0 &&
                                                    blockedByProjects.length === 0 &&
                                                    blockingTasks.length === 0 &&
                                                    relatedTasks.length === 0 && (_jsx("div", { className: "text-[11px] text-slate-400 italic", children: "No relationships defined." }))] })] })] })), _jsx(TaskAttachmentsSection, { task: task, canEdit: canEdit, onTaskChanged: onTaskChanged }), _jsxs("div", { className: "grid gap-4 border-t border-slate-200/60 pt-6", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-slate-400" }), _jsx("span", { className: sectionHeadingClass, children: "Add Comment" })] }), _jsxs("div", { className: "grid gap-3", children: [_jsx(Textarea, { value: commentText, onChange: (e) => setCommentText(e.target.value), rows: 3, placeholder: "Write a comment\u2026", disabled: !canEdit, className: "resize-none bg-white text-[13px] leading-relaxed shadow-sm transition-all focus-visible:ring-1 focus-visible:ring-slate-300" }), _jsx("div", { className: "flex justify-end", children: _jsx(Button, { size: "sm", onClick: submitComment, disabled: !canEdit || !commentText.trim(), className: "h-8 px-4 text-xs font-semibold", children: "Post comment" }) })] }), _jsx("div", { className: "mt-2", children: _jsx(CommentsList, { taskId: task.taskId, refreshKey: commentRefreshKey, currentUsername: editContext?.user?.name ?? null }) })] })] })) }), task && project && (_jsxs(_Fragment, { children: [_jsx(CreateTaskDialog, { open: isCreateSubtaskOpen, onOpenChange: setIsCreateSubtaskOpen, projectId: project.project.projectId, parentTaskId: task.taskId, availableParentTasks: allTasks, onCreated: onTaskChanged }), _jsx(AddDependencyDialog, { open: isAddDependencyOpen, onOpenChange: setIsAddDependencyOpen, task: task, allTasks: allTasks, onCreated: onTaskChanged })] }))] }));
}
//# sourceMappingURL=TaskDetailPanel.js.map