import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { cn } from "../lib/utils";
import { Splitter } from "../editor/ui/Splitter";
import { deleteProject, getExecutionState, getGraphLayout, getProject, getProjects, getTasks, getDependencies, runOrchestrator, triggerPlanning, updateProject, updateTask, } from "./services/taskService";
import { loadAiProfiles } from "../editor/services/aiService";
import { useEditContext } from "../editor/client/editContext";
import { LicenseFeatures, useFeature } from "../licensing";
import { KanbanView } from "./views/KanbanView";
import { ListView } from "./views/ListView";
import { DependencyGraphView } from "./views/DependencyGraphView";
import { WizardView } from "./views/WizardView";
import { SimpleTabs } from "../editor/ui/SimpleTabs";
import { TaskDetailPanel } from "./components/TaskDetailPanel";
import { TaskAgentPanel } from "./components/TaskAgentPanel";
import { ProjectDashboard, } from "./components/ProjectDashboard";
import { CreateTaskDialog } from "./components/CreateTaskDialog";
import { AssignAgentDialog } from "./components/AssignAgentDialog";
import { CreateProjectDialog } from "./components/CreateProjectDialog";
import { ProjectSettingsDialog } from "./components/ProjectSettingsDialog";
import { ProjectOverviewContent } from "./components/ProjectOverviewContent";
import { EditorSlotContextProvider } from "../editor/views/editorSlotContext";
import { SingleEditView } from "../editor/views/SingleEditView";
import { useEditorSlotContext } from "../editor/views/editorSlotContext";
import { Select } from "../components/ui/select";
import { getLinkedAgentId } from "./taskAgentLink";
import { setTaskBoardNavState, resetTaskBoardNavState, subscribeTaskBoardNav, getTaskBoardNavSnapshot, } from "./taskBoardNavStore";
import { useSyncExternalStore } from "react";
import { flattenProjectsHierarchy } from "./utils/projectHierarchy";
import { orderTasksByBlockedDependencies } from "./utils/taskDependencyOrdering";
import { normalizeTaskStatus } from "./taskStatus";
import { getTaskExecutionDisplay, } from "./taskExecutionStatus";
import { indexTaskExecutionRecords, overlayTaskExecutionList, } from "./taskExecutionRecords";
import { WizardCommunicationCenter } from "./components/WizardCommunicationCenter";
import { Button } from "../components/ui/button";
import { Loader2, Plus } from "lucide-react";
import { MainContentTree } from "../editor/sidebar/MainContentTree";
import { useTaskBoardAgentPanelState } from "./useTaskBoardAgentPanelState";
function TaskboardPreviewEditor({ itemDescriptor, }) {
    const slotContext = useEditorSlotContext({
        slotId: "taskboard-preview-slot",
        itemDescriptor,
    });
    if (!slotContext) {
        return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx("div", { className: "text-muted-foreground text-sm font-medium", children: "Editor preview unavailable" }), _jsx("div", { className: "text-muted-foreground text-xs", children: "Open the editor context item to preview and edit it here." })] }));
    }
    return (_jsx(EditorSlotContextProvider, { value: slotContext, children: _jsx(SingleEditView, { compareView: false, name: "taskboard-workspace-preview", view: "primary" }) }));
}
const TASKBOARD_PROJECT_QUERY_KEY = "tbProjectId";
const TASKBOARD_TASK_QUERY_KEY = "tbTaskId";
const TASKBOARD_VIEW_QUERY_KEY = "tbView";
const TASKBOARD_WIZARD_QUERY_KEY = "tbWizard";
const WS_REFRESH_DELAY_MS = 500;
function getInitialQueryValue(queryKey) {
    if (typeof window === "undefined")
        return null;
    const value = new URLSearchParams(window.location.search).get(queryKey);
    return value && value.trim().length > 0 ? value : null;
}
function getInitialViewTabIndex() {
    const view = getInitialQueryValue(TASKBOARD_VIEW_QUERY_KEY)?.toLowerCase();
    if (view === "list")
        return 1;
    if (view === "graph")
        return 2;
    return 0;
}
function getInitialWizardMode() {
    const value = getInitialQueryValue(TASKBOARD_WIZARD_QUERY_KEY)?.toLowerCase();
    return value === "true" || value === "1";
}
function getTaskBoardStateFromUrl() {
    const projectId = getInitialQueryValue(TASKBOARD_PROJECT_QUERY_KEY);
    return {
        projectId,
        taskId: projectId ? getInitialQueryValue(TASKBOARD_TASK_QUERY_KEY) : null,
        activeTab: getInitialViewTabIndex(),
        isWizardMode: getInitialWizardMode(),
    };
}
function getTaskExecutionRecordById(recordsByTaskId, taskId) {
    if (!taskId)
        return undefined;
    return recordsByTaskId[taskId];
}
function addAgentDisplayNames(taskList, agentProfileTitlesById) {
    return taskList.map((task) => {
        if (task.assigneeType !== "Agent" ||
            !task.assigneeId ||
            task.assigneeDisplayName) {
            return task;
        }
        const profileTitle = agentProfileTitlesById[task.assigneeId.toLowerCase()];
        if (!profileTitle)
            return task;
        return {
            ...task,
            assigneeDisplayName: profileTitle,
        };
    });
}
function buildTaskCounts(taskList) {
    const counts = {
        total: taskList.length,
        todo: 0,
        waiting: 0,
        inProgress: 0,
        review: 0,
        done: 0,
    };
    for (const task of taskList) {
        const normalizedStatus = normalizeTaskStatus(task.status, task.executionState);
        if (normalizedStatus === "Todo")
            counts.todo += 1;
        else if (normalizedStatus === "Waiting")
            counts.waiting += 1;
        else if (normalizedStatus === "InProgress")
            counts.inProgress += 1;
        else if (normalizedStatus === "Review")
            counts.review += 1;
        else if (normalizedStatus === "Done")
            counts.done += 1;
    }
    return counts;
}
// ── component ────────────────────────────────────────────────────────
export function TaskBoardWorkspace() {
    const canUseAi = useFeature(LicenseFeatures.AI);
    const editContext = useEditContext();
    const shouldAutoShowMobileEditorRef = useRef(typeof window !== "undefined" &&
        window.matchMedia("(max-width: 767px)").matches);
    const nav = useSyncExternalStore(subscribeTaskBoardNav, getTaskBoardNavSnapshot, getTaskBoardNavSnapshot);
    const isAdministrator = editContext?.user?.isAdministrator === true;
    const isMobile = editContext?.isMobile ?? false;
    const showEditorPanel = editContext?.showAgentsWorkspaceEditor ?? false;
    useEffect(() => {
        if (!editContext?.isMobile)
            return;
        if (!shouldAutoShowMobileEditorRef.current)
            return;
        if (!showEditorPanel) {
            editContext.setShowAgentsWorkspaceEditor(true);
        }
        shouldAutoShowMobileEditorRef.current = false;
    }, [editContext?.isMobile, showEditorPanel, editContext]);
    const currentItemDescriptor = editContext?.currentItemDescriptor;
    const [projects, setProjects] = useState([]);
    const [mobileActiveTab, setMobileActiveTab] = useState(0);
    const [selectedProjectId, setSelectedProjectId] = useState(() => getInitialQueryValue(TASKBOARD_PROJECT_QUERY_KEY));
    const [tasks, setTasks] = useState([]);
    const [isTasksLoading, setIsTasksLoading] = useState(false);
    const [dependencies, setDependencies] = useState([]);
    const [graphLayout, setGraphLayout] = useState(null);
    const [executionRecordsByTaskId, setExecutionRecordsByTaskId] = useState({});
    const [selectedTaskId, setSelectedTaskId] = useState(() => getInitialQueryValue(TASKBOARD_TASK_QUERY_KEY));
    const [selectedTaskSource, setSelectedTaskSource] = useState(() => getInitialQueryValue(TASKBOARD_TASK_QUERY_KEY) ? "system" : null);
    const [activeTab, setActiveTab] = useState(() => getInitialViewTabIndex());
    const [isWizardMode, setIsWizardMode] = useState(() => getInitialWizardMode());
    const [createDialogOpen, setCreateDialogOpen] = useState(false);
    const [createProjectOpen, setCreateProjectOpen] = useState(false);
    const [settingsProjectId, setSettingsProjectId] = useState(null);
    const [savingProjectStatus, setSavingProjectStatus] = useState(false);
    const [assignAgentDialogOpen, setAssignAgentDialogOpen] = useState(false);
    const [runningOrchestrator, setRunningOrchestrator] = useState(false);
    const [showAllProjects, setShowAllProjects] = useState(false);
    const [isProjectsLoading, setIsProjectsLoading] = useState(false);
    const [projectViewLoadingId, setProjectViewLoadingId] = useState(null);
    const [agentProfileTitlesById, setAgentProfileTitlesById] = useState({});
    const [subprojectTaskCounts, setSubprojectTaskCounts] = useState({});
    const [subprojectTasksByProjectId, setSubprojectTasksByProjectId] = useState({});
    const [subprojectExecutionRecordsByProjectId, setSubprojectExecutionRecordsByProjectId,] = useState({});
    const [subprojectCountsLoading, setSubprojectCountsLoading] = useState(false);
    const [wizardPinnedTaskId, setWizardPinnedTaskId] = useState(null);
    const [, setWizardPinnedTaskSource] = useState(null);
    const [wizardForceOverview, setWizardForceOverview] = useState(false);
    const setWizardPinnedTask = useCallback((taskId, source = null) => {
        setWizardPinnedTaskId(taskId);
        setWizardPinnedTaskSource(taskId ? source : null);
    }, []);
    const setTaskSelection = useCallback((taskId, options) => {
        const source = options?.source ?? "system";
        setSelectedTaskId(taskId);
        setSelectedTaskSource(taskId ? source : null);
        if (options?.pinInWizard !== undefined) {
            setWizardPinnedTask(options.pinInWizard ? taskId : null, source);
        }
    }, [setWizardPinnedTask]);
    const wsRefreshTimeoutRef = useRef(null);
    const wsSubprojectRefreshTimeoutRef = useRef(null);
    const wsRefreshQueuedRef = useRef(false);
    const wsRefreshRunningRef = useRef(false);
    const wsRefreshNeedsTasksRef = useRef(false);
    const wsRefreshNeedsExecutionStateRef = useRef(false);
    const wsRefreshNeedsDependenciesRef = useRef(false);
    const wsRefreshNeedsProjectsRef = useRef(false);
    const wsSubprojectRefreshQueuedRef = useRef(false);
    const wsSubprojectRefreshRunningRef = useRef(false);
    const wsSubprojectRefreshNeedsProjectsRef = useRef(false);
    const wizardCloseTransitionTimeoutRef = useRef(null);
    const projectsRequestCountRef = useRef(0);
    const tasksRequestCountRef = useRef(0);
    const latestTasksProjectIdRef = useRef(null);
    const latestDependenciesProjectIdRef = useRef(null);
    const latestGraphLayoutProjectIdRef = useRef(null);
    const latestSubprojectCountsProjectIdRef = useRef(null);
    const refreshProjectsRef = useRef(null);
    const refreshTasksRef = useRef(null);
    const refreshExecutionStateRef = useRef(null);
    const refreshDependenciesRef = useRef(null);
    const refreshGraphLayoutRef = useRef(null);
    const refreshSubprojectTaskCountsRef = useRef(null);
    const projectsRef = useRef([]);
    const selectedProjectIdRef = useRef(null);
    const directSubprojectIdsRef = useRef(new Set());
    const tasksRef = useRef([]);
    const previousTaskStatusesRef = useRef({});
    const previousWizardAttentionSignatureRef = useRef("");
    const autoSelectedProjectIdsRef = useRef(new Set());
    const syncTaskBoardStateFromUrl = useCallback(() => {
        const nextState = getTaskBoardStateFromUrl();
        setSelectedProjectId(nextState.projectId);
        setTaskSelection(nextState.taskId, { source: "system" });
        setActiveTab(nextState.activeTab);
        setIsWizardMode(nextState.isWizardMode);
        setWizardForceOverview(false);
    }, [setTaskSelection]);
    const isProjectWithinSelectedTree = useCallback((projectId, currentProjectId) => {
        if (projectId === currentProjectId)
            return true;
        const parentByProjectId = new Map();
        for (const project of projectsRef.current) {
            parentByProjectId.set(project.project.projectId, project.project.parentProjectId ?? null);
        }
        const visited = new Set();
        let cursor = parentByProjectId.get(projectId) ?? null;
        while (cursor && !visited.has(cursor)) {
            if (cursor === currentProjectId)
                return true;
            visited.add(cursor);
            cursor = parentByProjectId.get(cursor) ?? null;
        }
        return false;
    }, []);
    useEffect(() => {
        if (!canUseAi) {
            setAgentProfileTitlesById({});
            return;
        }
        let cancelled = false;
        loadAiProfiles()
            .then((profiles) => {
            if (cancelled)
                return;
            const byId = {};
            for (const profile of profiles || []) {
                if (!profile?.id)
                    continue;
                byId[profile.id.toLowerCase()] =
                    profile.displayTitle || profile.name || profile.id;
            }
            setAgentProfileTitlesById(byId);
        })
            .catch(() => {
            // best-effort only
        });
        return () => {
            cancelled = true;
        };
    }, [canUseAi]);
    const tasksWithDisplayAssignees = useMemo(() => addAgentDisplayNames(overlayTaskExecutionList(tasks, executionRecordsByTaskId), agentProfileTitlesById), [tasks, executionRecordsByTaskId, agentProfileTitlesById]);
    const selectedProject = useMemo(() => projects.find((p) => p.project.projectId === selectedProjectId) ?? null, [projects, selectedProjectId]);
    const settingsProject = useMemo(() => projects.find((p) => p.project.projectId === settingsProjectId) ?? null, [projects, settingsProjectId]);
    const selectedProjectTaskCounts = useMemo(() => buildTaskCounts(tasksWithDisplayAssignees), [tasksWithDisplayAssignees]);
    const directSubprojects = useMemo(() => selectedProjectId
        ? projects
            .filter((project) => project.project.parentProjectId === selectedProjectId)
            .sort((a, b) => a.project.title.localeCompare(b.project.title))
        : [], [projects, selectedProjectId]);
    const subprojectTasksWithDisplayAssignees = useMemo(() => {
        const nextTasks = {};
        for (const [projectId, taskList] of Object.entries(subprojectTasksByProjectId)) {
            nextTasks[projectId] = addAgentDisplayNames(overlayTaskExecutionList(taskList, subprojectExecutionRecordsByProjectId[projectId] || {}), agentProfileTitlesById);
        }
        return nextTasks;
    }, [
        subprojectTasksByProjectId,
        subprojectExecutionRecordsByProjectId,
        agentProfileTitlesById,
    ]);
    const wizardSubprojectTaskLists = useMemo(() => directSubprojects.map((subproject) => ({
        projectId: subproject.project.projectId,
        title: subproject.project.title,
        tasks: subprojectTasksWithDisplayAssignees[subproject.project.projectId] ||
            [],
    })), [directSubprojects, subprojectTasksWithDisplayAssignees]);
    const wizardTasksWithDisplayAssignees = useMemo(() => [
        ...tasksWithDisplayAssignees,
        ...wizardSubprojectTaskLists.flatMap((subproject) => subproject.tasks),
    ], [tasksWithDisplayAssignees, wizardSubprojectTaskLists]);
    const orderedWizardTasks = useMemo(() => orderTasksByBlockedDependencies(wizardTasksWithDisplayAssignees, dependencies), [wizardTasksWithDisplayAssignees, dependencies]);
    const wizardExecutionRecordsByTaskId = useMemo(() => {
        const merged = {
            ...executionRecordsByTaskId,
        };
        for (const records of Object.values(subprojectExecutionRecordsByProjectId)) {
            Object.assign(merged, records);
        }
        return merged;
    }, [executionRecordsByTaskId, subprojectExecutionRecordsByProjectId]);
    const taskSelectionUniverse = useMemo(() => isWizardMode
        ? wizardTasksWithDisplayAssignees
        : tasksWithDisplayAssignees, [isWizardMode, wizardTasksWithDisplayAssignees, tasksWithDisplayAssignees]);
    const selectedProjectCumulativeCostUsed = useMemo(() => {
        if (!selectedProjectId)
            return 0;
        const childrenByParent = new Map();
        for (const project of projects) {
            const parentId = project.project.parentProjectId;
            if (!parentId)
                continue;
            const children = childrenByParent.get(parentId) || [];
            children.push(project.project.projectId);
            childrenByParent.set(parentId, children);
        }
        const stack = [selectedProjectId];
        const visited = new Set();
        let total = 0;
        while (stack.length > 0) {
            const currentId = stack.pop();
            if (!currentId || visited.has(currentId))
                continue;
            visited.add(currentId);
            const currentProject = projects.find((project) => project.project.projectId === currentId);
            const cost = currentProject?.project.costUsed;
            if (typeof cost === "number" && Number.isFinite(cost)) {
                total += cost;
            }
            const children = childrenByParent.get(currentId) || [];
            for (const childId of children) {
                if (!visited.has(childId))
                    stack.push(childId);
            }
        }
        return total;
    }, [projects, selectedProjectId]);
    const parentProject = useMemo(() => {
        const parentId = selectedProject?.project.parentProjectId;
        if (!parentId)
            return null;
        return (projects.find((project) => project.project.projectId === parentId) ?? null);
    }, [projects, selectedProject]);
    useEffect(() => {
        const childrenByParent = new Map();
        for (const project of projects) {
            const parentId = project.project.parentProjectId;
            if (!parentId)
                continue;
            const children = childrenByParent.get(parentId) || [];
            children.push(project.project.projectId);
            childrenByParent.set(parentId, children);
        }
        const includedProjects = [];
        if (selectedProjectId) {
            const stack = [selectedProjectId];
            const visited = new Set();
            while (stack.length > 0) {
                const currentId = stack.pop();
                if (!currentId || visited.has(currentId))
                    continue;
                visited.add(currentId);
                const currentProject = projects.find((project) => project.project.projectId === currentId);
                includedProjects.push({
                    projectId: currentId,
                    costUsed: typeof currentProject?.project.costUsed === "number"
                        ? currentProject.project.costUsed
                        : null,
                });
                const children = childrenByParent.get(currentId) || [];
                for (const childId of children) {
                    if (!visited.has(childId))
                        stack.push(childId);
                }
            }
        }
    }, [
        selectedProjectCumulativeCostUsed,
        selectedProjectId,
        selectedProject?.project.costUsed,
        projects,
    ]);
    const canCreate = selectedProject?.permission === "Owner" ||
        selectedProject?.permission === "Editor";
    const canEditTasks = canCreate;
    const viewTabs = useMemo(() => [
        { id: "kanban", label: "Kanban", content: null },
        { id: "list", label: "List", content: null },
        { id: "graph", label: "Graph", content: null },
    ], []);
    const viewTabIds = useMemo(() => ["kanban", "list", "graph"], []);
    const isListView = viewTabIds[activeTab] === "list";
    const isGraphView = viewTabIds[activeTab] === "graph";
    const sharedViewSwitcher = useMemo(() => (_jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx(SimpleTabs, { tabs: viewTabs, activeTab: activeTab, setActiveTab: setActiveTab, hideContent: true, className: "rounded-lg border-0 bg-slate-100/50 p-1" }), _jsxs(Button, { size: "sm", onClick: () => setCreateDialogOpen(true), disabled: !canEditTasks, className: "h-8 px-3", "data-testid": "taskboard-create-task-button", children: [_jsx(Plus, { className: "h-4 w-4 sm:mr-1.5" }), _jsx("span", { className: "hidden sm:inline", children: "New Task" })] })] })), [activeTab, canEditTasks, viewTabs]);
    const handleSelectProject = useCallback((projectId) => {
        setSelectedProjectId((previousProjectId) => {
            if (previousProjectId !== projectId) {
                setTaskSelection(null, { pinInWizard: false });
                setWizardForceOverview(false);
            }
            return projectId;
        });
    }, [setTaskSelection]);
    const clearSelectedProjectData = useCallback(() => {
        setTasks([]);
        setDependencies([]);
        setGraphLayout(null);
        setExecutionRecordsByTaskId({});
        setSubprojectTaskCounts({});
        setSubprojectTasksByProjectId({});
        setSubprojectExecutionRecordsByProjectId({});
    }, []);
    const isPlanning = selectedProject?.project.status === "Planning";
    const selectedTask = useMemo(() => taskSelectionUniverse.find((t) => t.taskId === selectedTaskId) ?? null, [taskSelectionUniverse, selectedTaskId]);
    const wizardPinnedTask = useMemo(() => wizardPinnedTaskId
        ? (taskSelectionUniverse.find((task) => task.taskId === wizardPinnedTaskId) ?? null)
        : null, [taskSelectionUniverse, wizardPinnedTaskId]);
    const selectedTaskProject = useMemo(() => {
        if (!selectedTask)
            return selectedProject;
        return (projects.find((project) => project.project.projectId === selectedTask.projectId) ?? selectedProject);
    }, [projects, selectedProject, selectedTask]);
    const { agentPanelMode, canRunAssignedAgent, contextItemOptions, displayAgentId, handleSelectContextItem, hasMultipleContextItems, previewItemName, previewItemPath, previewItemVersion, runAssignedAgentDisabledReason, selectedContextItemValue, selectedTaskHasAssignedAgentProfile, selectedTaskIsBlocked, selectedTaskIsPlan, shouldHideAgentPanelForSelectedTask, } = useTaskBoardAgentPanelState({
        currentItemDescriptor,
        editContext,
        isMobile,
        mobileActiveTab,
        selectedTask,
        selectedTaskId,
        setMobileActiveTab,
        showEditorPanel,
    });
    const wizardAttentionState = useMemo(() => {
        const openTasks = orderedWizardTasks.filter((task) => normalizeTaskStatus(task.status, task.executionState) !== "Done");
        let runningCount = 0;
        let approvalCount = 0;
        let blockedCount = 0;
        let attentionTask = null;
        let attentionAgentId = null;
        let attentionExecutionDisplay = null;
        for (const task of openTasks) {
            const record = getTaskExecutionRecordById(wizardExecutionRecordsByTaskId, task.taskId);
            const executionStateFromBackend = record?.executionState ?? task.executionState;
            const normalizedTaskStatus = normalizeTaskStatus(task.status, executionStateFromBackend);
            const agentId = getLinkedAgentId(task);
            const executionDisplay = getTaskExecutionDisplay(record);
            const isBlocked = executionStateFromBackend === "WaitingForDependency";
            const isRunning = executionStateFromBackend === "Working";
            if (isBlocked) {
                blockedCount += 1;
            }
            if (isRunning) {
                runningCount += 1;
            }
            if (normalizedTaskStatus === "Review") {
                approvalCount += 1;
            }
            const needsAttention = !!executionDisplay?.needsAttention || normalizedTaskStatus === "Review";
            if (!attentionTask && !isBlocked && needsAttention) {
                attentionTask = task;
                attentionAgentId = agentId;
                attentionExecutionDisplay = executionDisplay;
            }
        }
        let summaryState = "idle";
        if (openTasks.length === 0) {
            summaryState = "complete";
        }
        else if (runningCount > 0) {
            summaryState = "working";
        }
        else if (blockedCount === openTasks.length) {
            summaryState = "blocked";
        }
        return {
            task: attentionTask,
            agentId: attentionAgentId,
            executionDisplay: attentionExecutionDisplay,
            summaryState,
            stats: {
                totalCount: orderedWizardTasks.length,
                completedCount: orderedWizardTasks.length - openTasks.length,
                approvalCount,
                blockedCount,
                runningCount,
            },
        };
    }, [orderedWizardTasks, wizardExecutionRecordsByTaskId]);
    const wizardDisplayedTask = wizardForceOverview
        ? null
        : (selectedTask ?? wizardPinnedTask ?? wizardAttentionState.task);
    const wizardDisplayedAgentId = wizardDisplayedTask
        ? getLinkedAgentId(wizardDisplayedTask)
        : null;
    const wizardDisplayedExecutionDisplay = wizardDisplayedTask
        ? getTaskExecutionDisplay(getTaskExecutionRecordById(wizardExecutionRecordsByTaskId, wizardDisplayedTask.taskId))
        : null;
    useEffect(() => {
        const attentionSnapshot = JSON.stringify({
            selectedTaskId,
            selectedTaskSource,
            wizardPinnedTaskId,
            wizardForceOverview,
            attentionTaskId: wizardAttentionState.task?.taskId ?? null,
            attentionAgentId: wizardAttentionState.agentId ?? null,
            summaryState: wizardAttentionState.summaryState,
            totalCount: wizardAttentionState.stats.totalCount,
            completedCount: wizardAttentionState.stats.completedCount,
            approvalCount: wizardAttentionState.stats.approvalCount,
            blockedCount: wizardAttentionState.stats.blockedCount,
            runningCount: wizardAttentionState.stats.runningCount,
            displayedTaskId: wizardDisplayedTask?.taskId ?? null,
            displayedExecutionLabel: wizardDisplayedExecutionDisplay?.label ?? null,
            displayedNeedsAttention: wizardDisplayedExecutionDisplay?.needsAttention ?? null,
        });
        if (previousWizardAttentionSignatureRef.current === attentionSnapshot) {
            return;
        }
        previousWizardAttentionSignatureRef.current = attentionSnapshot;
    }, [
        selectedTaskId,
        selectedTaskSource,
        wizardAttentionState,
        wizardDisplayedExecutionDisplay?.label,
        wizardDisplayedExecutionDisplay?.needsAttention,
        wizardDisplayedTask?.taskId,
        wizardForceOverview,
        wizardPinnedTaskId,
    ]);
    const clearWizardCloseTransitionTimeout = useCallback(() => {
        if (wizardCloseTransitionTimeoutRef.current !== null) {
            window.clearTimeout(wizardCloseTransitionTimeoutRef.current);
            wizardCloseTransitionTimeoutRef.current = null;
        }
    }, []);
    useEffect(() => {
        if (!isWizardMode) {
            clearWizardCloseTransitionTimeout();
        }
    }, [isWizardMode, clearWizardCloseTransitionTimeout]);
    useEffect(() => {
        clearWizardCloseTransitionTimeout();
    }, [selectedProjectId, clearWizardCloseTransitionTimeout]);
    const findNextAttentionTaskId = useCallback((excludedTaskId) => {
        const openTasks = orderedWizardTasks.filter((task) => {
            if (excludedTaskId && task.taskId === excludedTaskId)
                return false;
            return normalizeTaskStatus(task.status, task.executionState) !== "Done";
        });
        for (const task of openTasks) {
            const record = getTaskExecutionRecordById(wizardExecutionRecordsByTaskId, task.taskId);
            const executionStateFromBackend = record?.executionState ?? task.executionState;
            const isBlocked = executionStateFromBackend === "WaitingForDependency";
            const executionDisplay = getTaskExecutionDisplay(record);
            const normalizedTaskStatus = normalizeTaskStatus(task.status, executionStateFromBackend);
            const needsAttention = !!executionDisplay?.needsAttention ||
                normalizedTaskStatus === "Review";
            if (!isBlocked && needsAttention) {
                return task.taskId;
            }
        }
        return null;
    }, [orderedWizardTasks, wizardExecutionRecordsByTaskId]);
    // ── data fetching ──
    const refreshProjects = useCallback(async (options) => {
        projectsRequestCountRef.current += 1;
        setIsProjectsLoading(true);
        const includeAll = options?.includeAll ?? (isAdministrator && showAllProjects);
        try {
            const result = await getProjects({
                includeAll,
            });
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to load projects");
                return;
            }
            let data = result.data || [];
            const requestedProjectId = selectedProjectIdRef.current ??
                getInitialQueryValue(TASKBOARD_PROJECT_QUERY_KEY);
            if (requestedProjectId &&
                !data.some((project) => project.project.projectId === requestedProjectId)) {
                // Deep-linked reloads can briefly race the projects list; hydrate the
                // selected project directly so the workspace restores once the record exists.
                const selectedProjectResult = await getProject(requestedProjectId);
                if (selectedProjectResult.type === "success" &&
                    selectedProjectResult.data &&
                    !data.some((project) => project.project.projectId ===
                        selectedProjectResult.data?.project.projectId)) {
                    data = [...data, selectedProjectResult.data];
                }
            }
            setProjects(data);
            setSelectedProjectId((prev) => {
                if (!prev)
                    return null;
                const stillExists = data.some((p) => p.project.projectId === prev);
                return stillExists ? prev : null;
            });
        }
        finally {
            projectsRequestCountRef.current = Math.max(0, projectsRequestCountRef.current - 1);
            if (projectsRequestCountRef.current === 0) {
                setIsProjectsLoading(false);
            }
        }
    }, [isAdministrator, showAllProjects]);
    useEffect(() => {
        if (!isAdministrator && showAllProjects) {
            setShowAllProjects(false);
        }
    }, [isAdministrator, showAllProjects]);
    useEffect(() => {
        if (typeof window === "undefined")
            return;
        const current = new URLSearchParams(window.location.search);
        const view = viewTabIds[activeTab] ?? "kanban";
        if (selectedProjectId) {
            current.set(TASKBOARD_PROJECT_QUERY_KEY, selectedProjectId);
        }
        else {
            current.delete(TASKBOARD_PROJECT_QUERY_KEY);
        }
        if (selectedProjectId && selectedTaskId) {
            current.set(TASKBOARD_TASK_QUERY_KEY, selectedTaskId);
        }
        else {
            current.delete(TASKBOARD_TASK_QUERY_KEY);
        }
        current.set(TASKBOARD_VIEW_QUERY_KEY, view);
        if (isWizardMode) {
            current.set(TASKBOARD_WIZARD_QUERY_KEY, "true");
        }
        else {
            current.delete(TASKBOARD_WIZARD_QUERY_KEY);
        }
        const browserPathname = window.location.pathname;
        const queryString = current.toString();
        const newUrl = queryString
            ? `${browserPathname}?${queryString}`
            : browserPathname;
        const oldUrl = `${browserPathname}${window.location.search}`;
        if (newUrl !== oldUrl) {
            window.history.replaceState(null, "", newUrl);
        }
    }, [selectedProjectId, selectedTaskId, activeTab, isWizardMode, viewTabIds]);
    useEffect(() => {
        const handlePopState = () => {
            syncTaskBoardStateFromUrl();
        };
        window.addEventListener("popstate", handlePopState);
        return () => window.removeEventListener("popstate", handlePopState);
    }, [syncTaskBoardStateFromUrl]);
    const refreshTasks = useCallback(async (projectId) => {
        tasksRequestCountRef.current += 1;
        latestTasksProjectIdRef.current = projectId;
        const requestProjectId = projectId;
        setIsTasksLoading(true);
        try {
            const result = await getTasks(projectId);
            if (latestTasksProjectIdRef.current !== requestProjectId) {
                return;
            }
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to load tasks");
                return;
            }
            const nextTasks = result.data || [];
            setTasks(nextTasks);
        }
        finally {
            tasksRequestCountRef.current = Math.max(0, tasksRequestCountRef.current - 1);
            if (tasksRequestCountRef.current === 0) {
                setIsTasksLoading(false);
            }
        }
    }, []);
    const refreshExecutionState = useCallback(async (projectId) => {
        const result = await getExecutionState({ projectId });
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to load execution state");
            return;
        }
        const records = result.data?.records ?? [];
        const indexed = indexTaskExecutionRecords(records);
        setExecutionRecordsByTaskId(indexed);
    }, []);
    const refreshGraphLayout = useCallback(async (projectId) => {
        latestGraphLayoutProjectIdRef.current = projectId;
        const requestProjectId = projectId;
        const result = await getGraphLayout(projectId);
        if (latestGraphLayoutProjectIdRef.current !== requestProjectId) {
            return;
        }
        if (result.type !== "success") {
            toast.error(result.summary || "Failed to load graph layout");
            return;
        }
        setGraphLayout(result.data ?? null);
    }, []);
    const refreshSubprojectTaskCounts = useCallback(async () => {
        const requestProjectId = selectedProjectId;
        latestSubprojectCountsProjectIdRef.current = requestProjectId;
        if (directSubprojects.length === 0) {
            if (latestSubprojectCountsProjectIdRef.current === requestProjectId) {
                setSubprojectTaskCounts({});
                setSubprojectTasksByProjectId({});
                setSubprojectExecutionRecordsByProjectId({});
            }
            return;
        }
        setSubprojectCountsLoading(true);
        try {
            const results = await Promise.all(directSubprojects.map(async (subproject) => {
                const projectId = subproject.project.projectId;
                const [tasksResponse, executionResponse] = await Promise.all([
                    getTasks(projectId),
                    getExecutionState({ projectId }),
                ]);
                if (tasksResponse.type !== "success") {
                    return [projectId, null, null, null];
                }
                const tasksForProject = tasksResponse.data || [];
                const recordsByTaskId = executionResponse.type === "success"
                    ? indexTaskExecutionRecords(executionResponse.data?.records)
                    : {};
                const tasksWithExecution = overlayTaskExecutionList(tasksForProject, recordsByTaskId);
                return [
                    projectId,
                    buildTaskCounts(tasksWithExecution),
                    tasksForProject,
                    recordsByTaskId,
                ];
            }));
            if (latestSubprojectCountsProjectIdRef.current !== requestProjectId) {
                return;
            }
            const nextCounts = {};
            const nextTasksByProjectId = {};
            const nextExecutionByProjectId = {};
            for (const [projectId, counts, taskList, executionByTaskId] of results) {
                if (counts)
                    nextCounts[projectId] = counts;
                if (taskList)
                    nextTasksByProjectId[projectId] = taskList;
                if (executionByTaskId)
                    nextExecutionByProjectId[projectId] = executionByTaskId;
            }
            setSubprojectTaskCounts(nextCounts);
            setSubprojectTasksByProjectId(isWizardMode ? nextTasksByProjectId : {});
            setSubprojectExecutionRecordsByProjectId(isWizardMode ? nextExecutionByProjectId : {});
        }
        finally {
            setSubprojectCountsLoading(false);
        }
    }, [directSubprojects, isWizardMode, selectedProjectId]);
    // If a project only has a single task, auto-select it once when loading.
    // Do not auto-reselect after the user explicitly closes task details.
    useEffect(() => {
        if (!selectedProjectId)
            return;
        if (selectedTaskId)
            return;
        if (tasks.length !== 1)
            return;
        if (autoSelectedProjectIdsRef.current.has(selectedProjectId))
            return;
        const firstTask = tasks[0];
        if (!firstTask)
            return;
        autoSelectedProjectIdsRef.current.add(selectedProjectId);
        setTaskSelection(firstTask.taskId, { source: "system" });
    }, [selectedProjectId, selectedTaskId, setTaskSelection, tasks]);
    useEffect(() => {
        if (!wizardPinnedTaskId)
            return;
        if (taskSelectionUniverse.some((task) => task.taskId === wizardPinnedTaskId)) {
            return;
        }
        setWizardPinnedTask(null);
    }, [setWizardPinnedTask, taskSelectionUniverse, wizardPinnedTaskId]);
    // Pin to a task as soon as it shows Questions/WaitingForInput/WaitingForUser, so we don't
    // switch away when another subproject also gets Questions (wizardAttentionState
    // would pick a different task and we'd lose the questionnaire to agent mismatch).
    useEffect(() => {
        if (!isWizardMode)
            return;
        if (wizardForceOverview)
            return;
        if (selectedTaskId)
            return;
        if (wizardPinnedTaskId)
            return;
        if (!wizardDisplayedTask?.taskId)
            return;
        const needsInput = wizardDisplayedExecutionDisplay?.label === "Questions" ||
            wizardDisplayedExecutionDisplay?.label === "Waiting for input" ||
            wizardDisplayedExecutionDisplay?.label === "Waiting for user";
        if (!needsInput)
            return;
        setWizardPinnedTask(wizardDisplayedTask.taskId, "system");
    }, [
        isWizardMode,
        wizardForceOverview,
        selectedTaskId,
        wizardPinnedTaskId,
        wizardDisplayedTask?.taskId,
        wizardDisplayedExecutionDisplay?.label,
        setWizardPinnedTask,
    ]);
    useEffect(() => {
        if (!isWizardMode)
            return;
        if (selectedTaskId)
            return;
        const attentionTaskId = wizardAttentionState.task?.taskId;
        if (!attentionTaskId) {
            return;
        }
        if (wizardForceOverview) {
            setWizardForceOverview(false);
        }
        if (wizardPinnedTaskId === attentionTaskId)
            return;
        const displayedNeedsInput = wizardDisplayedExecutionDisplay?.label === "Questions" ||
            wizardDisplayedExecutionDisplay?.label === "Waiting for input" ||
            wizardDisplayedExecutionDisplay?.label === "Waiting for user";
        if (displayedNeedsInput && wizardDisplayedTask?.taskId) {
            return;
        }
        setWizardPinnedTaskId(attentionTaskId);
    }, [
        isWizardMode,
        selectedTaskId,
        selectedTaskSource,
        wizardDisplayedExecutionDisplay?.label,
        wizardDisplayedTask?.taskId,
        wizardPinnedTaskId,
        wizardForceOverview,
        wizardAttentionState.summaryState,
        wizardAttentionState.task?.taskId,
    ]);
    useEffect(() => {
        if (!isWizardMode)
            return;
        if (selectedTaskSource === "user")
            return;
        if (!selectedTask)
            return;
        if (normalizeTaskStatus(selectedTask.status, selectedTask.executionState) !==
            "Done") {
            return;
        }
        const nextAttentionTaskId = findNextAttentionTaskId(selectedTask.taskId);
        if (nextAttentionTaskId) {
            setWizardForceOverview(false);
            setTaskSelection(nextAttentionTaskId, {
                source: "system",
                pinInWizard: true,
            });
            return;
        }
        setTaskSelection(null, { pinInWizard: false });
    }, [
        findNextAttentionTaskId,
        isWizardMode,
        selectedTask,
        selectedTaskSource,
        setTaskSelection,
    ]);
    useEffect(() => {
        if (isWizardMode)
            return;
        if (!wizardPinnedTaskId)
            return;
        setWizardPinnedTask(null);
    }, [isWizardMode, setWizardPinnedTask, wizardPinnedTaskId]);
    useEffect(() => {
        if (!isWizardMode && wizardForceOverview) {
            setWizardForceOverview(false);
        }
    }, [isWizardMode, wizardForceOverview]);
    useEffect(() => {
        setWizardPinnedTask(null);
        setWizardForceOverview(false);
    }, [selectedProjectId, setWizardPinnedTask]);
    const refreshDependencies = useCallback(async (projectId) => {
        latestDependenciesProjectIdRef.current = projectId;
        const requestProjectId = projectId;
        const visibleProjectIds = Array.from(new Set([
            projectId,
            ...directSubprojects.map((subproject) => subproject.project.projectId),
        ]));
        const results = await Promise.all(visibleProjectIds.map(async (visibleProjectId) => {
            const result = await getDependencies(visibleProjectId);
            return [visibleProjectId, result];
        }));
        const primaryResult = results.find(([visibleProjectId]) => visibleProjectId === projectId)?.[1] ?? null;
        if (latestDependenciesProjectIdRef.current !== requestProjectId) {
            return;
        }
        if (!primaryResult || primaryResult.type !== "success") {
            toast.error(primaryResult?.summary || "Failed to load dependencies");
            return;
        }
        const mergedDependencies = new Map();
        for (const [, result] of results) {
            if (result.type !== "success")
                continue;
            for (const dependency of result.data || []) {
                mergedDependencies.set(dependency.dependencyId, dependency);
            }
        }
        setDependencies(Array.from(mergedDependencies.values()));
    }, [directSubprojects]);
    const refreshVisibleTaskData = useCallback(async () => {
        if (!selectedProjectId)
            return;
        await refreshTasks(selectedProjectId);
        await refreshExecutionState(selectedProjectId);
        await refreshDependencies(selectedProjectId);
        await refreshSubprojectTaskCounts();
    }, [
        selectedProjectId,
        refreshTasks,
        refreshExecutionState,
        refreshDependencies,
        refreshSubprojectTaskCounts,
    ]);
    // Sync refs with latest function/state values for use in WebSocket timeout callback
    useEffect(() => {
        refreshProjectsRef.current = refreshProjects;
        refreshTasksRef.current = refreshTasks;
        refreshExecutionStateRef.current = refreshExecutionState;
        refreshDependenciesRef.current = refreshDependencies;
        refreshGraphLayoutRef.current = refreshGraphLayout;
        refreshSubprojectTaskCountsRef.current = refreshSubprojectTaskCounts;
        projectsRef.current = projects;
        selectedProjectIdRef.current = selectedProjectId;
        directSubprojectIdsRef.current = new Set(directSubprojects.map((subproject) => subproject.project.projectId));
        tasksRef.current = taskSelectionUniverse;
    }, [
        refreshProjects,
        refreshTasks,
        refreshExecutionState,
        refreshDependencies,
        refreshGraphLayout,
        refreshSubprojectTaskCounts,
        projects,
        selectedProjectId,
        directSubprojects,
        taskSelectionUniverse,
    ]);
    const queueSelectedProjectRefresh = useCallback((options) => {
        if (options?.refreshTasks) {
            wsRefreshNeedsTasksRef.current = true;
        }
        if (options?.refreshExecutionState) {
            wsRefreshNeedsExecutionStateRef.current = true;
        }
        if (options?.refreshDependencies) {
            wsRefreshNeedsDependenciesRef.current = true;
        }
        if (options?.refreshProjects) {
            wsRefreshNeedsProjectsRef.current = true;
        }
        wsRefreshQueuedRef.current = true;
        if (wsRefreshTimeoutRef.current !== null || wsRefreshRunningRef.current) {
            return;
        }
        wsRefreshTimeoutRef.current = window.setTimeout(() => {
            wsRefreshTimeoutRef.current = null;
            const projectId = selectedProjectIdRef.current;
            const shouldRefreshTasks = wsRefreshNeedsTasksRef.current;
            const shouldRefreshExecutionState = wsRefreshNeedsExecutionStateRef.current;
            const shouldRefreshDependencies = wsRefreshNeedsDependenciesRef.current;
            const shouldRefreshProjects = wsRefreshNeedsProjectsRef.current;
            wsRefreshQueuedRef.current = false;
            wsRefreshNeedsTasksRef.current = false;
            wsRefreshNeedsExecutionStateRef.current = false;
            wsRefreshNeedsDependenciesRef.current = false;
            wsRefreshNeedsProjectsRef.current = false;
            const work = [];
            if (shouldRefreshProjects) {
                const refreshProjectsFn = refreshProjectsRef.current;
                if (refreshProjectsFn) {
                    work.push(refreshProjectsFn());
                }
            }
            if (projectId) {
                if (shouldRefreshTasks) {
                    const refreshTasksFn = refreshTasksRef.current;
                    if (refreshTasksFn) {
                        work.push(refreshTasksFn(projectId));
                    }
                }
                if (shouldRefreshExecutionState) {
                    const refreshExecutionStateFn = refreshExecutionStateRef.current;
                    if (refreshExecutionStateFn) {
                        work.push(refreshExecutionStateFn(projectId));
                    }
                }
                if (shouldRefreshDependencies) {
                    const refreshDependenciesFn = refreshDependenciesRef.current;
                    if (refreshDependenciesFn) {
                        work.push(refreshDependenciesFn(projectId));
                    }
                }
            }
            if (work.length === 0) {
                return;
            }
            wsRefreshRunningRef.current = true;
            void Promise.all(work).finally(() => {
                wsRefreshRunningRef.current = false;
                if (wsRefreshQueuedRef.current ||
                    wsRefreshNeedsTasksRef.current ||
                    wsRefreshNeedsExecutionStateRef.current ||
                    wsRefreshNeedsDependenciesRef.current ||
                    wsRefreshNeedsProjectsRef.current) {
                    queueSelectedProjectRefresh();
                }
            });
        }, WS_REFRESH_DELAY_MS);
    }, []);
    const queueSubprojectRefresh = useCallback((options) => {
        if (options?.refreshProjects) {
            wsSubprojectRefreshNeedsProjectsRef.current = true;
        }
        wsSubprojectRefreshQueuedRef.current = true;
        if (wsSubprojectRefreshTimeoutRef.current !== null ||
            wsSubprojectRefreshRunningRef.current) {
            return;
        }
        wsSubprojectRefreshTimeoutRef.current = window.setTimeout(() => {
            wsSubprojectRefreshTimeoutRef.current = null;
            const shouldRefreshProjects = wsSubprojectRefreshNeedsProjectsRef.current;
            wsSubprojectRefreshQueuedRef.current = false;
            wsSubprojectRefreshNeedsProjectsRef.current = false;
            const refreshSubprojectsFn = refreshSubprojectTaskCountsRef.current;
            const refreshProjectsFn = refreshProjectsRef.current;
            const work = [];
            if (refreshSubprojectsFn) {
                work.push(refreshSubprojectsFn());
            }
            if (shouldRefreshProjects && refreshProjectsFn) {
                work.push(refreshProjectsFn());
            }
            if (work.length === 0) {
                return;
            }
            wsSubprojectRefreshRunningRef.current = true;
            void Promise.all(work).finally(() => {
                wsSubprojectRefreshRunningRef.current = false;
                if (wsSubprojectRefreshQueuedRef.current ||
                    wsSubprojectRefreshNeedsProjectsRef.current) {
                    queueSubprojectRefresh();
                }
            });
        }, WS_REFRESH_DELAY_MS);
    }, []);
    const handleRunOrchestrator = useCallback(async (options) => {
        if (!canUseAi) {
            toast.error("AI features are unavailable with the current license.");
            return;
        }
        if (!selectedProjectId)
            return;
        setRunningOrchestrator(true);
        try {
            const result = await runOrchestrator(selectedProjectId);
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to run orchestrator");
                return;
            }
            const data = result.data;
            if (data?.errors?.length) {
                toast.error(data.errors.join(", "));
            }
            else {
                const dispatched = data?.tasksDispatched?.length || 0;
                const launched = data?.tasksLaunched?.length || 0;
                if (launched > 0) {
                    if (dispatched > 0) {
                        toast.success(`Launched ${launched} task(s). ${dispatched} task(s) still need planner assignment.`);
                    }
                    else {
                        toast.success(`Launched ${launched} task(s).`);
                    }
                }
                else if (dispatched > 0) {
                    toast.info(`${dispatched} task(s) are runnable but still need planner assignment.`);
                }
                else {
                    if (!options?.silentWhenNothingToLaunch) {
                        toast.info("No queued tasks ready to launch");
                    }
                }
            }
            await refreshVisibleTaskData();
        }
        finally {
            setRunningOrchestrator(false);
        }
    }, [canUseAi, selectedProjectId, refreshVisibleTaskData]);
    const handleRunSelectedTaskAgent = useCallback(async () => {
        if (!canUseAi) {
            toast.error("AI features are unavailable with the current license.");
            return;
        }
        const task = tasksRef.current.find((t) => t.taskId === selectedTaskId &&
            t.assigneeType === "Agent" &&
            !!t.assigneeId);
        if (!task)
            return;
        const taskProjectId = task.projectId || selectedProjectId;
        if (!taskProjectId)
            return;
        setRunningOrchestrator(true);
        try {
            const result = await runOrchestrator(taskProjectId);
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to launch agent");
                return;
            }
            const data = result.data;
            if (data?.errors?.length) {
                toast.error(data.errors.join(", "));
            }
            else {
                const launched = data?.tasksLaunched?.length || 0;
                if (launched > 0) {
                    toast.success(`Launched agent for task.`);
                }
                else {
                    toast.info("Could not launch agent. The task may be blocked or already running.");
                }
            }
            await refreshVisibleTaskData();
        }
        finally {
            setRunningOrchestrator(false);
        }
    }, [canUseAi, selectedProjectId, selectedTaskId, refreshVisibleTaskData]);
    const handleReopenSelectedTask = useCallback(async () => {
        if (!selectedTask)
            return;
        const taskProjectId = selectedTask.projectId || selectedProjectId;
        const reopenResult = await updateTask({
            taskId: selectedTask.taskId,
            status: "Todo",
        });
        if (reopenResult.type !== "success") {
            toast.error(reopenResult.summary || "Failed to reopen task");
            return;
        }
        if (selectedTaskIsPlan) {
            toast.success("Task reopened");
            await refreshVisibleTaskData();
            return;
        }
        if (!canUseAi ||
            !selectedTaskHasAssignedAgentProfile ||
            !canRunAssignedAgent ||
            !taskProjectId) {
            toast.success("Task reopened");
            await refreshVisibleTaskData();
            return;
        }
        setRunningOrchestrator(true);
        try {
            const result = await runOrchestrator(taskProjectId);
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to launch agent");
                await refreshVisibleTaskData();
                return;
            }
            const data = result.data;
            if (data?.errors?.length) {
                toast.error(data.errors.join(", "));
            }
            else {
                const launched = data?.tasksLaunched?.length || 0;
                if (launched > 0) {
                    toast.success("Task reopened and agent launched.");
                }
                else {
                    toast.info("Task reopened, but the agent could not be launched. The task may be blocked or already running.");
                }
            }
            await refreshVisibleTaskData();
        }
        finally {
            setRunningOrchestrator(false);
        }
    }, [
        canUseAi,
        selectedTask,
        selectedProjectId,
        selectedTaskIsPlan,
        selectedTaskHasAssignedAgentProfile,
        canRunAssignedAgent,
        refreshVisibleTaskData,
    ]);
    const handleStartPlanning = useCallback(async () => {
        if (!canUseAi) {
            toast.error("AI features are unavailable with the current license.");
            return;
        }
        if (!selectedProjectId)
            return;
        try {
            const result = await triggerPlanning(selectedProjectId);
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to start planning");
                return;
            }
            toast.success("Planning agent started");
            await refreshTasks(selectedProjectId);
            await refreshExecutionState(selectedProjectId);
            await refreshDependencies(selectedProjectId);
            const plan = tasks.find((t) => String(t.taskType ?? "").toLowerCase() === "plan") ??
                tasks.find((t) => t.title === "Project Plan") ??
                null;
            if (plan)
                setTaskSelection(plan.taskId, { source: "system" });
        }
        catch {
            toast.error("Failed to start planning");
        }
    }, [
        canUseAi,
        selectedProjectId,
        refreshTasks,
        refreshExecutionState,
        refreshDependencies,
        setTaskSelection,
        tasks,
    ]);
    const handleProjectStatusChange = useCallback(async (status) => {
        if (!selectedProject)
            return;
        if (selectedProject.permission !== "Owner")
            return;
        if (selectedProject.project.status === status)
            return;
        setSavingProjectStatus(true);
        try {
            const result = await updateProject({
                projectId: selectedProject.project.projectId,
                title: selectedProject.project.title,
                description: selectedProject.project.description ?? "",
                costLimit: selectedProject.project.costLimit ?? null,
                status,
            });
            if (result.type !== "success") {
                toast.error(result.summary || "Failed to update project status");
                return;
            }
            await refreshProjects();
        }
        finally {
            setSavingProjectStatus(false);
        }
    }, [selectedProject, refreshProjects]);
    const handleSelectMyTask = useCallback((task) => {
        handleSelectProject(task.projectId);
        setTaskSelection(task.taskId, { source: "user" });
    }, [handleSelectProject, setTaskSelection]);
    const handleOpenProjectTemplates = useCallback(() => {
        editContext?.switchWorkspace("settings", {
            skipConfirmation: false,
            urlParams: {
                ccpanel: "project-templates",
            },
        });
    }, [editContext]);
    useEffect(() => {
        setTaskBoardNavState({
            projectTitle: selectedProject?.project.title ?? "Tasks",
            projectSubtitle: selectedProject
                ? selectedProject.project.description?.trim() || "No description"
                : "Select a project to get started",
            permissionLabel: selectedProject?.permission ?? "No project selected",
            activeTab,
            isWizardMode,
            isAdministrator,
            showAllProjects: isAdministrator && showAllProjects,
            isProjectsLoading,
            selectedProjectId,
            selectedTaskId,
            projectOptions: flattenProjectsHierarchy(projects.map((project) => ({
                projectId: project.project.projectId,
                parentProjectId: project.project.parentProjectId ?? null,
                title: project.project.title,
                description: project.project.description,
                status: project.project.status,
                permission: project.permission,
                updatedAt: project.project.updatedAt,
                overview: project.overview ?? null,
            }))),
            hasSelectedProject: !!selectedProjectId,
            canCreateTask: canCreate,
            canRunOrchestrator: canCreate && !isPlanning,
            runningOrchestrator,
            canManageProject: selectedProject?.permission === "Owner",
            onSelectMyTask: handleSelectMyTask,
            onSelectProject: handleSelectProject,
            onSetActiveTab: setActiveTab,
            onCreateProject: () => setCreateProjectOpen(true),
            onOpenProjectTemplates: handleOpenProjectTemplates,
            onOpenProjectSettings: (projectId) => setSettingsProjectId(projectId),
            onDeleteProject: (projectId, title) => {
                const runDelete = async () => {
                    const result = await deleteProject(projectId);
                    if (result.type !== "success") {
                        toast.error(result.summary || "Failed to delete project");
                        return;
                    }
                    toast.success("Project deleted");
                    const fallbackProjectId = projects.find((p) => p.project.projectId !== projectId)?.project
                        .projectId ?? null;
                    await refreshProjects();
                    if (selectedProjectId === projectId) {
                        handleSelectProject(fallbackProjectId);
                    }
                };
                if (editContext?.confirm) {
                    editContext.confirm({
                        header: "Delete project",
                        message: `Are you sure you want to delete "${title}"?\n\nAny subprojects under this project will also be deleted. This action cannot be undone.`,
                        acceptLabel: "Delete",
                        showCancel: true,
                        accept: () => {
                            void runDelete();
                        },
                    });
                    return;
                }
                void runDelete();
            },
            onToggleShowAllProjects: (enabled) => {
                setShowAllProjects(enabled);
                void refreshProjects({ includeAll: isAdministrator && enabled });
            },
            onToggleWizardMode: (enabled) => setIsWizardMode(enabled),
            onCreateTask: () => setCreateDialogOpen(true),
            onRunOrchestrator: handleRunOrchestrator,
        });
    }, [
        selectedProject?.project.title,
        selectedProject?.project.description,
        selectedProject?.permission,
        activeTab,
        isWizardMode,
        isAdministrator,
        showAllProjects,
        isProjectsLoading,
        selectedProjectId,
        selectedTaskId,
        projects,
        canCreate,
        isPlanning,
        runningOrchestrator,
        editContext,
        refreshProjects,
        handleSelectMyTask,
        handleSelectProject,
        handleOpenProjectTemplates,
        handleRunOrchestrator,
        selectedProject,
    ]);
    useEffect(() => {
        return () => {
            resetTaskBoardNavState();
        };
    }, []);
    useEffect(() => {
        void refreshProjects();
    }, [refreshProjects]);
    useEffect(() => {
        if (!selectedProjectId) {
            setProjectViewLoadingId(null);
            clearSelectedProjectData();
            return;
        }
        clearSelectedProjectData();
        setProjectViewLoadingId(selectedProjectId);
        let cancelled = false;
        const refreshTasksFn = refreshTasksRef.current;
        const refreshExecutionStateFn = refreshExecutionStateRef.current;
        const refreshDependenciesFn = refreshDependenciesRef.current;
        const refreshGraphLayoutFn = refreshGraphLayoutRef.current;
        void Promise.all([
            refreshTasksFn?.(selectedProjectId),
            refreshExecutionStateFn?.(selectedProjectId),
            refreshDependenciesFn?.(selectedProjectId),
            refreshGraphLayoutFn?.(selectedProjectId),
        ]).finally(() => {
            if (cancelled)
                return;
            if (selectedProjectIdRef.current !== selectedProjectId)
                return;
            setProjectViewLoadingId(null);
        });
        return () => {
            cancelled = true;
        };
    }, [clearSelectedProjectData, selectedProjectId]);
    useEffect(() => {
        void refreshSubprojectTaskCounts();
    }, [refreshSubprojectTaskCounts]);
    useEffect(() => {
        previousTaskStatusesRef.current = {};
        previousWizardAttentionSignatureRef.current = "";
    }, [selectedProjectId]);
    useEffect(() => {
        if (!selectedProjectId)
            return;
        const previousStatuses = previousTaskStatusesRef.current;
        const currentStatuses = {};
        const transitions = [];
        let movedToDone = false;
        for (const task of tasksWithDisplayAssignees) {
            const currentStatus = normalizeTaskStatus(task.status, task.executionState);
            currentStatuses[task.taskId] = currentStatus;
            const previousStatus = previousStatuses[task.taskId];
            if (previousStatus &&
                previousStatus !== "Done" &&
                currentStatus === "Done") {
                movedToDone = true;
            }
            if (!previousStatus || previousStatus !== currentStatus) {
                transitions.push({
                    taskId: task.taskId,
                    title: task.title,
                    previousStatus: previousStatus ?? null,
                    currentStatus,
                    rawStatus: task.status ?? null,
                    executionState: task.executionState ?? null,
                });
            }
        }
        previousTaskStatusesRef.current = currentStatuses;
        if (transitions.length > 0) {
            // transitions tracked for potential future use
        }
        if (canUseAi &&
            movedToDone &&
            canCreate &&
            !isPlanning &&
            !runningOrchestrator) {
            void handleRunOrchestrator({ silentWhenNothingToLaunch: true });
        }
    }, [
        canUseAi,
        selectedProjectId,
        tasksWithDisplayAssignees,
        canCreate,
        isPlanning,
        runningOrchestrator,
        handleRunOrchestrator,
    ]);
    // Keep task board in sync with backend task updates pushed over WebSocket.
    // Uses refs for callbacks and selectedProjectId so the effect only depends on
    // editContext (stable), preventing cleanup from canceling pending refresh timeouts.
    useEffect(() => {
        const addListener = editContext?.addSocketMessageListener;
        if (!addListener)
            return;
        const unsubscribe = addListener((message) => {
            const messageType = message?.type;
            if (messageType === "project:properties:updated") {
                const payload = message?.payload;
                const projectId = payload?.projectId;
                const currentProjectId = selectedProjectIdRef.current;
                const refreshGraphLayoutFn = refreshGraphLayoutRef.current;
                if (projectId &&
                    currentProjectId &&
                    projectId === currentProjectId &&
                    refreshGraphLayoutFn) {
                    void refreshGraphLayoutFn(projectId);
                }
                return;
            }
            if (messageType === "project:updated") {
                const payload = message?.payload;
                const projectId = payload?.projectId;
                const currentProjectId = selectedProjectIdRef.current;
                if (!projectId ||
                    !currentProjectId ||
                    !isProjectWithinSelectedTree(projectId, currentProjectId)) {
                    return;
                }
                if (projectId === currentProjectId) {
                    queueSelectedProjectRefresh({ refreshProjects: true });
                    return;
                }
                queueSubprojectRefresh({ refreshProjects: true });
                return;
            }
            if (messageType === "task:state-changed") {
                const payload = message?.payload;
                const projectId = payload?.projectId ?? payload?.record?.projectId;
                const record = payload?.record;
                const currentProjectId = selectedProjectIdRef.current;
                if (!projectId || !currentProjectId || !record?.taskId)
                    return;
                if (projectId === currentProjectId) {
                    setExecutionRecordsByTaskId((prev) => {
                        const current = prev[record.taskId];
                        if (current && current.version > record.version) {
                            return prev;
                        }
                        if (current &&
                            current.version === record.version &&
                            current.taskStatus === record.taskStatus &&
                            current.executionState === record.executionState &&
                            current.attentionReason === record.attentionReason &&
                            current.waitingOnDialogId === record.waitingOnDialogId &&
                            current.waitingOnToolCallId === record.waitingOnToolCallId &&
                            current.agentId === record.agentId) {
                            return prev;
                        }
                        return {
                            ...prev,
                            [record.taskId]: record,
                        };
                    });
                    return;
                }
                if (directSubprojectIdsRef.current.has(projectId)) {
                    setSubprojectExecutionRecordsByProjectId((prev) => {
                        const projectRecords = prev[projectId] ?? {};
                        const current = projectRecords[record.taskId];
                        if (current && (current.version ?? 0) > (record.version ?? 0)) {
                            return prev;
                        }
                        return {
                            ...prev,
                            [projectId]: {
                                ...projectRecords,
                                [record.taskId]: record,
                            },
                        };
                    });
                    queueSubprojectRefresh();
                }
                return;
            }
            if (messageType !== "task:updated" &&
                messageType !== "task:created" &&
                messageType !== "task:deleted") {
                return;
            }
            const payload = message?.payload;
            const projectId = payload?.projectId;
            const currentProjectId = selectedProjectIdRef.current;
            const isDirectSubproject = !!projectId && directSubprojectIdsRef.current.has(projectId);
            if (!projectId || !currentProjectId)
                return;
            if (projectId !== currentProjectId) {
                if (!isDirectSubproject)
                    return;
                queueSubprojectRefresh({
                    refreshProjects: messageType !== "task:updated",
                });
                return;
            }
            queueSelectedProjectRefresh({
                refreshTasks: true,
                refreshExecutionState: messageType !== "task:updated",
                refreshDependencies: true,
                refreshProjects: messageType !== "task:updated",
            });
        });
        return () => {
            unsubscribe();
            // Do NOT clear wsRefreshTimeoutRef here — the ref persists across effect
            // re-runs and the timeout callback reads the latest values via refs.
            // Clearing it here was the bug: editContext changes caused cleanup to
            // cancel the pending debounced refresh before it could fire.
        };
    }, [editContext, isProjectWithinSelectedTree, queueSelectedProjectRefresh, queueSubprojectRefresh]);
    // Keep project dropdown in sync when projects are created elsewhere (e.g. by agents).
    useEffect(() => {
        const addListener = editContext?.addSocketMessageListener;
        if (!addListener)
            return;
        const unsubscribe = addListener((message) => {
            if (message?.type !== "project:created")
                return;
            void refreshProjects();
        });
        return () => unsubscribe();
    }, [editContext, refreshProjects]);
    // Clean up pending debounced refresh on unmount only.
    useEffect(() => {
        return () => {
            if (wsRefreshTimeoutRef.current !== null) {
                window.clearTimeout(wsRefreshTimeoutRef.current);
                wsRefreshTimeoutRef.current = null;
            }
            if (wsSubprojectRefreshTimeoutRef.current !== null) {
                window.clearTimeout(wsSubprojectRefreshTimeoutRef.current);
                wsSubprojectRefreshTimeoutRef.current = null;
            }
            wsRefreshQueuedRef.current = false;
            wsRefreshRunningRef.current = false;
            wsRefreshNeedsTasksRef.current = false;
            wsRefreshNeedsExecutionStateRef.current = false;
            wsRefreshNeedsDependenciesRef.current = false;
            wsRefreshNeedsProjectsRef.current = false;
            wsSubprojectRefreshQueuedRef.current = false;
            wsSubprojectRefreshRunningRef.current = false;
            wsSubprojectRefreshNeedsProjectsRef.current = false;
            if (wizardCloseTransitionTimeoutRef.current !== null) {
                window.clearTimeout(wizardCloseTransitionTimeoutRef.current);
                wizardCloseTransitionTimeoutRef.current = null;
            }
        };
    }, []);
    // Ensure selected task still exists after reload
    useEffect(() => {
        if (!selectedTaskId)
            return;
        if (selectedTaskSource === "system")
            return;
        if (!taskSelectionUniverse.some((t) => t.taskId === selectedTaskId)) {
            setTaskSelection(null);
        }
    }, [
        isWizardMode,
        selectedTaskId,
        selectedTaskSource,
        setTaskSelection,
        taskSelectionUniverse,
    ]);
    // No special auto-selection by project status — the agent panel is driven by
    // whichever task the user selects.
    // The backend now creates the Plan task and triggers the planner agent
    // during project creation (TaskService.CreateProjectAsync), so we no longer
    // need to auto-trigger planning from the frontend.
    const handleCloseWizardTask = useCallback((options) => {
        const closingProjectId = selectedProjectId;
        const closedTaskId = wizardDisplayedTask?.taskId ?? selectedTaskId ?? wizardPinnedTaskId;
        clearWizardCloseTransitionTimeout();
        setTaskSelection(null, { pinInWizard: false });
        setWizardForceOverview(true);
        if (!options?.advanceToNext) {
            return;
        }
        wizardCloseTransitionTimeoutRef.current = window.setTimeout(() => {
            wizardCloseTransitionTimeoutRef.current = null;
            if (!closingProjectId)
                return;
            if (selectedProjectIdRef.current !== closingProjectId)
                return;
            const nextAttentionTaskId = findNextAttentionTaskId(closedTaskId);
            setWizardForceOverview(false);
            if (nextAttentionTaskId) {
                setTaskSelection(nextAttentionTaskId, {
                    source: "system",
                    pinInWizard: true,
                });
            }
        }, 1000);
    }, [
        selectedProjectId,
        wizardDisplayedTask?.taskId,
        selectedTaskId,
        wizardPinnedTaskId,
        clearWizardCloseTransitionTimeout,
        findNextAttentionTaskId,
        setTaskSelection,
    ]);
    const wizardCommunicationPanel = useMemo(() => (_jsx(WizardCommunicationCenter, { task: wizardDisplayedTask, agentId: wizardDisplayedAgentId, agentStatus: undefined, executionDisplay: wizardDisplayedExecutionDisplay, summaryState: wizardAttentionState.summaryState, stats: wizardAttentionState.stats, allTasks: wizardTasksWithDisplayAssignees, dependencies: dependencies, canEdit: canEditTasks, onContentChanged: () => {
            void refreshVisibleTaskData();
        }, onTaskChanged: () => {
            handleCloseWizardTask({ advanceToNext: true });
            void refreshVisibleTaskData();
        }, onTaskApproved: async () => {
            await refreshVisibleTaskData();
            handleCloseWizardTask({ advanceToNext: true });
        }, onInteractionSubmitted: () => {
            handleCloseWizardTask({ advanceToNext: true });
        }, onCloseTask: () => handleCloseWizardTask(), onSelectTask: (taskId) => {
            clearWizardCloseTransitionTimeout();
            setWizardForceOverview(false);
            setTaskSelection(taskId, { source: "user", pinInWizard: true });
        }, onOpenAgentTab: isMobile ? () => setMobileActiveTab(2) : undefined })), [
        wizardDisplayedTask,
        wizardDisplayedAgentId,
        wizardDisplayedExecutionDisplay,
        wizardAttentionState.summaryState,
        wizardAttentionState.stats,
        wizardTasksWithDisplayAssignees,
        dependencies,
        canEditTasks,
        isMobile,
        refreshVisibleTaskData,
        handleCloseWizardTask,
        clearWizardCloseTransitionTimeout,
        setTaskSelection,
    ]);
    const isProjectViewLoading = !!selectedProjectId && projectViewLoadingId === selectedProjectId;
    const taskBoardContent = useMemo(() => {
        if (isProjectViewLoading) {
            return (_jsx("div", { className: "flex h-full min-h-[240px] items-center justify-center rounded-lg border border-dashed border-slate-200 bg-slate-50/70", "data-testid": "taskboard-project-loading-state", children: _jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-3 text-sm", children: [_jsx(Loader2, { className: "h-6 w-6 animate-spin" }), _jsx("div", { children: "Loading project..." })] }) }));
        }
        if (!selectedProjectId || (!selectedProject && !isProjectsLoading)) {
            return (_jsx("div", { className: "flex min-h-full w-full flex-col p-4 md:p-8", children: _jsx("div", { className: "mx-auto flex h-full min-h-0 w-full max-w-7xl flex-1", children: _jsx(ProjectOverviewContent, { nav: nav }) }) }));
        }
        if (isWizardMode) {
            return (_jsx(WizardView, { projectId: selectedProjectId, tasks: tasksWithDisplayAssignees, projectTasksLoading: isTasksLoading, dependencies: dependencies, subprojectTaskLists: wizardSubprojectTaskLists, subprojectTasksLoading: subprojectCountsLoading, selectedTaskId: wizardDisplayedTask?.taskId ?? null, onSelectTask: (id) => {
                    setWizardForceOverview(false);
                    setTaskSelection(id, { source: "user", pinInWizard: true });
                }, projectTitle: selectedProject?.project.title ?? "No project selected", projectDescription: selectedProject?.project.description, projectCostUsed: selectedProjectCumulativeCostUsed, projectCostLimit: selectedProject?.project.costLimit ?? null, canEditProperties: selectedProject?.permission === "Owner", communicationPanel: wizardCommunicationPanel }));
        }
        if (isListView) {
            return (_jsxs("div", { className: "grid gap-3", children: [_jsx(ProjectDashboard, { projectId: selectedProjectId, selectedProjectTitle: selectedProject?.project.title ?? "No project selected", selectedProjectDescription: selectedProject?.project.description, selectedProjectStatus: selectedProject?.project.status, selectedProjectCostUsed: selectedProjectCumulativeCostUsed, selectedProjectCostLimit: selectedProject?.project.costLimit ?? null, canEditProjectStatus: selectedProject?.permission === "Owner", savingProjectStatus: savingProjectStatus, onStatusChange: handleProjectStatusChange, selectedProjectTaskCounts: selectedProjectTaskCounts, subprojects: directSubprojects, taskCountsByProjectId: subprojectTaskCounts, loading: subprojectCountsLoading, parentProjectId: parentProject?.project.projectId ?? null, parentProjectTitle: parentProject?.project.title ?? null, onSelectProject: handleSelectProject, canEditProperties: selectedProject?.permission === "Owner" }), sharedViewSwitcher, _jsx(ListView, { tasks: tasksWithDisplayAssignees, onSelectTask: (id) => setTaskSelection(id, { source: "user" }), selectedTaskId: selectedTaskId, onTasksChanged: () => {
                            void refreshVisibleTaskData();
                        }, projectId: selectedProjectId, permission: selectedProject?.permission })] }));
        }
        if (isGraphView) {
            return (_jsxs("div", { className: "flex h-full min-h-0 min-w-0 flex-col gap-3", children: [_jsx(ProjectDashboard, { projectId: selectedProjectId, selectedProjectTitle: selectedProject?.project.title ?? "No project selected", selectedProjectDescription: selectedProject?.project.description, selectedProjectStatus: selectedProject?.project.status, selectedProjectCostUsed: selectedProjectCumulativeCostUsed, selectedProjectCostLimit: selectedProject?.project.costLimit ?? null, canEditProjectStatus: selectedProject?.permission === "Owner", savingProjectStatus: savingProjectStatus, onStatusChange: handleProjectStatusChange, selectedProjectTaskCounts: selectedProjectTaskCounts, subprojects: directSubprojects, taskCountsByProjectId: subprojectTaskCounts, loading: subprojectCountsLoading, parentProjectId: parentProject?.project.projectId ?? null, parentProjectTitle: parentProject?.project.title ?? null, onSelectProject: handleSelectProject, canEditProperties: selectedProject?.permission === "Owner" }), sharedViewSwitcher, _jsx("div", { className: "min-h-0 flex-1", children: _jsx(DependencyGraphView, { projectId: selectedProjectId, tasks: tasksWithDisplayAssignees, dependencies: dependencies, miniMapWidth: 56, miniMapHeight: 42, orientation: "horizontal", autoLayoutStrategy: "hierarchy", showOrientationToggle: true, savedLayout: graphLayout, selectedTaskId: selectedTaskId, onSelectTask: (id) => setTaskSelection(id, { source: "user" }), permission: selectedProject?.permission, onLayoutSaved: (layout) => setGraphLayout(layout && selectedProjectId
                                ? {
                                    projectId: selectedProjectId,
                                    ...layout,
                                }
                                : null) }) })] }));
        }
        return (_jsxs("div", { className: "flex h-full min-h-0 min-w-0 flex-col gap-3", children: [_jsx(ProjectDashboard, { projectId: selectedProjectId, selectedProjectTitle: selectedProject?.project.title ?? "No project selected", selectedProjectDescription: selectedProject?.project.description, selectedProjectStatus: selectedProject?.project.status, selectedProjectCostUsed: selectedProjectCumulativeCostUsed, selectedProjectCostLimit: selectedProject?.project.costLimit ?? null, canEditProjectStatus: selectedProject?.permission === "Owner", savingProjectStatus: savingProjectStatus, onStatusChange: handleProjectStatusChange, selectedProjectTaskCounts: selectedProjectTaskCounts, subprojects: directSubprojects, taskCountsByProjectId: subprojectTaskCounts, loading: subprojectCountsLoading, parentProjectId: parentProject?.project.projectId ?? null, parentProjectTitle: parentProject?.project.title ?? null, onSelectProject: handleSelectProject, canEditProperties: selectedProject?.permission === "Owner" }), sharedViewSwitcher, _jsx(KanbanView, { tasks: tasksWithDisplayAssignees, dependencies: dependencies, onSelectTask: (id) => setTaskSelection(id, { source: "user" }), selectedTaskId: selectedTaskId, onTasksChanged: () => {
                        void refreshVisibleTaskData();
                    }, projectId: selectedProjectId, permission: selectedProject?.permission })] }));
    }, [
        isProjectViewLoading,
        selectedProjectId,
        selectedProject,
        isProjectsLoading,
        isWizardMode,
        isListView,
        isGraphView,
        selectedProjectCumulativeCostUsed,
        savingProjectStatus,
        handleProjectStatusChange,
        selectedProjectTaskCounts,
        directSubprojects,
        subprojectTaskCounts,
        subprojectCountsLoading,
        parentProject?.project.projectId,
        parentProject?.project.title,
        handleSelectProject,
        sharedViewSwitcher,
        tasksWithDisplayAssignees,
        dependencies,
        selectedTaskId,
        activeTab,
        canEditTasks,
        nav,
        isTasksLoading,
        wizardSubprojectTaskLists,
        wizardDisplayedTask?.taskId,
        wizardCommunicationPanel,
        setTaskSelection,
        refreshVisibleTaskData,
    ]);
    const taskDetailPanel = useMemo(() => (_jsx(TaskDetailPanel, { project: selectedTaskProject, projects: projects, task: selectedTask, allTasks: taskSelectionUniverse, dependencies: dependencies, onTaskChanged: () => {
            void refreshVisibleTaskData();
        }, onSelectTask: (taskId) => setTaskSelection(taskId, { source: "user" }), onClose: () => setTaskSelection(null), variant: "panel" })), [
        selectedTaskProject,
        selectedTask,
        taskSelectionUniverse,
        dependencies,
        refreshVisibleTaskData,
        setTaskSelection,
    ]);
    const agentTerminalPanel = useMemo(() => (_jsx(TaskAgentPanel, { agentId: displayAgentId, mode: agentPanelMode, label: selectedTaskIsPlan ? "Planner" : "Task Agent", hasAssignedAgentProfile: !selectedTaskIsPlan && selectedTaskHasAssignedAgentProfile, assignedAgentProfileName: !selectedTaskIsPlan && selectedTaskHasAssignedAgentProfile
            ? selectedTask?.assigneeDisplayName ||
                selectedTask?.assigneeId ||
                null
            : null, canRunAssignedAgent: canRunAssignedAgent, runAssignedAgentDisabledReason: runAssignedAgentDisabledReason, onRunAssignedAgent: !selectedTaskIsPlan &&
            selectedTaskHasAssignedAgentProfile &&
            canRunAssignedAgent
            ? () => void handleRunSelectedTaskAgent()
            : undefined, onStartPlanning: selectedTaskIsPlan && isPlanning ? handleStartPlanning : undefined, canAssignAgent: !selectedTaskIsBlocked, assignAgentDisabledReason: selectedTaskIsBlocked
            ? "This task is blocked by unfinished dependencies."
            : undefined, onAssignAgent: !selectedTaskIsPlan &&
            canEditTasks &&
            agentPanelMode === "no-agent" &&
            !selectedTaskHasAssignedAgentProfile
            ? () => setAssignAgentDialogOpen(true)
            : undefined, assignedAgentStatus: undefined, onReopenTask: selectedTask && canEditTasks
            ? () => void handleReopenSelectedTask()
            : undefined })), [
        displayAgentId,
        agentPanelMode,
        selectedTaskIsPlan,
        selectedTaskHasAssignedAgentProfile,
        canRunAssignedAgent,
        runAssignedAgentDisabledReason,
        handleRunSelectedTaskAgent,
        isPlanning,
        handleStartPlanning,
        selectedTaskIsBlocked,
        canEditTasks,
        selectedTask,
        handleReopenSelectedTask,
    ]);
    const itemPreviewPanel = useMemo(() => {
        const hasCurrentItem = !!currentItemDescriptor;
        const previewSidebar = (_jsx("div", { className: "relative z-10 flex h-full min-h-0 flex-col bg-white", children: _jsx("div", { className: "min-h-0 flex-1", children: _jsx(MainContentTree, { mode: "normal" }) }) }));
        const renderPreviewSplit = (editorContent) => (_jsx(Splitter, { localStorageKey: "taskboard-preview-tree-splitter", panels: [
                {
                    name: "content-tree",
                    defaultSize: 320,
                    content: previewSidebar,
                },
                {
                    name: "editor-preview",
                    defaultSize: "auto",
                    content: (_jsx("div", { className: "h-full min-h-0 min-w-0 overflow-hidden bg-gray-50", children: editorContent })),
                },
            ], splitterClassName: "bg-gray-200 hover:bg-gray-300 w-[6px]", className: "h-full", direction: isMobile ? "vertical" : "horizontal" }));
        if (!currentItemDescriptor) {
            return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsx("div", { className: "border-b border-gray-200 bg-white px-3 py-2", children: hasCurrentItem ? (_jsxs("div", { className: "min-w-0", children: [hasMultipleContextItems ? (_jsx(Select, { value: selectedContextItemValue, onValueChange: handleSelectContextItem, options: contextItemOptions, placeholder: "Select context item", size: "xs", searchable: true, className: "h-7 rounded-md bg-white", maxWidth: 420, "data-testid": "taskboard-context-item-selector" })) : (_jsx("div", { className: "truncate text-sm font-medium text-slate-900", children: previewItemName || "Loading item..." })), _jsxs("div", { className: "mt-0.5 flex items-center gap-2", children: [_jsx("span", { className: "truncate text-xs text-slate-500", children: previewItemPath || "Path unavailable" }), _jsx("span", { className: "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-[10px] font-medium text-slate-600", children: selectedContextItemValue.split("|")[1] || "" }), previewItemVersion != null && (_jsxs("span", { className: "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-[10px] font-medium text-slate-600", children: ["v", previewItemVersion] }))] })] })) : (_jsx("div", { className: "text-xs text-slate-500", children: "No item loaded" })) }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden bg-gray-50", children: renderPreviewSplit(_jsxs("div", { className: "flex h-full min-h-0 flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx("div", { className: "text-muted-foreground text-sm font-medium", children: "Editor preview unavailable" }), _jsx("div", { className: "text-muted-foreground text-xs", children: "Open the editor context item to preview and edit it here." })] })) })] }));
        }
        return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsx("div", { className: "border-b border-gray-200 bg-white px-3 py-2", children: hasCurrentItem ? (_jsxs("div", { className: "min-w-0", children: [hasMultipleContextItems ? (_jsx(Select, { value: selectedContextItemValue, onValueChange: handleSelectContextItem, options: contextItemOptions, placeholder: "Select context item", size: "xs", searchable: true, className: "h-7 rounded-md bg-white", maxWidth: 420, "data-testid": "taskboard-context-item-selector" })) : (_jsx("div", { className: "truncate text-sm font-medium text-slate-900", children: previewItemName || "Loading item..." })), _jsxs("div", { className: "mt-0.5 flex items-center gap-2", children: [_jsx("span", { className: "truncate text-xs text-slate-500", children: previewItemPath || "Path unavailable" }), _jsx("span", { className: "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-[10px] font-medium text-slate-600", children: currentItemDescriptor?.language }), previewItemVersion != null && (_jsxs("span", { className: "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-[10px] font-medium text-slate-600", children: ["v", previewItemVersion] }))] })] })) : (_jsx("div", { className: "text-xs text-slate-500", children: "No item loaded" })) }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden bg-gray-50", children: renderPreviewSplit(_jsx(TaskboardPreviewEditor, { itemDescriptor: currentItemDescriptor })) })] }));
    }, [
        currentItemDescriptor,
        hasMultipleContextItems,
        selectedContextItemValue,
        handleSelectContextItem,
        contextItemOptions,
        previewItemName,
        previewItemPath,
        previewItemVersion,
        isMobile,
    ]);
    useEffect(() => {
        if (!assignAgentDialogOpen)
            return;
        if (!selectedTask ||
            agentPanelMode !== "no-agent" ||
            selectedTaskIsBlocked) {
            setAssignAgentDialogOpen(false);
        }
    }, [
        assignAgentDialogOpen,
        selectedTask,
        agentPanelMode,
        selectedTaskIsBlocked,
    ]);
    const panels = useMemo(() => {
        if (isWizardMode) {
            const wizardPanels = [
                {
                    name: "wizard-view",
                    defaultSize: 70,
                    content: (_jsx("div", { className: "h-full overflow-x-hidden overflow-y-auto bg-slate-50/50", children: taskBoardContent })),
                },
            ];
            if (showEditorPanel) {
                wizardPanels.push({
                    name: "editor-preview",
                    defaultSize: 30,
                    content: (_jsx("div", { className: "h-full overflow-hidden border-l border-gray-200 bg-gray-50", children: itemPreviewPanel })),
                });
            }
            return wizardPanels;
        }
        if (isListView) {
            const listPanels = [
                {
                    name: "task-list",
                    defaultSize: "auto",
                    content: (_jsx("div", { className: "h-full overflow-x-auto overflow-y-auto bg-slate-50/50 p-2 pt-2 md:p-4 md:pt-3", children: taskBoardContent })),
                },
                {
                    name: "task-details",
                    defaultSize: 420,
                    content: taskDetailPanel,
                    hidden: !selectedProjectId || !selectedTask,
                },
                {
                    name: "agent-terminal",
                    defaultSize: 560,
                    content: agentTerminalPanel,
                    hidden: !selectedProjectId || shouldHideAgentPanelForSelectedTask,
                },
            ];
            if (showEditorPanel) {
                listPanels.push({
                    name: "editor-preview",
                    defaultSize: 500,
                    content: (_jsx("div", { className: "h-full overflow-hidden border-l border-gray-200 bg-gray-50", children: itemPreviewPanel })),
                });
            }
            return listPanels;
        }
        if (isGraphView) {
            const graphPanels = [
                {
                    name: "task-list",
                    defaultSize: "auto",
                    content: (_jsx("div", { className: cn("flex h-full min-h-0 flex-col overflow-x-hidden overflow-y-auto bg-slate-50/50", selectedProjectId && "p-4 pt-3"), children: taskBoardContent })),
                },
                {
                    name: "task-details",
                    defaultSize: 420,
                    content: taskDetailPanel,
                    hidden: !selectedProjectId || !selectedTask,
                },
                {
                    name: "agent-terminal",
                    defaultSize: 560,
                    content: agentTerminalPanel,
                    hidden: !selectedProjectId || shouldHideAgentPanelForSelectedTask,
                },
            ];
            if (showEditorPanel) {
                graphPanels.push({
                    name: "editor-preview",
                    defaultSize: 500,
                    content: (_jsx("div", { className: "h-full overflow-hidden border-l border-gray-200 bg-gray-50", children: itemPreviewPanel })),
                });
            }
            return graphPanels;
        }
        const kanbanPanels = [
            {
                name: "task-list",
                defaultSize: "auto",
                content: (_jsx("div", { className: cn("flex h-full min-h-0 flex-col overflow-x-hidden overflow-y-auto bg-slate-50/50", selectedProjectId && "p-4 pt-3"), children: taskBoardContent })),
            },
            {
                name: "task-details",
                defaultSize: 420,
                content: taskDetailPanel,
                hidden: !selectedProjectId || !selectedTask,
            },
            {
                name: "agent-terminal",
                defaultSize: 560,
                content: agentTerminalPanel,
                hidden: !selectedProjectId || shouldHideAgentPanelForSelectedTask,
            },
        ];
        if (showEditorPanel) {
            kanbanPanels.push({
                name: "editor-preview",
                defaultSize: 500,
                content: (_jsx("div", { className: "h-full overflow-hidden border-l border-gray-200 bg-gray-50", children: itemPreviewPanel })),
            });
        }
        return kanbanPanels;
    }, [
        isWizardMode,
        isListView,
        isGraphView,
        selectedProjectId,
        taskBoardContent,
        taskDetailPanel,
        selectedTask,
        agentTerminalPanel,
        shouldHideAgentPanelForSelectedTask,
        showEditorPanel,
        itemPreviewPanel,
    ]);
    return (_jsxs("div", { className: "text-foreground flex h-full w-full flex-col bg-white select-text", children: [_jsx("div", { className: "min-h-0 flex-1", children: isMobile ? (_jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [selectedProjectId && (_jsx("div", { className: "shrink-0 border-b border-gray-100 bg-white px-4 shadow-[0_1px_2px_rgba(0,0,0,0.03)]", children: _jsx(SimpleTabs, { tabs: [
                                    { id: "project", label: "Project", content: null },
                                    {
                                        id: "task",
                                        label: "Task",
                                        content: null,
                                        disabled: !selectedTaskId,
                                    },
                                    {
                                        id: "agent",
                                        label: "Agent",
                                        content: null,
                                        disabled: !displayAgentId || shouldHideAgentPanelForSelectedTask,
                                    },
                                    ...(showEditorPanel
                                        ? [{ id: "editor", label: "Editor", content: null }]
                                        : []),
                                ], activeTab: mobileActiveTab, setActiveTab: setMobileActiveTab, hideContent: true, variant: "elegant", className: "gap-6" }) })), _jsxs("div", { className: "min-h-0 flex-1 overflow-hidden", children: [mobileActiveTab === 0 && (_jsx("div", { className: cn("flex h-full overflow-y-auto bg-slate-50/50", selectedProjectId &&
                                        !isWizardMode &&
                                        "p-2 pt-2 md:p-4 md:pt-3"), children: taskBoardContent })), mobileActiveTab === 1 && (_jsx("div", { className: "h-full overflow-y-auto bg-white", children: taskDetailPanel })), mobileActiveTab === 2 && (_jsx("div", { className: "h-full overflow-hidden bg-white", children: shouldHideAgentPanelForSelectedTask
                                        ? taskDetailPanel
                                        : agentTerminalPanel })), mobileActiveTab === 3 && showEditorPanel && (_jsx("div", { className: "h-full overflow-hidden bg-gray-50", children: itemPreviewPanel }))] })] })) : (_jsx(Splitter, { panels: panels, direction: "horizontal", localStorageKey: isWizardMode
                        ? "task-board-wizard-splitter-v2"
                        : "task-board-main-splitter" })) }), selectedProjectId && (_jsx(CreateTaskDialog, { open: createDialogOpen, onOpenChange: setCreateDialogOpen, projectId: selectedProjectId, availableParentTasks: tasks, onCreated: () => {
                    void refreshTasks(selectedProjectId);
                    void refreshExecutionState(selectedProjectId);
                    void refreshDependencies(selectedProjectId);
                } })), _jsx(CreateProjectDialog, { open: createProjectOpen, onOpenChange: setCreateProjectOpen, projects: projects, onCreated: async ({ projectId: newProjectId, openInWizardMode }) => {
                    if (openInWizardMode) {
                        setIsWizardMode(true);
                        setWizardForceOverview(false);
                    }
                    if (newProjectId)
                        handleSelectProject(newProjectId);
                    await refreshProjects();
                } }), _jsx(ProjectSettingsDialog, { open: !!settingsProjectId, onOpenChange: (open) => {
                    if (!open)
                        setSettingsProjectId(null);
                }, projectId: settingsProjectId, selectedProject: settingsProject, projects: projects, onChanged: async () => {
                    await refreshProjects();
                    await refreshVisibleTaskData();
                } }), _jsx(AssignAgentDialog, { open: assignAgentDialogOpen, task: selectedTask, onOpenChange: setAssignAgentDialogOpen, onAssigned: async () => {
                    if (!selectedProjectId)
                        return;
                    await refreshTasks(selectedProjectId);
                    await refreshExecutionState(selectedProjectId);
                    await refreshDependencies(selectedProjectId);
                } })] }));
}
//# sourceMappingURL=TaskBoardWorkspace.js.map