/**
 * TrueRef MCP Server — stdio and HTTP transports
 *
 * Exposes resolve-library-id and query-docs tools, identical to context7's
 * MCP interface, for drop-in compatibility with Claude Code, Cursor, and
 * other MCP-aware AI coding assistants.
 *
 * Configuration:
 *   TRUEREF_API_URL  Base URL for the TrueRef REST API (default: http://localhost:5173)
 *
 * Usage (stdio, default):
 *   npx tsx src/mcp/index.ts
 *
 * Usage (HTTP):
 *   npx tsx src/mcp/index.ts --transport http [--port 3001]
 */

import { parseArgs } from 'node:util';
import { createServer } from 'node:http';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import {
	CallToolRequestSchema,
	ListToolsRequestSchema
} from '@modelcontextprotocol/sdk/types.js';

import {
	RESOLVE_LIBRARY_ID_TOOL,
	handleResolveLibraryId
} from './tools/resolve-library-id.js';
import { QUERY_DOCS_TOOL, handleQueryDocs } from './tools/query-docs.js';

// ---------------------------------------------------------------------------
// CLI args
// ---------------------------------------------------------------------------

const { values: cliArgs } = parseArgs({
	options: {
		transport: { type: 'string', default: 'stdio' },
		port: { type: 'string', default: process.env.PORT ?? '3001' }
	},
	strict: false
});

// ---------------------------------------------------------------------------
// Server factory
// ---------------------------------------------------------------------------

function createMcpServer(): Server {
	const server = new Server(
		{
			name: 'io.github.trueref/trueref',
			version: '1.0.0'
		},
		{
			capabilities: { tools: {} }
		}
	);

	server.setRequestHandler(ListToolsRequestSchema, async () => ({
		tools: [RESOLVE_LIBRARY_ID_TOOL, QUERY_DOCS_TOOL]
	}));

	server.setRequestHandler(CallToolRequestSchema, async (request) => {
		const { name, arguments: args } = request.params;

		if (name === 'resolve-library-id') {
			return handleResolveLibraryId(args);
		}

		if (name === 'query-docs') {
			return handleQueryDocs(args);
		}

		return {
			content: [{ type: 'text' as const, text: `Unknown tool: ${name}` }],
			isError: true
		};
	});

	return server;
}

// ---------------------------------------------------------------------------
// HTTP transport
// ---------------------------------------------------------------------------

async function startHttp(port: number): Promise<void> {
	const httpServer = createServer(async (req, res) => {
		const url = new URL(req.url!, `http://localhost:${port}`);

		// Health check
		if (url.pathname === '/ping') {
			res.writeHead(200, { 'Content-Type': 'application/json' });
			res.end(JSON.stringify({ ok: true }));
			return;
		}

		// MCP endpoint
		if (url.pathname === '/mcp') {
			// CORS headers
			res.setHeader('Access-Control-Allow-Origin', '*');
			res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
			res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept');

			if (req.method === 'OPTIONS') {
				res.writeHead(204);
				res.end();
				return;
			}

			// Create a fresh server and transport per request (stateless mode)
			const mcpServer = createMcpServer();
			const transport = new StreamableHTTPServerTransport({
				sessionIdGenerator: undefined
			});

			await mcpServer.connect(transport);
			await transport.handleRequest(req, res);
			return;
		}

		res.writeHead(404);
		res.end('Not Found');
	});

	httpServer.listen(port, () => {
		process.stderr.write(`TrueRef MCP server listening on http://localhost:${port}/mcp\n`);
	});
}

// ---------------------------------------------------------------------------
// Startup
// ---------------------------------------------------------------------------

async function main() {
	if (cliArgs.transport === 'http') {
		const port = parseInt(cliArgs.port as string, 10);
		await startHttp(port);
	} else {
		const mcpServer = createMcpServer();
		const transport = new StdioServerTransport();
		await mcpServer.connect(transport);
		// Server runs until process exits
	}
}

main().catch((err) => {
	process.stderr.write(`MCP server error: ${err instanceof Error ? err.message : String(err)}\n`);
	process.exit(1);
});
