"use client";

import {
	Activity,
	BarChart3,
	CheckCircle2,
	ChevronDown,
	ChevronRight,
	Circle,
	Columns2,
	FileText,
	Folder,
	FolderKanban,
	GitBranch,
	LayoutDashboard,
	LifeBuoy,
	Loader2,
	LogOut,
	Map as MapIcon,
	MessagesSquare,
	Milestone,
	Monitor,
	Moon,
	PanelRightClose,
	PanelRightOpen,
	Play,
	Server,
	Settings,
	SkipForward,
	Sun,
} from "lucide-react";
import { useTheme } from "next-themes";
import { useMemo, useState, useSyncExternalStore } from "react";
import { Button } from "@/components/ui/button";
import {
	Dialog,
	DialogContent,
	DialogDescription,
	DialogFooter,
	DialogHeader,
	DialogTitle,
} from "@/components/ui/dialog";
import { Skeleton } from "@/components/ui/skeleton";
import { authFetch } from "@/lib/auth";
import { useProjectStoreManager } from "@/lib/project-store-manager";
import {
	buildPromptCommand,
	getCurrentScopeLabel,
	getLiveAutoDashboard,
	getLiveWorkspaceIndex,
	useSFWorkspaceActions,
	useSFWorkspaceState,
} from "@/lib/sf-workspace-store";
import { cn } from "@/lib/utils";
import { executeWorkflowActionInPowerMode } from "@/lib/workflow-action-execution";
import { deriveWorkflowAction } from "@/lib/workflow-actions";
import {
	getMilestoneStatus,
	getSliceStatus,
	getTaskStatus,
	type ItemStatus,
} from "@/lib/workspace-status";

const StatusIcon = ({ status }: { status: ItemStatus }) => {
	if (status === "done") {
		return <CheckCircle2 className="h-4 w-4 shrink-0 text-success" />;
	}
	if (status === "in-progress") {
		return <Play className="h-4 w-4 shrink-0 text-warning" />;
	}
	return <Circle className="h-4 w-4 shrink-0 text-muted-foreground" />;
};

/* ─── Nav Rail (left icon bar) ─── */

interface NavRailProps {
	activeView: string;
	onViewChange: (view: string) => void;
	isConnecting?: boolean;
}

