import type { Extension, HostAPI, Manifest } from "@dispatch/kernel";
import { cacheWarmHandle, turnSettled, turnStarted } from "@dispatch/session-orchestrator";
import type { SurfaceContext, SurfaceProvider } from "@dispatch/surface-registry";
import { surfaceRegistryHandle } from "@dispatch/surface-registry";
import type { SurfaceSpec } from "@dispatch/ui-contract";
import {
	buildConversationSpec,
	buildDefaultSpec,
	parseIntervalPayload,
	secondsToMs,
} from "./pure.js";
import { createCacheWarmer } from "./warmer.js";

export const manifest: Manifest = {
	id: "cache-warming",
	name: "Cache Warming",
	version: "0.0.0",
	apiVersion: "^0.1.0",
	trust: "bundled",
	activation: "eager",
	dependsOn: ["session-orchestrator", "surface-registry"],
	capabilities: {},
	contributes: {
		services: ["cache-warming/surface"],
	},
};

export function activate(host: HostAPI): void {
	const warmService = host.getService(cacheWarmHandle);
	const registry = host.getService(surfaceRegistryHandle);
	const storage = host.storage("cache-warming");

	const subscribers = new Set<() => void>();

	const timeoutMap = new Map<number, ReturnType<typeof setTimeout>>();
	let nextTimerId = 1;

	const warmer = createCacheWarmer({
		warm: warmService.warm,
		storage,
		logger: host.logger,
		timers: {
			setTimer(fn, ms) {
				const id = nextTimerId++;
				timeoutMap.set(id, setTimeout(fn, ms));
				return id;
			},
			clearTimer(id) {
				const timeout = timeoutMap.get(id);
				if (timeout !== undefined) {
					clearTimeout(timeout);
					timeoutMap.delete(id);
				}
			},
		},
		onSurfaceChange: () => {
			for (const notify of subscribers) {
				notify();
			}
		},
	});

	host.on(turnStarted, (payload) => {
		warmer.onTurnStarted(payload.conversationId);
	});

	host.on(turnSettled, (payload) => {
		warmer.onTurnSettled(payload.conversationId, {
			...(payload.cwd !== undefined ? { cwd: payload.cwd } : {}),
			...(payload.modelName !== undefined ? { modelName: payload.modelName } : {}),
		});
	});

	function getSpec(context?: SurfaceContext): SurfaceSpec {
		const convId = context?.conversationId;
		if (convId === undefined) {
			return buildDefaultSpec();
		}
		const state = warmer.getState(convId);
		return buildConversationSpec(state.enabled, state.intervalMs, state.lastPct);
	}

	async function invoke(
		actionId: string,
		payload?: unknown,
		context?: SurfaceContext,
	): Promise<void> {
		const convId = context?.conversationId;
		if (convId === undefined) return;

		if (actionId === "cache-warming/toggle") {
			const current = warmer.getState(convId);
			await warmer.setEnabled(convId, !current.enabled);
		}

		if (actionId === "cache-warming/set-interval") {
			const seconds = parseIntervalPayload(payload);
			if (seconds === null) return;
			const ms = secondsToMs(seconds);
			if (ms === null) return;
			await warmer.setIntervalMs(convId, ms);
		}
	}

	const provider: SurfaceProvider = {
		catalogEntry: {
			id: "cache-warming",
			region: "side",
			title: "Cache Warming",
		},
		getSpec,
		invoke,
		subscribe(onChange) {
			subscribers.add(onChange);
			return () => {
				subscribers.delete(onChange);
			};
		},
	};

	registry.register(provider);

	host.logger.info("cache-warming: registered");
}

export const extension: Extension = {
	manifest,
	activate,
};
