import { describe, it, expect } from 'vitest';
import {
  OfficialRegistryResponseSchema,
  GlamaRegistryResponseSchema,
  SmitheryRegistryResponseSchema,
  sanitizeString,
} from '../../src/registry/types.js';

describe('sanitizeString', () => {
  it('removes ANSI escape codes (\\x1b[)', () => {
    expect(sanitizeString('\x1b[31mRED\x1b[0m text')).toBe('RED text');
  });

  it('removes \\033[ style escape codes', () => {
    expect(sanitizeString('\x1b[1mBOLD\x1b[0m')).toBe('BOLD');
  });

  it('removes cursor movement codes', () => {
    expect(sanitizeString('\x1b[2J\x1b[Hscreen cleared')).toBe('screen cleared');
  });

  it('removes control characters', () => {
    expect(sanitizeString('hello\x07world')).toBe('helloworld');
  });

  it('preserves normal text', () => {
    expect(sanitizeString('A normal MCP server description.')).toBe('A normal MCP server description.');
  });

  it('preserves unicode characters', () => {
    expect(sanitizeString('Serveur MCP pour Slack 🚀')).toBe('Serveur MCP pour Slack 🚀');
  });

  it('handles empty string', () => {
    expect(sanitizeString('')).toBe('');
  });
});

describe('OfficialRegistryResponseSchema', () => {
  it('validates a correct response', () => {
    const valid = {
      servers: [{
        server: {
          name: 'io.github.test/slack-mcp',
          description: 'Slack integration',
          packages: [{
            registryType: 'npm',
            identifier: '@test/slack-mcp',
            transport: { type: 'stdio' },
            environmentVariables: [
              { name: 'SLACK_TOKEN', description: 'Bot token', isSecret: true },
            ],
          }],
        },
      }],
      metadata: { nextCursor: 'abc:1.0.0', count: 1 },
    };
    const result = OfficialRegistryResponseSchema.safeParse(valid);
    expect(result.success).toBe(true);
  });

  it('validates response with remotes', () => {
    const valid = {
      servers: [{
        server: {
          name: 'io.github.test/remote-mcp',
          remotes: [{
            type: 'sse',
            url: 'https://example.com/sse',
            headers: [{ name: 'Authorization', isSecret: true }],
          }],
        },
      }],
    };
    const result = OfficialRegistryResponseSchema.safeParse(valid);
    expect(result.success).toBe(true);
  });

  it('rejects response without servers array', () => {
    const result = OfficialRegistryResponseSchema.safeParse({ metadata: {} });
    expect(result.success).toBe(false);
  });

  it('rejects server without name', () => {
    const result = OfficialRegistryResponseSchema.safeParse({
      servers: [{ server: { description: 'no name' } }],
    });
    expect(result.success).toBe(false);
  });

  it('defaults missing optional fields', () => {
    const minimal = {
      servers: [{ server: { name: 'test/minimal' } }],
    };
    const result = OfficialRegistryResponseSchema.parse(minimal);
    expect(result.servers[0]?.server.packages).toEqual([]);
    expect(result.servers[0]?.server.remotes).toEqual([]);
    expect(result.servers[0]?.server.description).toBe('');
  });
});

describe('GlamaRegistryResponseSchema', () => {
  it('validates a correct response', () => {
    const valid = {
      servers: [{
        id: 'abc123',
        name: 'Slack MCP Server',
        description: 'Slack integration',
        attributes: ['hosting:local-only'],
        repository: { url: 'https://github.com/test/slack' },
        environmentVariablesJsonSchema: {
          type: 'object',
          properties: {
            SLACK_TOKEN: { type: 'string', description: 'Bot token' },
          },
          required: ['SLACK_TOKEN'],
        },
      }],
      pageInfo: {
        endCursor: 'xyz',
        hasNextPage: true,
        hasPreviousPage: false,
      },
    };
    const result = GlamaRegistryResponseSchema.safeParse(valid);
    expect(result.success).toBe(true);
  });

  it('rejects response without pageInfo', () => {
    const result = GlamaRegistryResponseSchema.safeParse({
      servers: [{ id: 'a', name: 'test' }],
    });
    expect(result.success).toBe(false);
  });

  it('defaults missing env schema properties', () => {
    const minimal = {
      servers: [{
        id: 'a',
        name: 'test',
        environmentVariablesJsonSchema: {},
      }],
      pageInfo: { hasNextPage: false, hasPreviousPage: false },
    };
    const result = GlamaRegistryResponseSchema.parse(minimal);
    const envSchema = result.servers[0]?.environmentVariablesJsonSchema;
    expect(envSchema?.properties).toEqual({});
    expect(envSchema?.required).toEqual([]);
  });
});

describe('SmitheryRegistryResponseSchema', () => {
  it('validates a correct response', () => {
    const valid = {
      servers: [{
        qualifiedName: 'slack',
        displayName: 'Slack',
        description: 'Slack integration',
        verified: true,
        useCount: 14062,
        remote: true,
      }],
      pagination: {
        currentPage: 1,
        pageSize: 10,
        totalPages: 5,
        totalCount: 50,
      },
    };
    const result = SmitheryRegistryResponseSchema.safeParse(valid);
    expect(result.success).toBe(true);
  });

  it('rejects response without pagination', () => {
    const result = SmitheryRegistryResponseSchema.safeParse({
      servers: [{ qualifiedName: 'test' }],
    });
    expect(result.success).toBe(false);
  });

  it('defaults useCount and verified', () => {
    const minimal = {
      servers: [{ qualifiedName: 'test' }],
      pagination: { currentPage: 1, pageSize: 10, totalPages: 1, totalCount: 1 },
    };
    const result = SmitheryRegistryResponseSchema.parse(minimal);
    expect(result.servers[0]?.useCount).toBe(0);
    expect(result.servers[0]?.verified).toBe(false);
  });
});
