import { z } from 'zod';

// ── Normalized types used throughout mcpctl ──

export interface EnvVar {
  name: string;
  description: string;
  isSecret: boolean;
  setupUrl?: string;
  defaultValue?: string;
}

export interface RegistryServer {
  name: string;
  description: string;
  packages: {
    npm?: string;
    pypi?: string;
    docker?: string;
  };
  envTemplate: EnvVar[];
  transport: 'stdio' | 'sse' | 'streamable-http';
  repositoryUrl?: string;
  popularityScore: number;
  verified: boolean;
  sourceRegistry: 'official' | 'glama' | 'smithery';
  lastUpdated?: Date;
}

export interface SearchOptions {
  query: string;
  limit?: number;
  registries?: RegistryName[];
  verified?: boolean;
  transport?: 'stdio' | 'sse';
  category?: string;
}

export type RegistryName = 'official' | 'glama' | 'smithery';

export interface RegistryClientConfig {
  registries?: RegistryName[];
  cacheTTLMs?: number;
  smitheryApiKey?: string;
  httpProxy?: string;
  httpsProxy?: string;
}

// ── Zod schemas for API response validation ──

// Official MCP Registry
const OfficialEnvVarSchema = z.object({
  name: z.string(),
  description: z.string().optional().default(''),
  format: z.string().optional(),
  isSecret: z.boolean().optional().default(false),
});

const OfficialPackageSchema = z.object({
  registryType: z.string(),
  identifier: z.string(),
  version: z.string().optional(),
  runtimeHint: z.string().optional(),
  transport: z.object({
    type: z.string(),
  }).optional(),
  environmentVariables: z.array(OfficialEnvVarSchema).optional().default([]),
});

const OfficialRemoteSchema = z.object({
  type: z.string(),
  url: z.string(),
  headers: z.array(z.object({
    name: z.string(),
    description: z.string().optional().default(''),
    value: z.string().optional(),
    isRequired: z.boolean().optional(),
    isSecret: z.boolean().optional(),
  })).optional().default([]),
});

const OfficialServerSchema = z.object({
  server: z.object({
    name: z.string(),
    title: z.string().optional(),
    description: z.string().optional().default(''),
    version: z.string().optional(),
    repository: z.object({
      url: z.string(),
      source: z.string().optional(),
      subfolder: z.string().optional(),
    }).optional(),
    packages: z.array(OfficialPackageSchema).optional().default([]),
    remotes: z.array(OfficialRemoteSchema).optional().default([]),
  }),
  _meta: z.record(z.unknown()).optional(),
});

export const OfficialRegistryResponseSchema = z.object({
  servers: z.array(OfficialServerSchema),
  metadata: z.object({
    nextCursor: z.string().nullable().optional(),
    count: z.number().optional(),
  }).optional(),
});

// Glama.ai
const GlamaServerSchema = z.object({
  id: z.string(),
  name: z.string(),
  namespace: z.string().optional().default(''),
  slug: z.string().optional().default(''),
  description: z.string().optional().default(''),
  url: z.string().optional(),
  attributes: z.array(z.string()).optional().default([]),
  repository: z.object({
    url: z.string(),
  }).optional(),
  environmentVariablesJsonSchema: z.object({
    type: z.string().optional(),
    properties: z.record(z.object({
      type: z.string().optional(),
      description: z.string().optional(),
      default: z.string().optional(),
    })).optional().default({}),
    required: z.array(z.string()).optional().default([]),
  }).optional(),
});

export const GlamaRegistryResponseSchema = z.object({
  servers: z.array(GlamaServerSchema),
  pageInfo: z.object({
    startCursor: z.string().nullable().optional(),
    endCursor: z.string().nullable().optional(),
    hasNextPage: z.boolean(),
    hasPreviousPage: z.boolean(),
  }),
});

// Smithery.ai
const SmitheryServerSchema = z.object({
  qualifiedName: z.string(),
  displayName: z.string().optional().default(''),
  description: z.string().optional().default(''),
  iconUrl: z.string().optional(),
  verified: z.boolean().optional().default(false),
  useCount: z.number().optional().default(0),
  remote: z.boolean().optional().default(false),
  isDeployed: z.boolean().optional().default(false),
  createdAt: z.string().optional(),
  homepage: z.string().optional(),
  score: z.number().optional().default(0),
});

export const SmitheryRegistryResponseSchema = z.object({
  servers: z.array(SmitheryServerSchema),
  pagination: z.object({
    currentPage: z.number(),
    pageSize: z.number(),
    totalPages: z.number(),
    totalCount: z.number(),
  }),
});

// ── Inferred types from Zod schemas ──

export type OfficialRegistryResponse = z.infer<typeof OfficialRegistryResponseSchema>;
export type OfficialServerEntry = z.infer<typeof OfficialServerSchema>;
export type GlamaRegistryResponse = z.infer<typeof GlamaRegistryResponseSchema>;
export type GlamaServerEntry = z.infer<typeof GlamaServerSchema>;
export type SmitheryRegistryResponse = z.infer<typeof SmitheryRegistryResponseSchema>;
export type SmitheryServerEntry = z.infer<typeof SmitheryServerSchema>;

// ── Security utilities ──

const ANSI_ESCAPE_RE = /\x1b\[[0-9;]*[a-zA-Z]|[\x00-\x08\x0B\x0C\x0E-\x1A\x1C-\x1F]|\x1b/g;

export function sanitizeString(text: string): string {
  return text.replace(ANSI_ESCAPE_RE, '');
}
