/**
 * MCP tools for rInbox (email mailboxes & threads).
 *
 * ALL tools use forceAuth=true — always requires token+member
 * regardless of space visibility (email content is sensitive).
 *
 * Tools: rinbox_list_mailboxes, rinbox_list_threads,
 *        rinbox_get_thread, rinbox_list_approvals
 */

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

const MAILBOX_PREFIX = ":inbox:mailboxes:";

/** Find all mailbox docIds for a space. */
function findMailboxDocIds(syncServer: SyncServer, space: string): string[] {
	const prefix = `${space}${MAILBOX_PREFIX}`;
	return syncServer.getDocIds().filter(id => id.startsWith(prefix));
}

export function registerInboxTools(server: McpServer, syncServer: SyncServer) {
	server.tool(
		"rinbox_list_mailboxes",
		"List mailboxes in a space (requires auth + membership — email content is sensitive)",
		{
			space: z.string().describe("Space slug"),
			token: z.string().describe("JWT auth token"),
		},
		async ({ space, token }) => {
			const access = await resolveAccess(token, space, false, true);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = findMailboxDocIds(syncServer, space);
			const mailboxes = [];
			for (const docId of docIds) {
				const doc = syncServer.getDoc<MailboxDoc>(docId);
				if (!doc?.mailbox) continue;
				mailboxes.push({
					id: doc.mailbox.id,
					name: doc.mailbox.name,
					slug: doc.mailbox.slug,
					email: doc.mailbox.email,
					threadCount: Object.keys(doc.threads || {}).length,
					approvalCount: Object.keys(doc.approvals || {}).length,
				});
			}

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

	server.tool(
		"rinbox_list_threads",
		"List email threads in a mailbox (subjects only, no body content)",
		{
			space: z.string().describe("Space slug"),
			token: z.string().describe("JWT auth token"),
			mailbox_slug: z.string().optional().describe("Filter by mailbox slug (searches all if omitted)"),
			status: z.string().optional().describe("Filter by status"),
			search: z.string().optional().describe("Search in subject/from"),
			limit: z.number().optional().describe("Max results (default 50)"),
		},
		async ({ space, token, mailbox_slug, status, search, limit }) => {
			const access = await resolveAccess(token, space, false, true);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = mailbox_slug
				? findMailboxDocIds(syncServer, space).filter(id => id.endsWith(`:${mailbox_slug}`))
				: findMailboxDocIds(syncServer, space);

			let threads: Array<{
				id: string; mailboxId: string; subject: string;
				fromAddress: string | null; fromName: string | null;
				status: string; isRead: boolean; isStarred: boolean;
				receivedAt: number;
			}> = [];

			for (const docId of docIds) {
				const doc = syncServer.getDoc<MailboxDoc>(docId);
				if (!doc?.threads) continue;
				for (const t of Object.values(doc.threads)) {
					threads.push({
						id: t.id,
						mailboxId: t.mailboxId,
						subject: t.subject,
						fromAddress: t.fromAddress,
						fromName: t.fromName,
						status: t.status,
						isRead: t.isRead,
						isStarred: t.isStarred,
						receivedAt: t.createdAt,
					});
				}
			}

			if (status) threads = threads.filter(t => t.status === status);
			if (search) {
				const q = search.toLowerCase();
				threads = threads.filter(t =>
					t.subject.toLowerCase().includes(q) ||
					(t.fromAddress && t.fromAddress.toLowerCase().includes(q)) ||
					(t.fromName && t.fromName.toLowerCase().includes(q)),
				);
			}

			threads.sort((a, b) => b.receivedAt - a.receivedAt);
			threads = threads.slice(0, limit || 50);

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

	server.tool(
		"rinbox_get_thread",
		"Get a full email thread including body text (omits bodyHtml for size)",
		{
			space: z.string().describe("Space slug"),
			token: z.string().describe("JWT auth token"),
			thread_id: z.string().describe("Thread ID"),
		},
		async ({ space, token, thread_id }) => {
			const access = await resolveAccess(token, space, false, true);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			for (const docId of findMailboxDocIds(syncServer, space)) {
				const doc = syncServer.getDoc<MailboxDoc>(docId);
				const thread = doc?.threads?.[thread_id];
				if (thread) {
					// Omit bodyHtml to reduce payload size
					const { bodyHtml, ...safe } = thread;
					return { content: [{ type: "text", text: JSON.stringify(safe, null, 2) }] };
				}
			}

			return { content: [{ type: "text", text: JSON.stringify({ error: "Thread not found" }) }] };
		},
	);

	server.tool(
		"rinbox_list_approvals",
		"List pending email approvals (draft reviews awaiting signatures)",
		{
			space: z.string().describe("Space slug"),
			token: z.string().describe("JWT auth token"),
			mailbox_slug: z.string().optional().describe("Filter by mailbox slug"),
		},
		async ({ space, token, mailbox_slug }) => {
			const access = await resolveAccess(token, space, false, true);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = mailbox_slug
				? findMailboxDocIds(syncServer, space).filter(id => id.endsWith(`:${mailbox_slug}`))
				: findMailboxDocIds(syncServer, space);

			const approvals = [];
			for (const docId of docIds) {
				const doc = syncServer.getDoc<MailboxDoc>(docId);
				if (!doc?.approvals) continue;
				for (const a of Object.values(doc.approvals)) {
					if (a.status !== "pending") continue;
					approvals.push({
						id: a.id,
						mailboxId: a.mailboxId,
						subject: a.subject,
						toAddresses: a.toAddresses,
						authorId: a.authorId,
						requiredSignatures: a.requiredSignatures,
						currentSignatures: a.signatures?.length ?? 0,
						createdAt: a.createdAt,
					});
				}
			}

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