import { describe, it, expect } from 'vitest';
import { z } from 'zod';
import { registerTool, getTool, listTools } from './registry.js';

describe('tool registry', () => {
  it('registers and retrieves a tool by name', () => {
    registerTool({
      name: 'test.hello',
      description: 'A test tool',
      requiredRole: 'viewer',
      inputSchema: z.object({ name: z.string() }),
      async execute(args) {
        return { hello: args.name };
      },
    });
    const tool = getTool('test.hello');
    expect(tool).toBeDefined();
    expect(tool?.name).toBe('test.hello');
    expect(tool?.requiredRole).toBe('viewer');
  });

  it('listTools returns all registered tools with meta', () => {
    const all = listTools();
    const found = all.find(t => t.name === 'test.hello');
    expect(found).toBeDefined();
    expect(found?.description).toBe('A test tool');
    expect(found?.inputSchema).toHaveProperty('type', 'object');
  });

  it('getTool returns undefined for unknown tool', () => {
    expect(getTool('does.not.exist')).toBeUndefined();
  });

  it('zodToJsonSchema emits correct types for boolean/number/array fields', () => {
    registerTool({
      name: 'test.types',
      description: 'Type test',
      requiredRole: 'viewer',
      inputSchema: z.object({
        flag: z.boolean(),
        count: z.coerce.number(),
        tags: z.array(z.string()),
        label: z.string().optional(),
        enabled: z.boolean().default(false),
      }),
      async execute(args) {
        return args;
      },
    });
    const tool = listTools().find(t => t.name === 'test.types');
    const props = (tool?.inputSchema as { properties: Record<string, { type: string }> })
      .properties;
    expect(props.flag.type).toBe('boolean');
    expect(props.count.type).toBe('number');
    expect(props.tags.type).toBe('array');
    expect(props.label.type).toBe('string');
    // ZodDefault should unwrap to boolean, not 'string'
    expect(props.enabled.type).toBe('boolean');
    // optional + default fields should NOT be in required
    const required = tool?.inputSchema.required as string[];
    expect(required).toContain('flag');
    expect(required).toContain('count');
    expect(required).not.toContain('label');
    expect(required).not.toContain('enabled');
  });
});

describe('tool execute', () => {
  it('executes with validated args', async () => {
    registerTool({
      name: 'test.echo',
      description: 'Echo',
      requiredRole: 'admin',
      inputSchema: z.object({ value: z.string() }),
      async execute(args) {
        return { echoed: args.value };
      },
    });

    const tool = getTool('test.echo')!;
    const result = await tool.execute({ value: 'ping' }, {} as never);
    expect(result).toEqual({ echoed: 'ping' });
  });
});