export function NavRail({
	activeView,
	onViewChange,
	isConnecting = false,
}: NavRailProps) {
	const { openCommandSurface } = useSFWorkspaceActions();
	const manager = useProjectStoreManager();
	const activeProjectCwd = useSyncExternalStore(
		manager.subscribe,
		manager.getSnapshot,
		manager.getSnapshot,
	);
	const [exitDialogOpen, setExitDialogOpen] = useState(false);
	const { theme, setTheme } = useTheme();

	const cycleTheme = () => {
		if (theme === "system") setTheme("light");
		else if (theme === "light") setTheme("dark");
		else setTheme("system");
	};

	const themeIcon = theme === "light" ? Sun : theme === "dark" ? Moon : Monitor;
	const themeLabel =
		theme === "light" ? "Light" : theme === "dark" ? "Dark" : "System";
	const ThemeIcon = themeIcon;

	const navItems = [
		{ id: "dashboard", label: "Dashboard", icon: LayoutDashboard },
		{ id: "power", label: "Power Mode", icon: Columns2 },
		{ id: "chat", label: "Chat", icon: MessagesSquare },
		{ id: "swarms", label: "Swarms", icon: Server },
		{ id: "roadmap", label: "Roadmap", icon: MapIcon },
		{ id: "files", label: "Files", icon: Folder },
		{ id: "activity", label: "Activity", icon: Activity },
		{ id: "visualize", label: "Visualize", icon: BarChart3 },
	];

	return (
		<div className="flex w-12 flex-col items-center gap-1 border-r border-border bg-sidebar py-3">
			{navItems.map((item) => (
				<button
					type="button"
					key={item.id}
					onClick={() => onViewChange(item.id)}
					disabled={isConnecting}
					className={cn(
						"flex h-10 w-10 items-center justify-center rounded-md transition-colors",
						isConnecting
							? "cursor-not-allowed text-muted-foreground/50"
							: activeView === item.id
								? "bg-accent text-foreground"
								: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
					)}
					title={isConnecting ? "Connecting…" : item.label}
				>
					<item.icon className="h-5 w-5" />
				</button>
			))}
			<div className="mt-auto flex flex-col gap-1">
				<button
					type="button"
					onClick={() =>
						window.dispatchEvent(new CustomEvent("sf:open-projects"))
					}
					disabled={isConnecting}
					className={cn(
						"flex h-10 w-10 items-center justify-center rounded-md transition-colors",
						isConnecting
							? "cursor-not-allowed text-muted-foreground/50"
							: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
					)}
					title={isConnecting ? "Connecting…" : "Projects"}
				>
					<FolderKanban className="h-5 w-5" />
				</button>
				<button
					type="button"
					className={cn(
						"flex h-10 w-10 items-center justify-center rounded-md text-muted-foreground transition-colors",
						isConnecting
							? "cursor-not-allowed opacity-30"
							: "hover:bg-accent/50 hover:text-foreground",
					)}
					title="Git"
					disabled={isConnecting}
					onClick={() =>
						!isConnecting && openCommandSurface("git", { source: "sidebar" })
					}
					data-testid="sidebar-git-button"
				>
					<GitBranch className="h-5 w-5" />
				</button>
				<button
					type="button"
					className={cn(
						"flex h-10 w-10 items-center justify-center rounded-md text-muted-foreground transition-colors",
						isConnecting
							? "cursor-not-allowed opacity-30"
							: "hover:bg-accent/50 hover:text-foreground",
					)}
					title="Settings"
					disabled={isConnecting}
					onClick={() =>
						!isConnecting &&
						openCommandSurface("settings", { source: "sidebar" })
					}
					data-testid="sidebar-settings-button"
				>
					<Settings className="h-5 w-5" />
				</button>
				<button
					type="button"
					className={cn(
						"flex h-10 w-10 items-center justify-center rounded-md text-muted-foreground transition-colors",
						isConnecting
							? "cursor-not-allowed opacity-30"
							: "hover:bg-accent/50 hover:text-foreground",
					)}
					title={`Theme: ${themeLabel}`}
					disabled={isConnecting}
					onClick={() => !isConnecting && cycleTheme()}
					data-testid="sidebar-theme-toggle"
				>
					<ThemeIcon className="h-5 w-5" />
				</button>
				<button
					type="button"
					className={cn(
						"flex h-10 w-10 items-center justify-center rounded-md text-muted-foreground transition-colors",
						isConnecting
							? "cursor-not-allowed opacity-30"
							: "hover:bg-destructive/15 hover:text-destructive",
					)}
					title="Exit"
					disabled={isConnecting}
					onClick={() => !isConnecting && setExitDialogOpen(true)}
					data-testid="sidebar-signoff-button"
				>
					<LogOut className="h-5 w-5" />
				</button>
				<ExitDialog
					open={exitDialogOpen}
					onOpenChange={setExitDialogOpen}
					projectCount={manager.getProjectCount()}
					activeProjectCwd={activeProjectCwd}
					onCloseProject={(cwd) => {
						manager.closeProject(cwd);
						onViewChange("dashboard");
						setExitDialogOpen(false);
					}}
					onStopServer={async () => {
						await authFetch("/api/shutdown", { method: "POST" }).catch(
							() => {},
						);
						setTimeout(() => {
							try {
								window.close();
							} catch {
								/* ignore */
							}
							setTimeout(() => {
								window.location.href = "about:blank";
							}, 300);
						}, 400);
					}}
				/>
			</div>
		</div>
	);
}

/* ─── Exit Dialog (multi-project aware) ─── */

