/**
 * Agent Dashboard — Unified observability across all agent interfaces
 *
 * Passively tracks agent activity from team dispatches, subagent spawns,
 * and chain pipeline runs. Provides a compact always-visible widget plus
 * a full-screen overlay with four switchable views.
 *
 * Hooks into: dispatch_agent, subagent_create, subagent_continue, run_chain
 * tool calls and their completions. Completely passive — never blocks.
 *
 * Commands:
 *   /dashboard           — toggle full-screen overlay
 *   /dashboard clear     — reset all tracked state
 *
 * Usage: pi -e extensions/agent-dashboard.ts
 */

import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
import { DynamicBorder } from "@mariozechner/pi-coding-agent";
import { Container, matchesKey, Text, truncateToWidth } from "@mariozechner/pi-tui";
import { applyExtensionDefaults } from "./themeMap.ts";

// ── Data Types ─────────────────────────────────────────────────────────

type AgentInterface = "team" | "subagent" | "chain";

interface TrackedAgent {
	id: string;
	name: string;
	iface: AgentInterface;
	status: "running" | "done" | "error";
	task: string;
	startedAt: number;
	endedAt?: number;
	elapsed: number;
	toolCount: number;
	lastText: string;
	turnCount: number;
	chainStep?: number;
	chainName?: string;
	teamName?: string;
}

interface AgentRun {
	id: string;
	name: string;
	iface: AgentInterface;
	task: string;
	status: "done" | "error";
	startedAt: number;
	endedAt: number;
	duration: number;
	toolCount: number;
	resultPreview: string;
	chainStep?: number;
	chainName?: string;
	teamName?: string;
}

interface DashboardStats {
	totalRuns: number;
	totalSuccess: number;
	totalError: number;
	totalDuration: number;
	agentRunCounts: Record<string, number>;
	ifaceCounts: Record<AgentInterface, number>;
}

// ── Helpers ────────────────────────────────────────────────────────────

function fmtDuration(ms: number): string {
	if (ms < 1000) return `${ms}ms`;
	const secs = Math.floor(ms / 1000);
	if (secs < 60) return `${secs}s`;
	const mins = Math.floor(secs / 60);
	const remSecs = secs % 60;
	if (mins < 60) return `${mins}m ${remSecs}s`;
	const hrs = Math.floor(mins / 60);
	const remMins = mins % 60;
	return `${hrs}h ${remMins}m`;
}

function shortId(): string {
	return Math.random().toString(36).slice(2, 6);
}

function truncate(s: string, max: number): string {
	return s.length > max ? s.slice(0, max - 1) + "…" : s;
}

function emptyStats(): DashboardStats {
	return {
		totalRuns: 0,
		totalSuccess: 0,
		totalError: 0,
		totalDuration: 0,
		agentRunCounts: {},
		ifaceCounts: { team: 0, subagent: 0, chain: 0 },
	};
}

// ── Extension ──────────────────────────────────────────────────────────

