import type { Plugin } from "@opencode-ai/plugin"
import { spawn } from "bun"

/**
 * tmux-panes plugin
 *
 * When opencode spawns a background subagent, this plugin automatically opens
 * a new tmux pane showing that subagent's live TUI via `opencode attach`.
 *
 * Layout:
 *   - First subagent: horizontal 60/40 split — main pane on left, subagent on right
 *   - Additional subagents: stacked vertically in the right column
 *   - Panes close automatically when subagent sessions end
 *
 * Only activates when running inside a tmux session (TMUX env var is set).
 */

const isInsideTmux = () => Boolean(process.env.TMUX)
const getCurrentPaneId = () => process.env.TMUX_PANE

const runTmux = async (args: string[]) => {
	const proc = spawn(["tmux", ...args], { stdout: "pipe", stderr: "pipe" })
	const stdout = await new Response(proc.stdout).text()
	const stderr = await new Response(proc.stderr).text()
	const exitCode = await proc.exited

	return {
		exitCode,
		stdout: stdout.trim(),
		stderr: stderr.trim(),
	}
}

const removeItem = (items: string[], value: string) => {
	const idx = items.indexOf(value)
	if (idx !== -1) items.splice(idx, 1)
}

const plugin: Plugin = async (ctx) => {
	if (!isInsideTmux()) return {}

	const sessions = new Map<string, string>() // sessionId → tmux paneId
	const sourcePaneId = getCurrentPaneId()
	const serverUrl = (ctx.serverUrl?.toString() ?? "").replace(/\/$/, "")

	// Ordered list of pane IDs in the right column.
	// Empty = no right column yet; length > 0 = right column exists.
	const rightColumnPanes: string[] = []
	let paneOps = Promise.resolve()

	const getWindowInfo = async () => {
		const targetPane = sourcePaneId ?? rightColumnPanes[0]
		if (!targetPane) return null

		const result = await runTmux([
			"display-message",
			"-p",
			"-t",
			targetPane,
			"#{window_id} #{window_width}",
		])

		if (result.exitCode !== 0 || !result.stdout) return null

		const [windowId, widthText] = result.stdout.split(/\s+/, 2)
		const width = Number(widthText)
		if (!windowId || Number.isNaN(width)) return null

		return { windowId, width }
	}

	const applyLayout = async () => {
		if (rightColumnPanes.length === 0) return

		const windowInfo = await getWindowInfo()
		if (!windowInfo) return

		const mainWidth = Math.max(1, Math.round(windowInfo.width * 0.6))

		await runTmux([
			"set-window-option",
			"-t",
			windowInfo.windowId,
			"main-pane-width",
			String(mainWidth),
		])
		await runTmux(["select-layout", "-t", sourcePaneId ?? rightColumnPanes[0], "main-vertical"])
	}

	const closeSessionPane = async (sessionId: string) => {
		const paneId = sessions.get(sessionId)
		if (!paneId) return

		await runTmux(["kill-pane", "-t", paneId])
		sessions.delete(sessionId)
		removeItem(rightColumnPanes, paneId)
		await applyLayout()
	}

	const enqueuePaneOp = (operation: () => Promise<void>) => {
		paneOps = paneOps.then(operation).catch(() => {})
		return paneOps
	}

	const isTerminalSessionUpdate = (info: any) =>
		Boolean(info?.time?.archived || info?.time?.compacting)

	return {
		event: async ({ event }) => {
			// Spawn a new pane when a subagent session is created
			if (event.type === "session.created") {
				const info = (event as any).properties?.info
				// parentID presence distinguishes subagents from the root session
				if (!info?.id || !info?.parentID) return
				const sessionId: string = info.id
				if (sessions.has(sessionId)) return

				await enqueuePaneOp(async () => {
					if (sessions.has(sessionId)) return

					const cmd = `opencode attach ${serverUrl} --session ${sessionId}`
					let args: string[]

					if (rightColumnPanes.length === 0) {
						const windowInfo = await getWindowInfo()
						const rightWidth = windowInfo
							? Math.max(1, Math.round(windowInfo.width * 0.4))
							: 40

						args = [
							"split-window",
							"-h",
							"-l",
							String(rightWidth),
							"-d",
							"-P",
							"-F",
							"#{pane_id}",
							...(sourcePaneId ? ["-t", sourcePaneId] : []),
							cmd,
						]
					} else {
						const lastRightPane = rightColumnPanes[rightColumnPanes.length - 1]
						args = [
							"split-window",
							"-v",
							"-d",
							"-P",
							"-F",
							"#{pane_id}",
							"-t",
							lastRightPane,
							cmd,
						]
					}

					const result = await runTmux(args)
					const paneId = result.stdout

					if (result.exitCode === 0 && paneId) {
						sessions.set(sessionId, paneId)
						rightColumnPanes.push(paneId)
						await applyLayout()
					}
				})
			}

			// Kill the pane when the subagent session ends
			if (event.type === "session.deleted") {
				const info = (event as any).properties?.info
				if (!info?.id) return
				await enqueuePaneOp(() => closeSessionPane(info.id))
			}

			if (event.type === "session.updated") {
				const info = (event as any).properties?.info
				if (!info?.id || !sessions.has(info.id) || !isTerminalSessionUpdate(info)) return
				await enqueuePaneOp(() => closeSessionPane(info.id))
			}

			if (event.type === "session.status") {
				const sessionID = (event as any).properties?.sessionID
				const statusType = (event as any).properties?.status?.type
				if (!sessionID || !sessions.has(sessionID) || statusType !== "idle") return
				await enqueuePaneOp(() => closeSessionPane(sessionID))
			}
		},
	}
}

export default plugin