function ExitDialog({
	open,
	onOpenChange,
	projectCount,
	activeProjectCwd,
	onCloseProject,
	onStopServer,
}: {
	open: boolean;
	onOpenChange: (open: boolean) => void;
	projectCount: number;
	activeProjectCwd: string | null;
	onCloseProject: (cwd: string) => void;
	onStopServer: () => void;
}) {
	const hasMultipleProjects = projectCount > 1;
	const projectName = activeProjectCwd
		? (activeProjectCwd.split("/").pop() ?? activeProjectCwd)
		: null;

	if (!hasMultipleProjects) {
		// Single project — simple stop server dialog
		return (
			<Dialog open={open} onOpenChange={onOpenChange}>
				<DialogContent className="sm:max-w-md">
					<DialogHeader>
						<DialogTitle>Stop the SF server?</DialogTitle>
						<DialogDescription>
							This will shut down the server process and close this tab. Run{" "}
							<code className="rounded bg-muted px-1 py-0.5 font-mono text-xs">
								sf server
							</code>{" "}
							again to restart.
						</DialogDescription>
					</DialogHeader>
					<DialogFooter>
						<Button variant="ghost" onClick={() => onOpenChange(false)}>
							Cancel
						</Button>
						<Button variant="destructive" onClick={onStopServer}>
							Stop server
						</Button>
					</DialogFooter>
				</DialogContent>
			</Dialog>
		);
	}

	// Multiple projects — offer close project vs stop server
	return (
		<Dialog open={open} onOpenChange={onOpenChange}>
			<DialogContent className="sm:max-w-md">
				<DialogHeader>
					<DialogTitle>Close project or stop server?</DialogTitle>
					<DialogDescription>
						You have {projectCount} projects open. You can close just the
						current project or stop the entire server.
					</DialogDescription>
				</DialogHeader>
				<div className="flex flex-col gap-2 py-2">
					{activeProjectCwd && (
						<Button
							variant="outline"
							className="h-auto justify-start gap-3 px-4 py-3 text-left"
							onClick={() => onCloseProject(activeProjectCwd)}
						>
							<FolderKanban className="h-4 w-4 shrink-0 text-muted-foreground" />
							<div className="min-w-0">
								<div className="text-sm font-medium">Close {projectName}</div>
								<div className="text-xs text-muted-foreground">
									Disconnect this project and switch to another
								</div>
							</div>
						</Button>
					)}
					<Button
						variant="outline"
						className="h-auto justify-start gap-3 px-4 py-3 text-left border-destructive/30 hover:bg-destructive/10 hover:text-destructive"
						onClick={onStopServer}
					>
						<LogOut className="h-4 w-4 shrink-0" />
						<div className="min-w-0">
							<div className="text-sm font-medium">Stop server</div>
							<div className="text-xs text-muted-foreground">
								Shut down all {projectCount} projects and close the tab
							</div>
						</div>
					</Button>
				</div>
				<DialogFooter>
					<Button variant="ghost" onClick={() => onOpenChange(false)}>
						Cancel
					</Button>
				</DialogFooter>
			</DialogContent>
		</Dialog>
	);
}

/* ─── Milestone Explorer (right sidebar) ─── */

