import { z } from 'zod';
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { config } from '../../config.js';
import { detectProject, resolvePackage } from '../../lib/frameworks/detect.js';
import { resolveTarget } from '../../lib/frameworks/resolve.js';
import { runCommand } from '../../lib/runCommand.js';
import { errorResult, jsonResult, packageSchema, targetSchema, toErrorMessage } from '../shared.js';

export function registerRunTestsTool(server: McpServer): void {
  server.registerTool(
    'run_tests',
    {
      title: 'Run Tests',
      description:
        'Run the project test suite via the detected adapter (e.g. Vitest/Jest for JS frontends, PHPUnit/Pest for PHP, manage.py test for Django, rails test for Rails). Optional `package` scopes to a monorepo package.',
      inputSchema: {
        target: targetSchema,
        package: packageSchema,
        extraArgs: z
          .array(z.string())
          .optional()
          .describe('Extra CLI arguments forwarded to the test runner, e.g. ["--filter", "UserTest"].'),
      },
    },
    async ({ target, package: packageName, extraArgs }) => {
      try {
        const root = packageName
          ? resolvePackage(config.workspaceRoot, packageName).pkg.absolutePath
          : config.workspaceRoot;
        const detected = detectProject(root);
        const { adapter, target: resolvedTarget } = resolveTarget(detected, target);
        const cmd = adapter.testCommand(extraArgs ?? []);
        if (!cmd) {
          return jsonResult({
            target: resolvedTarget,
            package: packageName ?? null,
            adapter: adapter.label,
            ran: false,
            message:
              'No test runner detected for this project (no "test" script, and no vendor/bin/phpunit or vendor/bin/pest).',
          });
        }
        const result = await runCommand(cmd.command, cmd.args, {
          cwd: cmd.cwd,
          timeoutMs: config.scaffoldCommandTimeoutMs,
        });
        return jsonResult({
          target: resolvedTarget,
          package: packageName ?? null,
          adapter: adapter.label,
          ran: true,
          exitCode: result.exitCode,
          timedOut: result.timedOut,
          failed: result.failed,
          output: result.output,
          cwd: result.cwd,
        });
      } catch (error) {
        return errorResult(toErrorMessage(error));
      }
    },
  );
}
