import fs from 'node:fs';
import path from 'node:path';
import { z } from 'zod';
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { requireReact } from './requireReact.js';

type RouterType = 'next-app' | 'next-pages' | 'react-router' | 'tanstack-router' | 'unknown';

export function registerAddReactRouteTool(server: McpServer): void {
  server.registerTool(
    'add_react_route',
    {
      title: 'Add React Route',
      description:
        'Add a route entry for the detected React router: Next.js App Router (creates a page file), Next.js Pages Router (creates a page file), react-router (appends a route to a routes file), or TanStack Router (appends a file-based route under src/routes).',
      inputSchema: {
        path: z.string().min(1).describe('URL path, e.g. "/users" or "/users/:id".'),
        component: z
          .string()
          .min(1)
          .describe('Component name to import, e.g. "UserList" or a relative path like "./pages/UserList".'),
        file: z.string().optional().describe('Override the file to write/edit. Auto-detected by default.'),
      },
    },
    async ({ path: routePath, component, file: fileOverride }) => {
      try {
        const react = requireReact();
        const router = detectRouterType(react.root);

        switch (router) {
          case 'next-app':
          case 'next-pages': {
            const file =
              fileOverride ??
              path.join(
                react.root,
                router === 'next-app' ? 'app' : 'pages',
                ...routePath.split('/').filter(Boolean),
                'page.tsx',
              );
            const created = writeNextPage(file, component, router === 'next-app');
            return jsonResult({ router, file, created });
          }
          case 'react-router':
          case 'tanstack-router': {
            const file =
              fileOverride ??
              (router === 'react-router'
                ? path.join(react.root, 'src', 'routes.tsx')
                : path.join(react.root, 'src', 'routes', `${routePath.replace(/[^a-z0-9]/gi, '-')}.tsx`));
            const wired = appendRoute(file, routePath, component, router);
            return jsonResult({ router, file, wired });
          }
          default:
            return jsonResult({
              router: 'unknown',
              message:
                'No known React router detected (Next.js app/pages, react-router, or TanStack Router). ' +
                'Provide the file argument explicitly to add a route entry.',
            });
        }
      } catch (error) {
        return errorResult(toErrorMessage(error));
      }
    },
  );
}

function detectRouterType(root: string): RouterType {
  if (fs.existsSync(path.join(root, 'app', 'layout.tsx')) || fs.existsSync(path.join(root, 'app', 'layout.jsx'))) {
    return 'next-app';
  }
  if (fs.existsSync(path.join(root, 'pages', 'index.tsx')) || fs.existsSync(path.join(root, 'pages', 'index.jsx'))) {
    return 'next-pages';
  }
  if (fs.existsSync(path.join(root, 'src', 'app', 'layout.tsx')) || fs.existsSync(path.join(root, 'src', 'app', 'layout.jsx'))) {
    return 'next-app';
  }
  if (
    fs.existsSync(path.join(root, 'src', 'pages', 'index.tsx')) ||
    fs.existsSync(path.join(root, 'src', 'pages', 'index.jsx'))
  ) {
    return 'next-pages';
  }
  const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
  if (deps['@tanstack/react-router']) return 'tanstack-router';
  if (deps['react-router-dom'] || deps['react-router']) return 'react-router';
  return 'unknown';
}

function writeNextPage(file: string, component: string, appRouter: boolean): boolean {
  fs.mkdirSync(path.dirname(file), { recursive: true });
  if (fs.existsSync(file)) return false;
  const importPath = component.startsWith('.') ? component : `./${component}`;
  const contents = appRouter
    ? `import { ${component} } from '${importPath}';

export default function Page() {
  return <${component} />;
}
`
    : `import { ${component} } from '${importPath}';

export default function ${component}Page() {
  return <${component} />;
}
`;
  fs.writeFileSync(file, contents);
  return true;
}

function appendRoute(file: string, routePath: string, component: string, router: RouterType): boolean {
  fs.mkdirSync(path.dirname(file), { recursive: true });
  const importPath = component.startsWith('.') ? component : `./${component}`;
  const routeLine =
    router === 'tanstack-router'
      ? `// TODO: route ${routePath} -> <${component} /> (TanStack Router uses file-based routing; this file was created).`
      : `{ path: '${routePath}', element: <${component} /> },`;

  if (!fs.existsSync(file)) {
    fs.writeFileSync(
      file,
      `import { ${component} } from '${importPath}';

// Add this route to your router configuration:
${routeLine}
`,
    );
    return true;
  }

  const existing = fs.readFileSync(file, 'utf8');
  if (existing.includes(routeLine.trim())) return false;

  let next = existing;
  if (!new RegExp(`import\\s+\\{[^}]*\\b${component}\\b[^}]*\\}\\s+from\\s+['"]${importPath.replace(/\./g, '\\.')}['"];`).test(next)) {
    next = `import { ${component} } from '${importPath}';\n${next}`;
  }
  fs.writeFileSync(file, `${next.trimEnd()}\n${routeLine}\n`);
  return true;
}