export function MilestoneExplorer({
	isConnecting = false,
	width,
	onCollapse,
}: {
	isConnecting?: boolean;
	width?: number;
	onCollapse?: () => void;
}) {
	const workspace = useSFWorkspaceState();
	const { openCommandSurface, setCommandSurfaceSection, sendCommand } =
		useSFWorkspaceActions();
	const [expandedMilestones, setExpandedMilestones] = useState<string[]>([]);
	const [expandedSlices, setExpandedSlices] = useState<string[]>([]);

	const liveWorkspace = getLiveWorkspaceIndex(workspace);
	const milestones = useMemo(
		() => liveWorkspace?.milestones ?? [],
		[liveWorkspace?.milestones],
	);
	const activeScope = liveWorkspace?.active;
	const auto = getLiveAutoDashboard(workspace);
	const recoverySummary = workspace.live.recoverySummary;
	const validationCount = liveWorkspace?.validationIssues.length ?? 0;
	const currentScopeLabel = getCurrentScopeLabel(liveWorkspace);
	const projectCwd = workspace.boot?.project.cwd ?? null;
	const bridge = workspace.boot?.bridge ?? null;

	const openTaskFile = (absolutePath: string | undefined) => {
		if (!absolutePath || !projectCwd) return;
		const sfPrefix = `${projectCwd}/.sf/`;
		if (!absolutePath.startsWith(sfPrefix)) return;
		const relativePath = absolutePath.slice(sfPrefix.length);
		window.dispatchEvent(
			new CustomEvent("sf:open-file", {
				detail: { root: "sf", path: relativePath },
			}),
		);
	};

	const workflowAction = deriveWorkflowAction({
		phase: liveWorkspace?.active.phase ?? "pre-planning",
		autoActive: auto?.active ?? false,
		autoPaused: auto?.paused ?? false,
		onboardingLocked: workspace.boot?.onboarding.locked ?? false,
		commandInFlight: workspace.commandInFlight,
		bootStatus: workspace.bootStatus,
		hasMilestones: milestones.length > 0,
		projectDetectionKind: workspace.boot?.projectDetection?.kind ?? null,
	});

	const handleCommand = (command: string) => {
		executeWorkflowActionInPowerMode({
			dispatch: () => sendCommand(buildPromptCommand(command, bridge)),
		});
	};

	const handlePrimaryAction = () => {
		if (!workflowAction.primary) return;
		handleCommand(workflowAction.primary.command);
	};

	const handleOpenRecovery = () => {
		openCommandSurface("settings", { source: "sidebar" });
		setCommandSurfaceSection("recovery");
	};

	const effectiveExpandedMilestones =
		activeScope?.milestoneId &&
		!expandedMilestones.includes(activeScope.milestoneId)
			? [...expandedMilestones, activeScope.milestoneId]
			: expandedMilestones;

	const effectiveExpandedSlices =
		activeScope?.milestoneId && activeScope.sliceId
			? (() => {
					const sliceKey = `${activeScope.milestoneId}-${activeScope.sliceId}`;
					return expandedSlices.includes(sliceKey)
						? expandedSlices
						: [...expandedSlices, sliceKey];
				})()
			: expandedSlices;

	const milestoneStatus = new Map(
		milestones.map((milestone) => [
			milestone.id,
			getMilestoneStatus(milestone, activeScope ?? {}),
		]),
	);

	const toggleMilestone = (id: string) => {
		setExpandedMilestones((prev) =>
			prev.includes(id) ? prev.filter((entry) => entry !== id) : [...prev, id],
		);
	};

	const toggleSlice = (id: string) => {
		setExpandedSlices((prev) =>
			prev.includes(id) ? prev.filter((entry) => entry !== id) : [...prev, id],
		);
	};

	return (
		<div
			className="flex flex-col bg-sidebar"
			style={{ width: width ?? 256, flexShrink: 0 }}
		>
			{isConnecting && (
				<div className="flex-1 overflow-y-auto px-1.5 py-1">
					<div className="px-2 py-1.5">
						<span className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
							Milestones
						</span>
					</div>
					<div className="space-y-0.5 px-1">
						{[1, 2].map((m) => (
							<div key={m}>
								<div className="flex items-center gap-1.5 px-2 py-1.5">
									<Skeleton className="h-4 w-4 shrink-0 rounded" />
									<Skeleton className="h-4 w-4 shrink-0 rounded-full" />
									<Skeleton className={cn("h-4", m === 1 ? "w-40" : "w-32")} />
								</div>
								{m === 1 && (
									<div className="ml-4 space-y-0.5">
										{[1, 2, 3].map((s) => (
											<div
												key={s}
												className="flex items-center gap-1.5 px-2 py-1.5"
											>
												<Skeleton className="h-4 w-4 shrink-0 rounded" />
												<Skeleton className="h-4 w-4 shrink-0 rounded-full" />
												<Skeleton
													className={cn(
														"h-3.5",
														s === 1 ? "w-32" : s === 2 ? "w-28" : "w-24",
													)}
												/>
											</div>
										))}
									</div>
								)}
							</div>
						))}
					</div>
				</div>
			)}

			{!isConnecting && (
				<div className="flex-1 overflow-y-auto px-1.5 py-1">
					<div className="flex items-start justify-between px-2 py-1.5">
						<div className="min-w-0">
							<span className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
								Milestones
							</span>
							<div
								className="mt-1 text-xs text-foreground"
								data-testid="sidebar-current-scope"
							>
								{currentScopeLabel}
							</div>
						</div>
						{onCollapse && (
							<button
								type="button"
								onClick={onCollapse}
								className="flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
								title="Collapse sidebar"
							>
								<PanelRightClose className="h-3.5 w-3.5" />
							</button>
						)}
					</div>

					{workspace.bootStatus === "error" && milestones.length === 0 && (
						<div className="px-3 py-2 text-xs text-destructive">
							Workspace boot failed before the explorer could load.
						</div>
					)}

					{workspace.bootStatus === "ready" && milestones.length === 0 && (
						<div className="px-3 py-2 text-xs text-muted-foreground">
							No milestones found for this project.
						</div>
					)}

					{milestones.map((milestone) => {
						const milestoneOpen = effectiveExpandedMilestones.includes(
							milestone.id,
						);
						const milestoneActive = activeScope?.milestoneId === milestone.id;
						const status = milestoneStatus.get(milestone.id) ?? "pending";

						return (
							<div key={milestone.id}>
								<button
									type="button"
									onClick={() => toggleMilestone(milestone.id)}
									className={cn(
										"flex w-full items-center gap-1.5 px-2 py-1.5 text-sm transition-colors hover:bg-accent/50",
										milestoneActive && "bg-accent/30",
									)}
								>
									{milestoneOpen ? (
										<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
									) : (
										<ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
									)}
									<StatusIcon status={status} />
									<span
										className={cn(
											"truncate",
											status === "pending" && "text-muted-foreground",
										)}
									>
										{milestone.id}: {milestone.title}
									</span>
								</button>

								{milestoneOpen && (
									<div className="ml-4">
										{milestone.slices.map((slice) => {
											const sliceKey = `${milestone.id}-${slice.id}`;
											const sliceOpen =
												effectiveExpandedSlices.includes(sliceKey);
											const sliceStatus = getSliceStatus(
												milestone.id,
												slice,
												activeScope ?? {},
											);
											const sliceActive =
												activeScope?.milestoneId === milestone.id &&
												activeScope.sliceId === slice.id;

											return (
												<div key={sliceKey}>
													<button
														type="button"
														onClick={() => toggleSlice(sliceKey)}
														className={cn(
															"flex w-full items-center gap-1.5 px-2 py-1.5 text-sm transition-colors hover:bg-accent/50",
															sliceActive && "bg-accent/20",
														)}
													>
														{sliceOpen ? (
															<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
														) : (
															<ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
														)}
														<StatusIcon status={sliceStatus} />
														<span
															className={cn(
																"truncate text-[13px]",
																sliceStatus === "pending" &&
																	"text-muted-foreground",
															)}
														>
															{slice.id}: {slice.title}
														</span>
													</button>

													{sliceOpen && (
														<div className="ml-5">
															{slice.branch && (
																<div className="px-2 py-0.5 text-[10px] uppercase tracking-wider text-muted-foreground">
																	{slice.branch}
																</div>
															)}
															{slice.tasks.map((task) => {
																const taskStatus = getTaskStatus(
																	milestone.id,
																	slice.id,
																	task,
																	activeScope ?? {},
																);
																const hasFile = !!(
																	task.planPath || task.summaryPath
																);
																return (
																	<button
																		key={`${sliceKey}-${task.id}`}
																		type="button"
																		onClick={() =>
																			openTaskFile(
																				task.summaryPath ?? task.planPath,
																			)
																		}
																		disabled={!hasFile}
																		className={cn(
																			"flex w-full items-center gap-1.5 px-2 py-1 text-xs transition-colors",
																			hasFile
																				? "cursor-pointer hover:bg-accent/50"
																				: "cursor-default opacity-70",
																			activeScope?.taskId === task.id &&
																				sliceActive &&
																				"bg-accent/10",
																		)}
																	>
																		<FileText className="h-4 w-4 shrink-0 text-muted-foreground" />
																		<StatusIcon status={taskStatus} />
																		<span
																			className={cn(
																				"truncate text-left",
																				taskStatus === "pending" &&
																					"text-muted-foreground",
																			)}
																		>
																			{task.id}: {task.title}
																		</span>
																	</button>
																);
															})}
														</div>
													)}
												</div>
											);
										})}
									</div>
								)}
							</div>
						);
					})}
				</div>
			)}

			{/* Sticky action footer */}
			{!isConnecting && (
				<div className="border-t border-border px-3 py-2.5">
					<div className="flex items-center justify-between gap-2 rounded-md border border-border bg-background px-3 py-2 text-xs">
						<div className="min-w-0">
							<div
								className="font-medium text-foreground"
								data-testid="sidebar-validation-count"
							>
								{validationCount} validation issue
								{validationCount === 1 ? "" : "s"}
							</div>
							<div className="truncate text-muted-foreground">
								{recoverySummary.label}
							</div>
						</div>
						<button
							type="button"
							onClick={handleOpenRecovery}
							className="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-border bg-card px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent"
							data-testid="sidebar-recovery-summary-entrypoint"
						>
							<LifeBuoy className="h-3.5 w-3.5" />
							Recovery
						</button>
					</div>
				</div>
			)}

			{!isConnecting && workflowAction.primary && (
				<div className="border-t border-border px-3 py-2.5">
					<div className="flex items-center gap-2">
						<button
							type="button"
							onClick={handlePrimaryAction}
							disabled={workflowAction.disabled}
							className={cn(
								"inline-flex h-9 flex-1 items-center justify-center gap-2 rounded-md px-3 text-sm font-medium transition-colors",
								workflowAction.primary.variant === "destructive"
									? "bg-destructive text-destructive-foreground hover:bg-destructive/90"
									: "bg-primary text-primary-foreground hover:bg-primary/90",
								workflowAction.disabled && "cursor-not-allowed opacity-50",
							)}
							title={workflowAction.disabledReason}
						>
							{workspace.commandInFlight ? (
								<Loader2 className="h-3.5 w-3.5 animate-spin" />
							) : workflowAction.isNewMilestone ? (
								<Milestone className="h-3.5 w-3.5" />
							) : (
								<Play className="h-3.5 w-3.5" />
							)}
							{workflowAction.primary.label}
						</button>
						{workflowAction.secondaries.map((action) => (
							<button
								type="button"
								key={action.command}
								onClick={() => handleCommand(action.command)}
								disabled={workflowAction.disabled}
								className={cn(
									"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-border bg-background transition-colors hover:bg-accent",
									workflowAction.disabled && "cursor-not-allowed opacity-50",
								)}
								title={action.label}
							>
								<SkipForward className="h-3.5 w-3.5" />
							</button>
						))}
					</div>
				</div>
			)}
		</div>
	);
}

