/**
 * MCP tools for rVote (proposals & pairwise ranking).
 *
 * Tools: rvote_list_proposals, rvote_get_proposal, rvote_get_results
 */

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

const PROPOSAL_PREFIX = ":vote:proposals:";

function findProposalDocIds(syncServer: SyncServer, space: string): string[] {
	const prefix = `${space}${PROPOSAL_PREFIX}`;
	return syncServer.getDocIds().filter(id => id.startsWith(prefix));
}

export function registerVoteTools(server: McpServer, syncServer: SyncServer) {
	server.tool(
		"rvote_list_proposals",
		"List governance proposals in a space with Elo rankings and vote tallies",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			status: z.string().optional().describe("Filter by status"),
			limit: z.number().optional().describe("Max results (default 50)"),
		},
		async ({ space, token, status, limit }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = findProposalDocIds(syncServer, space);
			let proposals: any[] = [];

			for (const docId of docIds) {
				const doc = syncServer.getDoc<ProposalDoc>(docId);
				if (!doc?.proposal) continue;
				const p = doc.proposal;
				proposals.push({
					id: p.id,
					title: p.title,
					description: (p.description || "").slice(0, 200),
					status: p.status,
					score: p.score,
					elo: doc.pairwise?.elo ?? null,
					comparisons: doc.pairwise?.comparisons ?? 0,
					finalYes: p.finalYes,
					finalNo: p.finalNo,
					finalAbstain: p.finalAbstain,
					voteCount: Object.keys(doc.votes || {}).length,
					votingEndsAt: p.votingEndsAt,
					createdAt: p.createdAt,
				});
			}

			if (status) proposals = proposals.filter(p => p.status === status);
			proposals.sort((a, b) => (b.elo ?? 0) - (a.elo ?? 0));
			proposals = proposals.slice(0, limit || 50);

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

	server.tool(
		"rvote_get_proposal",
		"Get full details of a specific proposal including votes and pairwise data",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			proposal_id: z.string().describe("Proposal ID"),
		},
		async ({ space, token, proposal_id }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docId = `${space}${PROPOSAL_PREFIX}${proposal_id}`;
			const doc = syncServer.getDoc<ProposalDoc>(docId);
			if (!doc?.proposal) {
				return { content: [{ type: "text", text: JSON.stringify({ error: "Proposal not found" }) }] };
			}

			return {
				content: [{
					type: "text",
					text: JSON.stringify({
						proposal: doc.proposal,
						pairwise: doc.pairwise,
						voteCount: Object.keys(doc.votes || {}).length,
						finalVoteCount: Object.keys(doc.finalVotes || {}).length,
					}, null, 2),
				}],
			};
		},
	);

	server.tool(
		"rvote_get_results",
		"Get vote results summary: Elo rankings across all proposals",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
		},
		async ({ space, token }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = findProposalDocIds(syncServer, space);
			const rankings = [];

			for (const docId of docIds) {
				const doc = syncServer.getDoc<ProposalDoc>(docId);
				if (!doc?.proposal) continue;
				rankings.push({
					id: doc.proposal.id,
					title: doc.proposal.title,
					status: doc.proposal.status,
					elo: doc.pairwise?.elo ?? 1500,
					comparisons: doc.pairwise?.comparisons ?? 0,
					wins: doc.pairwise?.wins ?? 0,
					finalYes: doc.proposal.finalYes,
					finalNo: doc.proposal.finalNo,
					finalAbstain: doc.proposal.finalAbstain,
				});
			}

			rankings.sort((a, b) => b.elo - a.elo);
			return { content: [{ type: "text", text: JSON.stringify(rankings, null, 2) }] };
		},
	);
}