export default function (pi: ExtensionAPI) {
	// ── State ──────────────────────────────────────────────────────────

	const activeAgents: Map<string, TrackedAgent> = new Map();
	let history: AgentRun[] = [];
	let stats: DashboardStats = emptyStats();
	let widgetCtx: ExtensionContext | null = null;
	let tickTimer: ReturnType<typeof setInterval> | null = null;

	// Mapping from toolCallId → tracked agent info (with timestamp for staleness)
	const pendingCalls: Map<string, { agentId: string; ts: number }> = new Map();

	// Staleness threshold: 10 minutes
	const STALE_TIMEOUT_MS = 10 * 60 * 1000;

	// Inactivity auto-stop: stop tick after 30s with no active agents
	let lastActivityTs = Date.now();

	// ── Tracked tool names ─────────────────────────────────────────────

	const TRACKED_TOOLS = new Set([
		"dispatch_agent",
		"subagent_create",
		"subagent_continue",
		"run_chain",
	]);

	// ── State Management ───────────────────────────────────────────────

	function clearState() {
		activeAgents.clear();
		history = [];
		stats = emptyStats();
		pendingCalls.clear();
		lastActivityTs = Date.now();
	}

	function addToHistory(agent: TrackedAgent) {
		const run: AgentRun = {
			id: agent.id,
			name: agent.name,
			iface: agent.iface,
			task: agent.task,
			status: agent.status === "error" ? "error" : "done",
			startedAt: agent.startedAt,
			endedAt: agent.endedAt || Date.now(),
			duration: agent.elapsed,
			toolCount: agent.toolCount,
			resultPreview: truncate(agent.lastText, 200),
			chainStep: agent.chainStep,
			chainName: agent.chainName,
			teamName: agent.teamName,
		};

		history.push(run);
		// Ring buffer capped at 200
		if (history.length > 200) {
			history = history.slice(-200);
		}

		// Update stats
		stats.totalRuns++;
		if (run.status === "done") stats.totalSuccess++;
		else stats.totalError++;
		stats.totalDuration += run.duration;
		stats.agentRunCounts[run.name] = (stats.agentRunCounts[run.name] || 0) + 1;
		stats.ifaceCounts[run.iface] = (stats.ifaceCounts[run.iface] || 0) + 1;
	}

	// ── Tick Timer ─────────────────────────────────────────────────────

	function startTick() {
		if (tickTimer) return;
		tickTimer = setInterval(() => {
			const now = Date.now();

			// Update elapsed on running agents
			for (const agent of activeAgents.values()) {
				if (agent.status === "running") {
					agent.elapsed = now - agent.startedAt;
				}
			}

			// Staleness check: expire pending calls older than 10 minutes
			for (const [callId, pending] of pendingCalls) {
				if (now - pending.ts > STALE_TIMEOUT_MS) {
					pendingCalls.delete(callId);
					const agent = activeAgents.get(pending.agentId);
					if (agent && agent.status === "running") {
						agent.status = "error";
						agent.endedAt = now;
						agent.elapsed = now - agent.startedAt;
						agent.lastText = "Timed out (no completion after 10m)";
						addToHistory(agent);
						activeAgents.delete(pending.agentId);
					}
				}
			}

			// Auto-stop tick after 30s of inactivity (no active agents, no pending calls)
			if (activeAgents.size === 0 && pendingCalls.size === 0) {
				if (now - lastActivityTs > 30_000) {
					stopTick();
					return;
				}
			} else {
				lastActivityTs = now;
			}

			updateWidget();
		}, 1000);
	}

	function stopTick() {
		if (tickTimer) {
			clearInterval(tickTimer);
			tickTimer = null;
		}
	}

	// ── Widget Rendering ───────────────────────────────────────────────

	function updateWidget() {
		if (!widgetCtx) return;

		try {
			widgetCtx.ui.setWidget("agent-dashboard", (_tui, theme) => {
				const container = new Container();
				const borderFn = (s: string) => theme.fg("accent", s);

				container.addChild(new DynamicBorder(borderFn));

				const headerText = new Text("", 1, 0);
				container.addChild(headerText);

				const agentLines: Text[] = [];
				// Pre-allocate up to 4 lines for active agents
				for (let i = 0; i < 4; i++) {
					const t = new Text("", 1, 0);
					agentLines.push(t);
					container.addChild(t);
				}

				const hintText = new Text("", 1, 0);
				container.addChild(hintText);

				container.addChild(new DynamicBorder(borderFn));

				return {
					render(width: number): string[] {
						const activeCount = activeAgents.size;
						const doneCount = stats.totalSuccess;
						const errorCount = stats.totalError;

						// Line 1: summary bar
						const line1 =
							theme.fg("accent", " 📊 Dashboard") +
							theme.fg("dim", " │ Active: ") + theme.fg(activeCount > 0 ? "accent" : "muted", `${activeCount}`) +
							theme.fg("dim", " │ Done: ") + theme.fg("success", `${doneCount}`) +
							theme.fg("dim", " │ Errors: ") + theme.fg(errorCount > 0 ? "error" : "muted", `${errorCount}`);
						headerText.setText(truncateToWidth(line1, width - 4));

						// Active agent lines
						const agents = Array.from(activeAgents.values());
						for (let i = 0; i < agentLines.length; i++) {
							if (i < agents.length) {
								const a = agents[i];
								const icon = a.status === "running" ? "⟳"
									: a.status === "done" ? "✓" : "✗";
								const statusColor = a.status === "running" ? "accent"
									: a.status === "done" ? "success" : "error";
								const ifaceTag = theme.fg("dim", `[${a.iface}]`);
								const elapsed = theme.fg("muted", fmtDuration(a.elapsed));
								const tools = theme.fg("dim", `🔧${a.toolCount}`);
								const lastText = a.lastText
									? theme.fg("muted", truncate(a.lastText, Math.max(20, width - 60)))
									: "";

								const line =
									" " + theme.fg(statusColor, icon) + " " +
									theme.fg("accent", truncate(a.name, 16)) + " " +
									ifaceTag + " " +
									elapsed + " " +
									tools +
									(lastText ? theme.fg("dim", " │ ") + lastText : "");
								agentLines[i].setText(truncateToWidth(line, width - 4));
							} else {
								agentLines[i].setText("");
							}
						}

						// Hint line
						const hintLine =
							theme.fg("dim", " /dashboard") + theme.fg("muted", " — full view") +
							theme.fg("dim", " │ ") +
							theme.fg("muted", `${stats.totalRuns} total runs`) +
							(stats.totalDuration > 0
								? theme.fg("dim", " │ avg ") + theme.fg("muted", fmtDuration(Math.round(stats.totalDuration / Math.max(1, stats.totalRuns))))
								: "");
						hintText.setText(truncateToWidth(hintLine, width - 4));

						return container.render(width);
					},
					invalidate() {
						container.invalidate();
					},
				};
			});
		} catch {}
	}

	// ── Overlay ────────────────────────────────────────────────────────

	async function openOverlay(ctx: ExtensionContext) {
		if (!ctx.hasUI) return;

		let currentView = 0; // 0=Live, 1=History, 2=Interfaces, 3=Stats
		let scrollOffset = 0;

		const viewNames = ["1:Live", "2:History", "3:Interfaces", "4:Stats"];

		await ctx.ui.custom((_tui, theme, _kb, done) => {
			return {
				render(width: number): string[] {
					const lines: string[] = [];

					// ── Header ──
					lines.push("");
					const tabs = viewNames.map((name, i) =>
						i === currentView
							? theme.fg("accent", theme.bold(`[${name}]`))
							: theme.fg("dim", `[${name}]`)
					).join(" ");
					lines.push(truncateToWidth(
						" " + theme.fg("accent", theme.bold("📊 Agent Dashboard")) +
						" ".repeat(Math.max(1, width - 20 - viewNames.join(" ").length - 2)) +
						tabs,
						width,
					));
					lines.push(theme.fg("dim", "─".repeat(width)));

					// ── View content ──
					const contentLines = renderView(currentView, width, theme, scrollOffset);
					lines.push(...contentLines);

					// ── Footer controls ──
					lines.push("");
					lines.push(theme.fg("dim", "─".repeat(width)));
					lines.push(truncateToWidth(
						" " + theme.fg("dim", "1-4/Tab: views │ j/k: scroll │ c: clear │ q/Esc: close"),
						width,
					));
					lines.push("");

					return lines;
				},
				handleInput(data: string) {
					if (matchesKey(data, "escape") || data === "q") {
						done(undefined);
						return;
					}
					if (data === "1") { currentView = 0; scrollOffset = 0; }
					else if (data === "2") { currentView = 1; scrollOffset = 0; }
					else if (data === "3") { currentView = 2; scrollOffset = 0; }
					else if (data === "4") { currentView = 3; scrollOffset = 0; }
					else if (data === "\t") { currentView = (currentView + 1) % 4; scrollOffset = 0; }
					else if (matchesKey(data, "up") || data === "k") { scrollOffset = Math.max(0, scrollOffset - 1); }
					else if (matchesKey(data, "down") || data === "j") { scrollOffset++; }
					else if (matchesKey(data, "pageUp")) { scrollOffset = Math.max(0, scrollOffset - 20); }
					else if (matchesKey(data, "pageDown")) { scrollOffset += 20; }
					else if (data === "c") {
						clearState();
						scrollOffset = 0;
					}
					_tui.requestRender();
				},
				invalidate() {},
			};
		}, {
			overlay: true,
			overlayOptions: { width: "90%", anchor: "center" },
		});
	}

	// ── View Renderers ─────────────────────────────────────────────────

	function renderView(view: number, width: number, theme: any, offset: number): string[] {
		switch (view) {
			case 0: return renderLiveView(width, theme, offset);
			case 1: return renderHistoryView(width, theme, offset);
			case 2: return renderInterfacesView(width, theme, offset);
			case 3: return renderStatsView(width, theme, offset);
			default: return [];
		}
	}

	// ── View 1: Live ───────────────────────────────────────────────────

	function renderLiveView(width: number, theme: any, offset: number): string[] {
		const lines: string[] = [];
		const agents = Array.from(activeAgents.values());

		lines.push(truncateToWidth(
			"  " + theme.fg("accent", theme.bold("Active Agents")) +
			theme.fg("dim", ` (${agents.length} running)`),
			width,
		));
		lines.push("");

		if (agents.length === 0) {
			lines.push(truncateToWidth(
				"  " + theme.fg("dim", "No agents currently running. Activity will appear here when"),
				width,
			));
			lines.push(truncateToWidth(
				"  " + theme.fg("dim", "dispatch_agent, subagent_create, subagent_continue, or run_chain is called."),
				width,
			));
			lines.push("");

			// Show recent completions as context
			if (history.length > 0) {
				lines.push(truncateToWidth(
					"  " + theme.fg("muted", `Last completed: ${history.length} agents`),
					width,
				));
				const recent = history.slice(-3).reverse();
				for (const run of recent) {
					const icon = run.status === "done" ? "✓" : "✗";
					const color = run.status === "done" ? "success" : "error";
					lines.push(truncateToWidth(
						"  " + theme.fg(color, `${icon} ${run.name}`) +
						theme.fg("dim", ` [${run.iface}] `) +
						theme.fg("muted", fmtDuration(run.duration)) +
						theme.fg("dim", " — ") +
						theme.fg("muted", truncate(run.task, 50)),
						width,
					));
				}
			}
			return lines;
		}

		const allLines: string[] = [];
		for (const agent of agents) {
			const icon = agent.status === "running" ? "●"
				: agent.status === "done" ? "✓" : "✗";
			const statusColor = agent.status === "running" ? "accent"
				: agent.status === "done" ? "success" : "error";

			// Card top
			allLines.push(truncateToWidth(
				"  " + theme.fg("dim", "┌─ ") +
				theme.fg(statusColor, `${icon} ${agent.name}`) +
				theme.fg("dim", ` [${agent.iface}]`) +
				(agent.chainName ? theme.fg("dim", ` chain:${agent.chainName}`) : "") +
				(agent.teamName ? theme.fg("dim", ` team:${agent.teamName}`) : "") +
				(agent.chainStep !== undefined ? theme.fg("dim", ` step:${agent.chainStep}`) : "") +
				theme.fg("dim", " ─".repeat(Math.max(0, Math.floor((width - 50) / 2)))),
				width,
			));

			// Task
			allLines.push(truncateToWidth(
				"  " + theme.fg("dim", "│ ") +
				theme.fg("muted", "Task: ") +
				theme.fg("accent", truncate(agent.task, width - 20)),
				width,
			));

			// Metrics
			allLines.push(truncateToWidth(
				"  " + theme.fg("dim", "│ ") +
				theme.fg("muted", "Elapsed: ") + theme.fg("success", fmtDuration(agent.elapsed)) +
				theme.fg("dim", " │ ") +
				theme.fg("muted", "Tools: ") + theme.fg("accent", `${agent.toolCount}`) +
				theme.fg("dim", " │ ") +
				theme.fg("muted", "Turns: ") + theme.fg("accent", `${agent.turnCount}`),
				width,
			));

			// Streaming text
			if (agent.lastText) {
				allLines.push(truncateToWidth(
					"  " + theme.fg("dim", "│ ") +
					theme.fg("muted", truncate(agent.lastText, width - 10)),
					width,
				));
			}

			// Card bottom
			allLines.push(truncateToWidth(
				"  " + theme.fg("dim", "└" + "─".repeat(Math.max(0, width - 5))),
				width,
			));
			allLines.push("");
		}

		const visible = allLines.slice(offset);
		lines.push(...visible);

		return lines;
	}

	// ── View 2: History ────────────────────────────────────────────────

	function renderHistoryView(width: number, theme: any, offset: number): string[] {
		const lines: string[] = [];

		lines.push(truncateToWidth(
			"  " + theme.fg("accent", theme.bold("Completed Runs")) +
			theme.fg("dim", ` (${history.length} total)`),
			width,
		));
		lines.push("");

		if (history.length === 0) {
			lines.push(truncateToWidth("  " + theme.fg("dim", "No completed runs yet."), width));
			return lines;
		}

		// Table header
		const hdr =
			theme.fg("accent", "  Status") +
			theme.fg("accent", " │ Name          ") +
			theme.fg("accent", " │ Interface ") +
			theme.fg("accent", " │ Duration ") +
			theme.fg("accent", " │ Tools ") +
			theme.fg("accent", " │ Task");
		lines.push(truncateToWidth(hdr, width));
		lines.push(truncateToWidth("  " + theme.fg("dim", "─".repeat(Math.min(80, width - 4))), width));

		// Show newest first
		const rows: string[] = [];
		const reversed = [...history].reverse();
		for (const run of reversed) {
			const icon = run.status === "done" ? "✓" : "✗";
			const color = run.status === "done" ? "success" : "error";
			const ifaceLabel = run.iface.padEnd(9);
			const nameLabel = truncate(run.name, 14).padEnd(14);
			const durLabel = fmtDuration(run.duration).padEnd(8);
			const toolLabel = String(run.toolCount).padStart(5);
			const taskPreview = truncate(run.task, Math.max(10, width - 70));

			const row =
				"  " + theme.fg(color, `  ${icon}   `) +
				theme.fg("dim", " │ ") + theme.fg("accent", nameLabel) +
				theme.fg("dim", " │ ") + theme.fg("muted", ifaceLabel) +
				theme.fg("dim", " │ ") + theme.fg("success", durLabel) +
				theme.fg("dim", " │ ") + theme.fg("accent", toolLabel) +
				theme.fg("dim", " │ ") + theme.fg("muted", taskPreview);
			rows.push(row);
		}

		const visible = rows.slice(offset);
		for (const row of visible) {
			lines.push(truncateToWidth(row, width));
		}

		return lines;
	}

	// ── View 3: Interfaces ─────────────────────────────────────────────

	function renderInterfacesView(width: number, theme: any, offset: number): string[] {
		const lines: string[] = [];

		lines.push(truncateToWidth(
			"  " + theme.fg("accent", theme.bold("Agents by Interface")),
			width,
		));
		lines.push("");

		const ifaceLabels: Record<AgentInterface, string> = {
			team: "🏢 Team (dispatch_agent)",
			subagent: "🤖 Subagent (subagent_create/continue)",
			chain: "🔗 Chain (run_chain)",
		};

		const allLines: string[] = [];

		for (const iface of ["team", "subagent", "chain"] as AgentInterface[]) {
			const activeForIface = Array.from(activeAgents.values()).filter(a => a.iface === iface);
			const historyForIface = history.filter(r => r.iface === iface);
			const totalCount = stats.ifaceCounts[iface] || 0;

			allLines.push(truncateToWidth(
				"  " + theme.fg("accent", theme.bold(ifaceLabels[iface])) +
				theme.fg("dim", ` — ${activeForIface.length} active, ${totalCount} completed`),
				width,
			));
			allLines.push(truncateToWidth("  " + theme.fg("dim", "─".repeat(Math.min(60, width - 6))), width));

			// Active
			if (activeForIface.length > 0) {
				for (const agent of activeForIface) {
					allLines.push(truncateToWidth(
						"    " + theme.fg("accent", "● ") +
						theme.fg("accent", agent.name) +
						theme.fg("dim", " — ") +
						theme.fg("success", fmtDuration(agent.elapsed)) +
						theme.fg("dim", " │ 🔧") + theme.fg("muted", `${agent.toolCount}`) +
						theme.fg("dim", " │ ") +
						theme.fg("muted", truncate(agent.task, 40)),
						width,
					));
				}
			}

			// Recent completed (last 5)
			const recent = historyForIface.slice(-5).reverse();
			if (recent.length > 0) {
				for (const run of recent) {
					const icon = run.status === "done" ? "✓" : "✗";
					const color = run.status === "done" ? "success" : "error";
					allLines.push(truncateToWidth(
						"    " + theme.fg(color, `${icon} `) +
						theme.fg("muted", run.name) +
						theme.fg("dim", " — ") +
						theme.fg("muted", fmtDuration(run.duration)) +
						theme.fg("dim", " │ ") +
						theme.fg("muted", truncate(run.task, 40)),
						width,
					));
				}
			}

			if (activeForIface.length === 0 && recent.length === 0) {
				allLines.push(truncateToWidth("    " + theme.fg("dim", "No activity recorded."), width));
			}

			allLines.push("");
		}

		const visible = allLines.slice(offset);
		lines.push(...visible);

		return lines;
	}

	// ── View 4: Stats ──────────────────────────────────────────────────

	function renderStatsView(width: number, theme: any, offset: number): string[] {
		const lines: string[] = [];

		lines.push(truncateToWidth(
			"  " + theme.fg("accent", theme.bold("Aggregate Statistics")),
			width,
		));
		lines.push("");

		const avgDur = stats.totalRuns > 0
			? fmtDuration(Math.round(stats.totalDuration / stats.totalRuns))
			: "—";
		const successRate = stats.totalRuns > 0
			? `${Math.round((stats.totalSuccess / stats.totalRuns) * 100)}%`
			: "—";

		const allLines: string[] = [];

		// Summary cards
		allLines.push(truncateToWidth(
			"  " +
			theme.fg("muted", "Total Runs: ") + theme.fg("accent", `${stats.totalRuns}`) +
			theme.fg("dim", " │ ") +
			theme.fg("muted", "Success: ") + theme.fg("success", `${stats.totalSuccess}`) +
			theme.fg("dim", " │ ") +
			theme.fg("muted", "Errors: ") + theme.fg(stats.totalError > 0 ? "error" : "muted", `${stats.totalError}`) +
			theme.fg("dim", " │ ") +
			theme.fg("muted", "Success Rate: ") + theme.fg("success", successRate),
			width,
		));
		allLines.push(truncateToWidth(
			"  " +
			theme.fg("muted", "Total Duration: ") + theme.fg("success", fmtDuration(stats.totalDuration)) +
			theme.fg("dim", " │ ") +
			theme.fg("muted", "Avg Duration: ") + theme.fg("accent", avgDur),
			width,
		));
		allLines.push("");

		// Interface breakdown
		allLines.push(truncateToWidth(
			"  " + theme.fg("accent", theme.bold("Interface Breakdown")),
			width,
		));
		allLines.push("");

		const ifaceTotal = Math.max(1, stats.ifaceCounts.team + stats.ifaceCounts.subagent + stats.ifaceCounts.chain);
		const barWidth = Math.min(30, Math.floor(width * 0.3));

		for (const [iface, label] of [["team", "Team     "], ["subagent", "Subagent "], ["chain", "Chain    "]] as [AgentInterface, string][]) {
			const count = stats.ifaceCounts[iface] || 0;
			const ratio = count / ifaceTotal;
			const filled = Math.round(ratio * barWidth);
			const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);

			allLines.push(truncateToWidth(
				"  " +
				theme.fg("accent", label) + " " +
				theme.fg("success", bar) + " " +
				theme.fg("muted", `${count}`) +
				theme.fg("dim", ` (${Math.round(ratio * 100)}%)`),
				width,
			));
		}
		allLines.push("");

		// Most-used agents bar chart
		allLines.push(truncateToWidth(
			"  " + theme.fg("accent", theme.bold("Most-Used Agents")),
			width,
		));
		allLines.push("");

		const agentEntries = Object.entries(stats.agentRunCounts).sort((a, b) => b[1] - a[1]);

		if (agentEntries.length === 0) {
			allLines.push(truncateToWidth("  " + theme.fg("dim", "No agent runs recorded yet."), width));
		} else {
			const maxCount = agentEntries[0][1];
			for (const [name, count] of agentEntries.slice(0, 15)) {
				const ratio = maxCount > 0 ? count / maxCount : 0;
				const filled = Math.round(ratio * barWidth);
				const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);

				allLines.push(truncateToWidth(
					"  " +
					theme.fg("accent", name.padEnd(16)) + " " +
					theme.fg("success", bar) + " " +
					theme.fg("muted", `${count}`),
					width,
				));
			}
		}
		allLines.push("");

		// Per-agent average durations
		if (history.length > 0) {
			allLines.push(truncateToWidth(
				"  " + theme.fg("accent", theme.bold("Average Duration by Agent")),
				width,
			));
			allLines.push("");

			const durByAgent: Record<string, number[]> = {};
			for (const run of history) {
				if (!durByAgent[run.name]) durByAgent[run.name] = [];
				durByAgent[run.name].push(run.duration);
			}

			const durEntries = Object.entries(durByAgent).sort((a, b) => {
				const avgA = a[1].reduce((s, v) => s + v, 0) / a[1].length;
				const avgB = b[1].reduce((s, v) => s + v, 0) / b[1].length;
				return avgB - avgA;
			});

			for (const [name, durations] of durEntries) {
				const avg = durations.reduce((s, v) => s + v, 0) / durations.length;
				const min = Math.min(...durations);
				const max = Math.max(...durations);

				allLines.push(truncateToWidth(
					"  " +
					theme.fg("accent", name.padEnd(16)) +
					theme.fg("dim", " avg: ") + theme.fg("success", fmtDuration(Math.round(avg)).padEnd(8)) +
					theme.fg("dim", " min: ") + theme.fg("muted", fmtDuration(min).padEnd(8)) +
					theme.fg("dim", " max: ") + theme.fg("muted", fmtDuration(max).padEnd(8)) +
					theme.fg("dim", " runs: ") + theme.fg("muted", `${durations.length}`),
					width,
				));
			}
		}

		const visible = allLines.slice(offset);
		lines.push(...visible);

		return lines;
	}

	// ── Commands ───────────────────────────────────────────────────────

	pi.registerCommand("dashboard", {
		description: "Open Agent Dashboard overlay. Args: clear",
		handler: async (args, ctx) => {
			widgetCtx = ctx;
			const arg = (args || "").trim().toLowerCase();

			if (arg === "clear") {
				stopTick();
				clearState();
				startTick();
				ctx.ui.notify("📊 Dashboard: All data cleared.", "info");
				updateWidget();
				return;
			}

			await openOverlay(ctx);
		},
	});

	// ── Event Handlers ─────────────────────────────────────────────────

	pi.on("session_start", async (_event, ctx) => {
		applyExtensionDefaults(import.meta.url, ctx);
		stopTick();
		widgetCtx = ctx;
		clearState();
		startTick();
		updateWidget();
	});

	pi.on("before_agent_start", async (_event, ctx) => {
		widgetCtx = ctx;
		return undefined;
	});

	pi.on("agent_end", async (_event, ctx) => {
		widgetCtx = ctx;
		updateWidget();
	});

	pi.on("tool_call", async (event, _ctx) => {
		try {
			const toolName = event.toolName;
			if (!TRACKED_TOOLS.has(toolName)) return undefined;

			const input = event.input as Record<string, unknown>;
			const now = Date.now();
			const callId = event.toolCallId;
			lastActivityTs = now;

			if (toolName === "dispatch_agent") {
				const agentName = (input.agent as string) || "unknown";
				const task = (input.task as string) || "";
				const id = `team:${agentName}:${shortId()}`;

				const tracked: TrackedAgent = {
					id,
					name: agentName,
					iface: "team",
					status: "running",
					task,
					startedAt: now,
					elapsed: 0,
					toolCount: 0,
					lastText: "",
					turnCount: 1,
					teamName: agentName,
				};

				activeAgents.set(id, tracked);
				pendingCalls.set(callId, { agentId: id, ts: now });

			} else if (toolName === "subagent_create") {
				const task = (input.task as string) || "";
				const id = `sub:create:${shortId()}`;

				const tracked: TrackedAgent = {
					id,
					name: "Subagent",
					iface: "subagent",
					status: "running",
					task,
					startedAt: now,
					elapsed: 0,
					toolCount: 0,
					lastText: "",
					turnCount: 1,
				};

				activeAgents.set(id, tracked);
				pendingCalls.set(callId, { agentId: id, ts: now });

			} else if (toolName === "subagent_continue") {
				// Always create a new tracking entry using the widget's ID from input
				const subId = input.id;
				const prompt = (input.prompt as string) || "";
				const id = `sub:cont:${subId}:${shortId()}`;

				const tracked: TrackedAgent = {
					id,
					name: `Subagent #${subId}`,
					iface: "subagent",
					status: "running",
					task: prompt,
					startedAt: now,
					elapsed: 0,
					toolCount: 0,
					lastText: "",
					turnCount: 1,
				};

				activeAgents.set(id, tracked);
				pendingCalls.set(callId, { agentId: id, ts: now });

			} else if (toolName === "run_chain") {
				const task = (input.task as string) || "";
				const id = `chain:${shortId()}`;

				const tracked: TrackedAgent = {
					id,
					name: "chain",
					iface: "chain",
					status: "running",
					task,
					startedAt: now,
					elapsed: 0,
					toolCount: 0,
					lastText: "",
					turnCount: 1,
					chainName: "pipeline",
				};

				activeAgents.set(id, tracked);
				pendingCalls.set(callId, { agentId: id, ts: now });
			}

			// Ensure tick is running when we have active agents
			startTick();
			updateWidget();
		} catch {}

		return undefined;
	});

	pi.on("tool_execution_end", async (event) => {
		try {
			const toolName = event.toolName;
			if (!TRACKED_TOOLS.has(toolName)) return;

			const now = Date.now();
			const callId = event.toolCallId;
			lastActivityTs = now;

			const pending = pendingCalls.get(callId);
			if (pending) {
				pendingCalls.delete(callId);

				const agent = activeAgents.get(pending.agentId);
				if (agent) {
					agent.status = event.isError ? "error" : "done";
					agent.endedAt = now;
					agent.elapsed = now - agent.startedAt;

					// Extract result preview if available
					try {
						const result = event.result;
						if (result?.content) {
							for (const block of result.content) {
								if (block.type === "text" && block.text) {
									agent.lastText = block.text.slice(0, 200);
									break;
								}
							}
						}
					} catch {}

					// Move to history
					addToHistory(agent);
					activeAgents.delete(pending.agentId);
				}
			}

			updateWidget();
		} catch {}
	});
}