/* ─── Collapsed Milestone Sidebar (icon-only rail) ─── */

export function CollapsedMilestoneSidebar({
	onExpand,
}: {
	onExpand: () => void;
}) {
	const workspace = useSFWorkspaceState();
	const { sendCommand } = useSFWorkspaceActions();

	const liveWorkspace = getLiveWorkspaceIndex(workspace);
	const milestones = liveWorkspace?.milestones ?? [];
	const auto = getLiveAutoDashboard(workspace);
	const bridge = workspace.boot?.bridge ?? null;

	const workflowAction = deriveWorkflowAction({
		phase: liveWorkspace?.active.phase ?? "pre-planning",
		autoActive: auto?.active ?? false,
		autoPaused: auto?.paused ?? false,
		onboardingLocked: workspace.boot?.onboarding.locked ?? false,
		commandInFlight: workspace.commandInFlight,
		bootStatus: workspace.bootStatus,
		hasMilestones: milestones.length > 0,
		projectDetectionKind: workspace.boot?.projectDetection?.kind ?? null,
	});

	const handleCommand = (command: string) => {
		executeWorkflowActionInPowerMode({
			dispatch: () => sendCommand(buildPromptCommand(command, bridge)),
		});
	};

	const handlePrimaryAction = () => {
		if (!workflowAction.primary) return;
		handleCommand(workflowAction.primary.command);
	};

	return (
		<div className="flex h-full w-10 flex-col items-center border-l border-border bg-sidebar py-3">
			<button
				type="button"
				onClick={onExpand}
				className="flex h-8 w-8 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
				title="Expand milestone sidebar"
			>
				<PanelRightOpen className="h-4 w-4" />
			</button>

			{workflowAction.primary && (
				<div className="mt-auto pb-0.5">
					<button
						type="button"
						onClick={handlePrimaryAction}
						disabled={workflowAction.disabled}
						className={cn(
							"flex h-8 w-8 items-center justify-center rounded-md transition-colors",
							workflowAction.primary.variant === "destructive"
								? "bg-destructive text-destructive-foreground hover:bg-destructive/90"
								: "bg-primary text-primary-foreground hover:bg-primary/90",
							workflowAction.disabled && "cursor-not-allowed opacity-50",
						)}
						title={
							workflowAction.disabledReason ?? workflowAction.primary.label
						}
					>
						{workspace.commandInFlight ? (
							<Loader2 className="h-4 w-4 animate-spin" />
						) : workflowAction.isNewMilestone ? (
							<Milestone className="h-4 w-4" />
						) : (
							<Play className="h-4 w-4" />
						)}
					</button>
				</div>
			)}
		</div>
	);
}

