/**
 * MCP tools for rChoices (voting sessions — vote/rank/score).
 *
 * Tools: rchoices_list_sessions, rchoices_get_session, rchoices_get_results
 */

import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import type { SyncServer } from "../local-first/sync-server";
import { choicesDocId } from "../../modules/rchoices/schemas";
import type { ChoicesDoc } from "../../modules/rchoices/schemas";
import { resolveAccess, accessDeniedResponse } from "./_auth";

export function registerChoicesTools(server: McpServer, syncServer: SyncServer) {
	server.tool(
		"rchoices_list_sessions",
		"List voting/ranking sessions in a space",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			type: z.string().optional().describe("Filter by type (vote, rank, score)"),
			include_closed: z.boolean().optional().describe("Include closed sessions (default false)"),
		},
		async ({ space, token, type, include_closed }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const doc = syncServer.getDoc<ChoicesDoc>(choicesDocId(space));
			if (!doc) {
				return { content: [{ type: "text", text: JSON.stringify({ error: "No choices data found" }) }] };
			}

			let sessions = Object.values(doc.sessions || {});
			if (!include_closed) sessions = sessions.filter(s => !s.closed);
			if (type) sessions = sessions.filter(s => s.type === type);

			const summary = sessions.map(s => ({
				id: s.id,
				title: s.title,
				type: s.type,
				mode: s.mode,
				optionCount: s.options?.length ?? 0,
				closed: s.closed,
				createdAt: s.createdAt,
			}));

			return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
		},
	);

	server.tool(
		"rchoices_get_session",
		"Get full details of a voting session including options",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			session_id: z.string().describe("Session ID"),
		},
		async ({ space, token, session_id }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const doc = syncServer.getDoc<ChoicesDoc>(choicesDocId(space));
			const session = doc?.sessions?.[session_id];
			if (!session) {
				return { content: [{ type: "text", text: JSON.stringify({ error: "Session not found" }) }] };
			}

			const voteCount = Object.values(doc!.votes || {})
				.filter(v => v.choices && Object.keys(v.choices).some(k => session.options?.some(o => o.id === k)))
				.length;

			return { content: [{ type: "text", text: JSON.stringify({ ...session, voteCount }, null, 2) }] };
		},
	);

	server.tool(
		"rchoices_get_results",
		"Get tallied results for a voting session",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			session_id: z.string().describe("Session ID"),
		},
		async ({ space, token, session_id }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const doc = syncServer.getDoc<ChoicesDoc>(choicesDocId(space));
			const session = doc?.sessions?.[session_id];
			if (!session) {
				return { content: [{ type: "text", text: JSON.stringify({ error: "Session not found" }) }] };
			}

			const optionIds = new Set(session.options?.map(o => o.id) || []);
			const relevantVotes = Object.values(doc!.votes || {})
				.filter(v => v.choices && Object.keys(v.choices).some(k => optionIds.has(k)));

			// Tally
			const tallies: Record<string, { label: string; totalScore: number; voteCount: number }> = {};
			for (const opt of session.options || []) {
				tallies[opt.id] = { label: opt.label, totalScore: 0, voteCount: 0 };
			}
			for (const vote of relevantVotes) {
				for (const [optId, score] of Object.entries(vote.choices || {})) {
					if (tallies[optId]) {
						tallies[optId].totalScore += score;
						tallies[optId].voteCount++;
					}
				}
			}

			const results = Object.entries(tallies)
				.map(([id, t]) => ({ id, ...t, avgScore: t.voteCount > 0 ? t.totalScore / t.voteCount : 0 }))
				.sort((a, b) => b.totalScore - a.totalScore);

			return {
				content: [{
					type: "text",
					text: JSON.stringify({
						session: { id: session.id, title: session.title, type: session.type, closed: session.closed },
						totalVoters: relevantVotes.length,
						results,
					}, null, 2),
				}],
			};
		},
	);
}
