import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import * as fs from "fs";
import * as path from "path";

/**
 * MCP Server for Battle Racing Common Library
 * This server allows other AI agents to query types, schemas and constants
 * from the br-common-lib repository locally.
 */

const DOMAINS_DIR = path.resolve(__dirname, "../../src/domains");

const server = new McpServer({
  name: "br-common-lib-mcp",
  version: "1.1.1",
});

/**
 * List all available domains in src/domains
 */
async function listDomains() {
  if (!fs.existsSync(DOMAINS_DIR)) {
    throw new Error(`Domains directory not found at ${DOMAINS_DIR}`);
  }

  const entries = fs.readdirSync(DOMAINS_DIR, { withFileTypes: true });
  return entries
    .filter((entry: fs.Dirent) => entry.isDirectory())
    .map((entry: fs.Dirent) => entry.name);
}

/**
 * Get details for a specific domain (recursive)
 */
async function getDomainDetails(domain: string) {
  const domainPath = path.join(DOMAINS_DIR, domain);

  if (!fs.existsSync(domainPath)) {
    throw new Error(`Domain "${domain}" not found at ${domainPath}`);
  }

  let output = `## Domain: ${domain}\n\n`;

  function readDirRecursive(dir: string) {
    const entries = fs.readdirSync(dir, { withFileTypes: true });

    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        readDirRecursive(fullPath);
      } else if (
        entry.name.endsWith(".types.ts") ||
        entry.name.endsWith(".schema.ts") ||
        entry.name.endsWith(".const.ts") ||
        entry.name === "index.ts"
      ) {
        const relativePath = path.relative(domainPath, fullPath);
        const content = fs.readFileSync(fullPath, "utf-8");
        output += `### File: ${relativePath}\n\`\`\`typescript\n${content}\n\`\`\`\n\n`;
      }
    }
  }

  readDirRecursive(domainPath);
  return output;
}

/**
 * Search for a symbol (type, constant, etc) across all domains
 */
async function searchSymbol(query: string) {
  const domains = await listDomains();
  let results: { domain: string; file: string; match: string }[] = [];

  for (const domain of domains) {
    const domainPath = path.join(DOMAINS_DIR, domain);
    
    function searchInDir(dir: string) {
      const entries = fs.readdirSync(dir, { withFileTypes: true });
      for (const entry of entries) {
        const fullPath = path.join(dir, entry.name);
        if (entry.isDirectory()) {
          searchInDir(fullPath);
        } else if (entry.isFile() && (entry.name.endsWith(".ts"))) {
          const content = fs.readFileSync(fullPath, "utf-8");
          if (content.includes(query)) {
            const lines = content.split("\n");
            const matchLine = lines.find(l => l.includes(query)) || "";
            results.push({
              domain,
              file: path.relative(DOMAINS_DIR, fullPath),
              match: matchLine.trim()
            });
          }
        }
      }
    }
    searchInDir(domainPath);
  }

  if (results.length === 0) return `No results found for "${query}"`;

  return results
    .map(r => `- [${r.domain}] ${r.file}: \`${r.match}\``)
    .join("\n");
}

// Register tools using the high-level McpServer API (registerTool)
server.registerTool(
  "list_domains",
  {
    description: "List all available domains in br-common-lib (e.g., kart, game, powerUp)",
  },
  async () => {
    const domains = await listDomains();
    return {
      content: [
        {
          type: "text",
          text: `Available domains: ${domains.join(", ")}`,
        },
      ],
    };
  }
);

server.registerTool(
  "get_domain_details",
  {
    description: "Get all types, schemas, and constants for a specific domain (recursive)",
    inputSchema: z.object({
      domain: z.string().describe("The name of the domain (e.g., 'kart')"),
    }),
  },
  async ({ domain }) => {
    const details = await getDomainDetails(domain);
    return {
      content: [{ type: "text", text: details }],
    };
  }
);

server.registerTool(
  "search_symbol",
  {
    description: "Search for a specific type, constant or property across all domains",
    inputSchema: z.object({
      query: z.string().describe("The symbol or string to search for (e.g., 'hardwareState')"),
    }),
  },
  async ({ query }) => {
    const results = await searchSymbol(query);
    return {
      content: [{ type: "text", text: results }],
    };
  }
);

// Start the server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Battle Racing Common Lib MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});