/* ─── Legacy Sidebar export (back-compat) ─── */

interface SidebarProps {
	activeView: string;
	onViewChange: (view: string) => void;
	isConnecting?: boolean;
	mobile?: boolean;
}

export function Sidebar({
	activeView,
	onViewChange,
	isConnecting = false,
	mobile = false,
}: SidebarProps) {
	if (mobile) {
		return (
			<MobileNavPanel
				activeView={activeView}
				onViewChange={onViewChange}
				isConnecting={isConnecting}
			/>
		);
	}
	return (
		<div className="flex h-full">
			<NavRail
				activeView={activeView}
				onViewChange={onViewChange}
				isConnecting={isConnecting}
			/>
		</div>
	);
}

/* ─── Mobile Nav Panel (full-width labels for touch) ─── */

function MobileNavPanel({
	activeView,
	onViewChange,
	isConnecting = false,
}: NavRailProps) {
	const { openCommandSurface } = useSFWorkspaceActions();
	const { theme, setTheme } = useTheme();

	const cycleTheme = () => {
		if (theme === "system") setTheme("light");
		else if (theme === "light") setTheme("dark");
		else setTheme("system");
	};

	const themeLabel =
		theme === "light" ? "Light" : theme === "dark" ? "Dark" : "System";
	const ThemeIcon = theme === "light" ? Sun : theme === "dark" ? Moon : Monitor;

	const navItems = [
		{ id: "dashboard", label: "Dashboard", icon: LayoutDashboard },
		{ id: "power", label: "Power Mode", icon: Columns2 },
		{ id: "chat", label: "Chat", icon: MessagesSquare },
		{ id: "roadmap", label: "Roadmap", icon: MapIcon },
		{ id: "files", label: "Files", icon: Folder },
		{ id: "activity", label: "Activity", icon: Activity },
		{ id: "visualize", label: "Visualize", icon: BarChart3 },
	];

	return (
		<div
			className="flex h-full flex-col bg-sidebar pt-14"
			data-testid="mobile-nav-panel"
		>
			<div className="flex-1 overflow-y-auto px-2 py-2">
				{navItems.map((item) => (
					<button
						type="button"
						key={item.id}
						onClick={() => onViewChange(item.id)}
						disabled={isConnecting}
						className={cn(
							"flex w-full items-center gap-3 rounded-md px-3 py-3 text-sm font-medium transition-colors min-h-[44px]",
							isConnecting
								? "cursor-not-allowed text-muted-foreground/50"
								: activeView === item.id
									? "bg-accent text-foreground"
									: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
						)}
					>
						<item.icon className="h-5 w-5 shrink-0" />
						{item.label}
					</button>
				))}
			</div>
			<div className="border-t border-border px-2 py-2 space-y-1">
				<button
					type="button"
					onClick={() =>
						window.dispatchEvent(new CustomEvent("sf:open-projects"))
					}
					disabled={isConnecting}
					className="flex w-full items-center gap-3 rounded-md px-3 py-3 text-sm text-muted-foreground hover:bg-accent/50 hover:text-foreground transition-colors min-h-[44px]"
				>
					<FolderKanban className="h-5 w-5 shrink-0" />
					Projects
				</button>
				<button
					type="button"
					onClick={() =>
						!isConnecting && openCommandSurface("git", { source: "sidebar" })
					}
					disabled={isConnecting}
					className="flex w-full items-center gap-3 rounded-md px-3 py-3 text-sm text-muted-foreground hover:bg-accent/50 hover:text-foreground transition-colors min-h-[44px]"
				>
					<GitBranch className="h-5 w-5 shrink-0" />
					Git
				</button>
				<button
					type="button"
					onClick={() =>
						!isConnecting &&
						openCommandSurface("settings", { source: "sidebar" })
					}
					disabled={isConnecting}
					className="flex w-full items-center gap-3 rounded-md px-3 py-3 text-sm text-muted-foreground hover:bg-accent/50 hover:text-foreground transition-colors min-h-[44px]"
				>
					<Settings className="h-5 w-5 shrink-0" />
					Settings
				</button>
				<button
					type="button"
					onClick={() => !isConnecting && cycleTheme()}
					disabled={isConnecting}
					className="flex w-full items-center gap-3 rounded-md px-3 py-3 text-sm text-muted-foreground hover:bg-accent/50 hover:text-foreground transition-colors min-h-[44px]"
				>
					<ThemeIcon className="h-5 w-5 shrink-0" />
					Theme: {themeLabel}
				</button>
			</div>
		</div>
	);
}
