import type { AgentMessage } from "@earendil-works/pi-agent-core";
import { describe, expect, it } from "vitest";
import {
	type AgentSessionController,
	createAgentSessionHostHandlers,
	createAgentSessionTurnSummaries,
	normalizeAgentSessionMaxChars,
	normalizeAgentSessionTurnCount,
} from "../src/core/agent-sessions.js";

const summary = {
	activeSessionId: "active-root",
	sessionId: "session-root",
	cwd: "/repo",
	status: "idle",
	isCurrent: true,
	isStreaming: false,
	isCompacting: false,
	attachedClients: 1,
	messageCount: 4,
	queuedCount: 0,
	isSessionActive: false,
	capabilities: ["send", "recent_turns", "stop", "restart"] as const,
};

function user(text: string, timestamp: number): AgentMessage {
	return { role: "user", content: [{ type: "text", text }], timestamp } as AgentMessage;
}

function assistant(text: string, timestamp: number): AgentMessage {
	return { role: "assistant", content: [{ type: "text", text }], timestamp } as AgentMessage;
}

describe("agent session helpers", () => {
	it("groups bounded recent turns without exposing unbounded transcript text", () => {
		const result = createAgentSessionTurnSummaries(
			[
				user("first question", 1),
				assistant("first answer", 2),
				user("second question", 3),
				assistant("second answer", 4),
			],
			1,
			6,
		);

		expect(result).toEqual({
			turns: [
				{
					user: "second",
					assistant: "second",
					toolCalls: 0,
					startedAt: 3,
					endedAt: 4,
					messageCount: 2,
					truncated: true,
				},
			],
			truncated: true,
		});
	});

	it("normalizes the recent-turn bounds", () => {
		expect(normalizeAgentSessionTurnCount(undefined)).toBe(3);
		expect(normalizeAgentSessionTurnCount(20)).toBe(20);
		expect(normalizeAgentSessionMaxChars(undefined)).toBe(6_000);
		expect(normalizeAgentSessionMaxChars(12_000)).toBe(12_000);
		expect(() => normalizeAgentSessionTurnCount(0)).toThrow("between 1 and 20");
		expect(() => normalizeAgentSessionMaxChars(79)).toThrow("between 80 and 12000");
	});

	it("validates and routes the typed host handlers", async () => {
		const controller: AgentSessionController = {
			listSessions: () => [summary],
			getSession: (target) => ({ ...summary, activeSessionId: target }),
			recentTurns: () => ({ agent: summary, turns: [], count: 3, maxChars: 6_000, truncated: false }),
			send: ({ target, delivery }) => ({
				operationId: "op-1",
				status: "queued",
				delivery,
				target: { activeSessionId: target, sessionId: "session-root" },
			}),
			stop: () => ({ operationId: "op-2", status: "accepted" }),
			restart: () => ({ operationId: "op-3", status: "accepted" }),
		};
		const handlers = createAgentSessionHostHandlers(controller);

		expect(await handlers["agent.sessions.list"]({})).toEqual({ sessions: [summary] });
		expect(await handlers["agent.sessions.get"]({ target: "root" })).toEqual({
			session: { ...summary, activeSessionId: "root" },
		});
		expect(
			await handlers["agent.sessions.send"]({ target: "root", message: "continue", delivery: "follow_up" }),
		).toEqual({
			operationId: "op-1",
			status: "queued",
			delivery: "follow_up",
			target: { activeSessionId: "root", sessionId: "session-root" },
		});
		await expect(
			handlers["agent.sessions.send"]({ target: "root", message: "continue", delivery: "bad" }),
		).rejects.toThrow("delivery must be 'steer' or 'follow_up'");
		expect(await handlers["agent.sessions.stop"]({ target: "root" })).toEqual({
			operationId: "op-2",
			status: "accepted",
		});
		expect(await handlers["agent.sessions.restart"]({ target: "root" })).toEqual({
			operationId: "op-3",
			status: "accepted",
		});
	});
});
