import type { McpTool, McpToolMeta } from './types.js';
import type { ZodTypeAny } from 'zod';

const tools = new Map<string, McpTool>();

export function registerTool(tool: McpTool): void {
  tools.set(tool.name, tool);
}

export function getTool(name: string): McpTool | undefined {
  return tools.get(name);
}

export function listTools(): McpToolMeta[] {
  return Array.from(tools.values()).map(t => ({
    name: t.name,
    description: t.description,
    requiredRole: t.requiredRole,
    inputSchema: zodToJsonSchema(t.inputSchema),
  }));
}

type ZodDef = {
  typeName: string;
  description?: string;
  innerType?: { _def: ZodDef };
  shape?: () => Record<string, ZodTypeAny>;
};

/** Minimal Zod → JSON Schema converter (object shapes only — sufficient for tool docs) */
function zodToJsonSchema(schema: ZodTypeAny): Record<string, unknown> {
  try {
    const def = (schema as unknown as { _def: ZodDef })._def;
    if (def.typeName === 'ZodObject' && def.shape) {
      const shape = def.shape();
      const properties: Record<string, unknown> = {};
      const required: string[] = [];
      for (const [key, field] of Object.entries(shape)) {
        const fieldDef = (field as unknown as { _def: ZodDef })._def;
        const { resolvedType, isRequired, description } = resolveZodDef(fieldDef);
        properties[key] = { ...resolvedType, description: description ?? key };
        if (isRequired) required.push(key);
      }
      return { type: 'object', properties, required };
    }
  } catch {
    // fall through
  }
  return { type: 'object' };
}

/**
 * Unwrap ZodOptional / ZodDefault wrappers and resolve the JSON type for a field.
 * Returns the JSON Schema fragment plus whether the field is required.
 */
function resolveZodDef(def: ZodDef): {
  resolvedType: Record<string, unknown>;
  isRequired: boolean;
  description?: string;
} {
  const description = def.description;
  if (def.typeName === 'ZodOptional') {
    const inner = def.innerType?._def;
    return {
      resolvedType: inner ? zodDefToJsonType(inner) : { type: 'string' },
      isRequired: false,
      description,
    };
  }
  if (def.typeName === 'ZodDefault') {
    const inner = def.innerType?._def;
    return {
      resolvedType: inner ? zodDefToJsonType(inner) : { type: 'string' },
      isRequired: false, // has default → not required in JSON Schema
      description,
    };
  }
  return { resolvedType: zodDefToJsonType(def), isRequired: true, description };
}

function zodDefToJsonType(def: ZodDef): Record<string, unknown> {
  switch (def.typeName) {
    case 'ZodObject':
      return { type: 'object' };
    case 'ZodArray':
      return { type: 'array' };
    case 'ZodBoolean':
      return { type: 'boolean' };
    case 'ZodNumber':
      return { type: 'number' };
    case 'ZodEnum':
      return { type: 'string' };
    default:
      return { type: 'string' };
  }
}
