import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import fs from "node:fs";
import path from "node:path";

const ROOT = path.resolve(
  process.env.ZCLIENTS_ROOT ??
    "C:\\Users\\ahuja\\My ShareSync\\P-Homes\\zclients"
);

function resolveInRoot(relativePath: string): string {
  const resolved = path.resolve(ROOT, relativePath);
  if (resolved !== ROOT && !resolved.startsWith(ROOT + path.sep)) {
    throw new Error(`Path escapes zclients root: ${relativePath}`);
  }
  return resolved;
}

function listDir(dirPath: string) {
  return fs
    .readdirSync(dirPath, { withFileTypes: true })
    .map((entry) => ({
      name: entry.name,
      type: entry.isDirectory() ? "folder" : "file",
    }))
    .sort((a, b) => a.name.localeCompare(b.name));
}

function walk(dirPath: string, relBase: string, results: string[], maxResults: number) {
  if (results.length >= maxResults) return;
  for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
    if (results.length >= maxResults) return;
    const rel = relBase ? `${relBase}/${entry.name}` : entry.name;
    const full = path.join(dirPath, entry.name);
    if (entry.isDirectory()) {
      walk(full, rel, results, maxResults);
    } else {
      results.push(rel);
    }
  }
}

export function registerZclientsTools(server: McpServer) {
  server.registerTool(
    "list_year_folders",
    {
      title: "List year folders",
      description: "List the top-level year folders under the zclients root (e.g. 2026, 2025).",
      inputSchema: {},
    },
    async () => ({
      content: [{ type: "text", text: JSON.stringify(listDir(ROOT), null, 2) }],
    })
  );

  server.registerTool(
    "list_job_folders",
    {
      title: "List job folders",
      description:
        "List job folders inside a given year folder (relative path from zclients root, e.g. '2026').",
      inputSchema: {
        yearFolder: z.string().describe("Relative path to the year folder, e.g. '2026'"),
      },
    },
    async ({ yearFolder }) => {
      const dir = resolveInRoot(yearFolder);
      return {
        content: [{ type: "text", text: JSON.stringify(listDir(dir), null, 2) }],
      };
    }
  );

  server.registerTool(
    "search_jobs",
    {
      title: "Search job folders",
      description:
        "Search all job folder names under zclients (across all years) for a substring match, e.g. an address or job number.",
      inputSchema: {
        query: z.string().describe("Substring to search for, case-insensitive"),
        maxResults: z.number().optional().describe("Max results to return (default 25)"),
      },
    },
    async ({ query, maxResults }) => {
      const limit = maxResults ?? 25;
      const matches: { year: string; job: string; path: string }[] = [];
      for (const yearEntry of fs.readdirSync(ROOT, { withFileTypes: true })) {
        if (!yearEntry.isDirectory()) continue;
        const yearPath = path.join(ROOT, yearEntry.name);
        for (const jobEntry of fs.readdirSync(yearPath, { withFileTypes: true })) {
          if (!jobEntry.isDirectory()) continue;
          if (jobEntry.name.toLowerCase().includes(query.toLowerCase())) {
            matches.push({
              year: yearEntry.name,
              job: jobEntry.name,
              path: `${yearEntry.name}/${jobEntry.name}`,
            });
            if (matches.length >= limit) break;
          }
        }
        if (matches.length >= limit) break;
      }
      return {
        content: [{ type: "text", text: JSON.stringify(matches, null, 2) }],
      };
    }
  );

  server.registerTool(
    "list_job_files",
    {
      title: "List files in a job folder",
      description:
        "Recursively list files inside a specific job folder (relative path from zclients root, e.g. '2026/2026-04141426 150-154 E 105th Street').",
      inputSchema: {
        jobFolder: z.string().describe("Relative path to the job folder"),
        maxResults: z.number().optional().describe("Max files to return (default 200)"),
      },
    },
    async ({ jobFolder, maxResults }) => {
      const dir = resolveInRoot(jobFolder);
      const results: string[] = [];
      walk(dir, "", results, maxResults ?? 200);
      return {
        content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
      };
    }
  );

  server.registerTool(
    "read_job_file",
    {
      title: "Read a file from a job folder",
      description:
        "Read the text content of a file inside zclients (relative path from zclients root). Limited to text-readable files under 2MB.",
      inputSchema: {
        filePath: z.string().describe("Relative path to the file, from zclients root"),
      },
    },
    async ({ filePath }) => {
      const full = resolveInRoot(filePath);
      const stat = fs.statSync(full);
      if (stat.size > 2 * 1024 * 1024) {
        throw new Error(`File too large to read directly (${stat.size} bytes): ${filePath}`);
      }
      const content = fs.readFileSync(full, "utf-8");
      return { content: [{ type: "text", text: content }] };
    }
  );

  server.registerTool(
    "write_job_file",
    {
      title: "Write a file into a job folder",
      description:
        "Create or overwrite a text file inside zclients (relative path from zclients root). Creates parent folders if needed.",
      inputSchema: {
        filePath: z.string().describe("Relative path to the file, from zclients root"),
        content: z.string().describe("Text content to write"),
      },
    },
    async ({ filePath, content }) => {
      const full = resolveInRoot(filePath);
      fs.mkdirSync(path.dirname(full), { recursive: true });
      fs.writeFileSync(full, content, "utf-8");
      return {
        content: [{ type: "text", text: `Wrote ${content.length} characters to ${filePath}` }],
      };
    }
  );
}
