/**
 * JSON Schema Validation Module
 * Validates JSON structures to prevent injection attacks
 */

/**
 * User session schema
 */
export interface UserSessionSchema {
  username: string;
  loggedInAt: number;
  lastActivityAt: number;
  expiresAt: number;
  gatewayUrl?: string;
}

/**
 * Custom agent schema
 */
export interface CustomAgentSchema {
  id: string;
  name: string;
  systemPrompt?: string;
  temperature?: number;
  maxTokens?: number;
  topP?: number;
  frequencyPenalty?: number;
  presencePenalty?: number;
  tools?: string[];
  useLocalModel?: boolean;
  localModelProvider?: string;
  localModelName?: string;
  localModelUrl?: string;
}

/**
 * Custom tool schema
 */
export interface CustomToolSchema {
  id: string;
  name: string;
  description: string;
  code: string;
  createdAt?: number;
}

/**
 * Config schema
 */
export interface ConfigSchema {
  autoUpdate?: boolean;
  updateCheck?: boolean;
  [key: string]: any;
}

/**
 * Validate user session
 */
export function validateUserSession(data: any): { valid: boolean; error?: string; data?: UserSessionSchema } {
  if (typeof data !== 'object' || data === null) {
    return { valid: false, error: 'Session data must be an object' };
  }
  
  if (typeof data.username !== 'string' || data.username.length === 0) {
    return { valid: false, error: 'Invalid username' };
  }
  
  if (typeof data.loggedInAt !== 'number' || data.loggedInAt < 0) {
    return { valid: false, error: 'Invalid loggedInAt timestamp' };
  }
  
  if (typeof data.lastActivityAt !== 'number' || data.lastActivityAt < 0) {
    return { valid: false, error: 'Invalid lastActivityAt timestamp' };
  }
  
  if (typeof data.expiresAt !== 'number' || data.expiresAt < 0) {
    return { valid: false, error: 'Invalid expiresAt timestamp' };
  }
  
  if (data.gatewayUrl !== undefined && typeof data.gatewayUrl !== 'string') {
    return { valid: false, error: 'Invalid gatewayUrl' };
  }
  
  return {
    valid: true,
    data: {
      username: data.username,
      loggedInAt: data.loggedInAt,
      lastActivityAt: data.lastActivityAt,
      expiresAt: data.expiresAt,
      gatewayUrl: data.gatewayUrl,
    }
  };
}

/**
 * Validate custom agent
 */
export function validateCustomAgent(data: any): { valid: boolean; error?: string; data?: CustomAgentSchema } {
  if (typeof data !== 'object' || data === null) {
    return { valid: false, error: 'Agent data must be an object' };
  }
  
  if (typeof data.id !== 'string' || data.id.length === 0) {
    return { valid: false, error: 'Invalid agent id' };
  }
  
  if (typeof data.name !== 'string' || data.name.length === 0) {
    return { valid: false, error: 'Invalid agent name' };
  }
  
  if (data.systemPrompt !== undefined && typeof data.systemPrompt !== 'string') {
    return { valid: false, error: 'Invalid systemPrompt' };
  }
  
  if (data.temperature !== undefined && (typeof data.temperature !== 'number' || data.temperature < 0 || data.temperature > 2)) {
    return { valid: false, error: 'Invalid temperature (must be 0-2)' };
  }
  
  if (data.maxTokens !== undefined && (typeof data.maxTokens !== 'number' || data.maxTokens < 1 || data.maxTokens > 100000)) {
    return { valid: false, error: 'Invalid maxTokens (must be 1-100000)' };
  }
  
  if (data.topP !== undefined && (typeof data.topP !== 'number' || data.topP < 0 || data.topP > 1)) {
    return { valid: false, error: 'Invalid topP (must be 0-1)' };
  }
  
  if (data.tools !== undefined && !Array.isArray(data.tools)) {
    return { valid: false, error: 'tools must be an array' };
  }
  
  return {
    valid: true,
    data: {
      id: data.id,
      name: data.name,
      systemPrompt: data.systemPrompt,
      temperature: data.temperature,
      maxTokens: data.maxTokens,
      topP: data.topP,
      frequencyPenalty: data.frequencyPenalty,
      presencePenalty: data.presencePenalty,
      tools: data.tools,
      useLocalModel: data.useLocalModel,
      localModelProvider: data.localModelProvider,
      localModelName: data.localModelName,
      localModelUrl: data.localModelUrl,
    }
  };
}

/**
 * Validate custom tool
 */
export function validateCustomTool(data: any): { valid: boolean; error?: string; data?: CustomToolSchema } {
  if (typeof data !== 'object' || data === null) {
    return { valid: false, error: 'Tool data must be an object' };
  }
  
  if (typeof data.id !== 'string' || data.id.length === 0) {
    return { valid: false, error: 'Invalid tool id' };
  }
  
  if (typeof data.name !== 'string' || data.name.length === 0) {
    return { valid: false, error: 'Invalid tool name' };
  }
  
  if (typeof data.description !== 'string') {
    return { valid: false, error: 'Invalid tool description' };
  }
  
  if (typeof data.code !== 'string') {
    return { valid: false, error: 'Invalid tool code' };
  }
  
  // Limit code size (prevent DoS)
  if (data.code.length > 100000) {
    return { valid: false, error: 'Tool code too large (max 100KB)' };
  }
  
  return {
    valid: true,
    data: {
      id: data.id,
      name: data.name,
      description: data.description,
      code: data.code,
      createdAt: data.createdAt,
    }
  };
}

/**
 * Validate config
 */
export function validateConfig(data: any): { valid: boolean; error?: string; data?: ConfigSchema } {
  if (typeof data !== 'object' || data === null) {
    return { valid: false, error: 'Config data must be an object' };
  }
  
  if (data.autoUpdate !== undefined && typeof data.autoUpdate !== 'boolean') {
    return { valid: false, error: 'Invalid autoUpdate (must be boolean)' };
  }
  
  if (data.updateCheck !== undefined && typeof data.updateCheck !== 'boolean') {
    return { valid: false, error: 'Invalid updateCheck (must be boolean)' };
  }
  
  return {
    valid: true,
    data: data as ConfigSchema
  };
}

/**
 * Sanitize package name (prevent command injection)
 */
export function sanitizePackageName(name: string): { valid: boolean; error?: string; sanitized?: string } {
  // Package names must follow npm naming rules
  // Only lowercase letters, numbers, hyphens, underscores, dots, @, /
  const validPattern = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
  
  if (!validPattern.test(name)) {
    return { valid: false, error: 'Invalid package name format' };
  }
  
  // Block dangerous characters
  if (name.includes(';') || name.includes('&') || name.includes('|') || 
      name.includes('`') || name.includes('$') || name.includes('(') || 
      name.includes(')') || name.includes('<') || name.includes('>')) {
    return { valid: false, error: 'Package name contains dangerous characters' };
  }
  
  // Limit length
  if (name.length > 214) {
    return { valid: false, error: 'Package name too long (max 214 chars)' };
  }
  
  return { valid: true, sanitized: name };
}

/**
 * Safe JSON parse with validation
 */
export function safeJsonParse<T>(
  json: string,
  validator: (data: any) => { valid: boolean; error?: string; data?: T }
): { success: boolean; error?: string; data?: T } {
  try {
    const parsed = JSON.parse(json);
    const validation = validator(parsed);
    
    if (!validation.valid) {
      return { success: false, error: validation.error };
    }
    
    return { success: true, data: validation.data };
  } catch (error: any) {
    return { success: false, error: `JSON parse error: ${error.message}` };
  }
}
