/**
 * MCP tools for rFiles (file metadata & memory cards).
 *
 * Tools: rfiles_list_files, rfiles_get_file, rfiles_list_cards
 * Read-only. Omits storagePath and fileHash from all responses.
 */

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

const FILES_PREFIX = ":files:cards:";

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

export function registerFilesTools(server: McpServer, syncServer: SyncServer) {
	server.tool(
		"rfiles_list_files",
		"List file metadata in a space (omits storagePath for security)",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			mime_type: z.string().optional().describe("Filter by MIME type prefix (e.g. 'image/', 'application/pdf')"),
			search: z.string().optional().describe("Search in filename/title/tags"),
			limit: z.number().optional().describe("Max results (default 50)"),
		},
		async ({ space, token, mime_type, search, limit }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = findFilesDocIds(syncServer, space);
			let files: Array<{
				id: string; originalFilename: string; title: string | null;
				mimeType: string | null; fileSize: number; tags: string[];
				uploadedBy: string | null; createdAt: number; updatedAt: number;
			}> = [];

			for (const docId of docIds) {
				const doc = syncServer.getDoc<FilesDoc>(docId);
				if (!doc?.files) continue;
				for (const f of Object.values(doc.files)) {
					files.push({
						id: f.id,
						originalFilename: f.originalFilename,
						title: f.title,
						mimeType: f.mimeType,
						fileSize: f.fileSize,
						tags: f.tags,
						uploadedBy: f.uploadedBy,
						createdAt: f.createdAt,
						updatedAt: f.updatedAt,
					});
				}
			}

			if (mime_type) {
				files = files.filter(f => f.mimeType && f.mimeType.startsWith(mime_type));
			}

			if (search) {
				const q = search.toLowerCase();
				files = files.filter(f =>
					f.originalFilename.toLowerCase().includes(q) ||
					(f.title && f.title.toLowerCase().includes(q)) ||
					f.tags.some(t => t.toLowerCase().includes(q)),
				);
			}

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

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

	server.tool(
		"rfiles_get_file",
		"Get detailed metadata for a specific file (omits storagePath)",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			file_id: z.string().describe("File ID"),
		},
		async ({ space, token, file_id }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			for (const docId of findFilesDocIds(syncServer, space)) {
				const doc = syncServer.getDoc<FilesDoc>(docId);
				const file = doc?.files?.[file_id];
				if (file) {
					// Omit storagePath and fileHash for security
					const { storagePath, fileHash, ...safe } = file;
					return { content: [{ type: "text", text: JSON.stringify(safe, null, 2) }] };
				}
			}

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

	server.tool(
		"rfiles_list_cards",
		"List memory cards (knowledge cards) in a space",
		{
			space: z.string().describe("Space slug"),
			token: z.string().optional().describe("JWT auth token"),
			type: z.string().optional().describe("Filter by card type"),
			search: z.string().optional().describe("Search in title/body/tags"),
			limit: z.number().optional().describe("Max results (default 50)"),
		},
		async ({ space, token, type, search, limit }) => {
			const access = await resolveAccess(token, space, false);
			if (!access.allowed) return accessDeniedResponse(access.reason!);

			const docIds = findFilesDocIds(syncServer, space);
			let cards: Array<{
				id: string; title: string; body: string; cardType: string | null;
				tags: string[]; position: number; createdAt: number; updatedAt: number;
			}> = [];

			for (const docId of docIds) {
				const doc = syncServer.getDoc<FilesDoc>(docId);
				if (!doc?.memoryCards) continue;
				for (const c of Object.values(doc.memoryCards)) {
					cards.push({
						id: c.id,
						title: c.title,
						body: c.body.slice(0, 500),
						cardType: c.cardType,
						tags: c.tags,
						position: c.position,
						createdAt: c.createdAt,
						updatedAt: c.updatedAt,
					});
				}
			}

			if (type) cards = cards.filter(c => c.cardType === type);
			if (search) {
				const q = search.toLowerCase();
				cards = cards.filter(c =>
					c.title.toLowerCase().includes(q) ||
					c.body.toLowerCase().includes(q) ||
					c.tags.some(t => t.toLowerCase().includes(q)),
				);
			}

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

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