// ================================================================
// AgentC Customer Chat Library - Type Guards & Validators
// ================================================================

import {
  Message,
  ChatSession,
  ChatError,
  DeviceInfo,
  DeviceType,
  ChatMode,
  ChatbotTheme,
  SupportedLanguage,
  UnifiedCustomerChatLibraryConfig,
  ApiConfig,
  ChatEvent,
  ChatEventType,
  CHAT_EVENTS
} from './types';

// ================================================================
// Core Type Guards
// ================================================================

export function isMessage(value: any): value is Message {
  return (
    typeof value === 'object' &&
    value !== null &&
    typeof value.id === 'string' &&
    typeof value.content === 'string' &&
    ['user', 'ai', 'system'].includes(value.sender) &&
    value.timestamp instanceof Date &&
    ['text', 'image', 'file', 'action'].includes(value.type)
  );
}

export function isChatSession(value: any): value is ChatSession {
  return (
    typeof value === 'object' &&
    value !== null &&
    typeof value.id === 'string' &&
    value.startTime instanceof Date &&
    value.lastActivity instanceof Date &&
    Array.isArray(value.messages) &&
    value.messages.every(isMessage) &&
    typeof value.context === 'object' &&
    ['active', 'ended', 'paused'].includes(value.status)
  );
}

export function isChatError(value: any): value is ChatError {
  return (
    typeof value === 'object' &&
    value !== null &&
    typeof value.code === 'string' &&
    typeof value.message === 'string' &&
    value.timestamp instanceof Date &&
    typeof value.recoverable === 'boolean'
  );
}

// ================================================================
// Device & Responsive Type Guards
// ================================================================

export function isDeviceType(value: any): value is DeviceType {
  return Object.values(DeviceType).includes(value);
}

export function isChatMode(value: any): value is ChatMode {
  return Object.values(ChatMode).includes(value);
}

export function isDeviceInfo(value: any): value is DeviceInfo {
  return (
    typeof value === 'object' &&
    value !== null &&
    isDeviceType(value.type) &&
    typeof value.screenWidth === 'number' &&
    typeof value.screenHeight === 'number' &&
    ['portrait', 'landscape'].includes(value.orientation) &&
    typeof value.isTouchDevice === 'boolean' &&
    typeof value.isKeyboardVisible === 'boolean' &&
    typeof value.userAgent === 'string' &&
    typeof value.pixelRatio === 'number'
  );
}

// ================================================================
// Configuration Type Guards
// ================================================================

export function isApiConfig(value: any): value is ApiConfig {
  return (
    typeof value === 'object' &&
    value !== null &&
    (value.baseUrl === undefined || typeof value.baseUrl === 'string') &&
    (value.apiKey === undefined || typeof value.apiKey === 'string') &&
    (value.timeout === undefined || typeof value.timeout === 'number') &&
    (value.retryAttempts === undefined || typeof value.retryAttempts === 'number')
  );
}

export function isSupportedLanguage(value: any): value is SupportedLanguage {
  const supportedLanguages: SupportedLanguage[] = ['ko', 'en', 'ja', 'zh', 'es', 'fr', 'de'];
  return supportedLanguages.includes(value);
}

export function isChatbotTheme(value: any): value is ChatbotTheme {
  return (
    typeof value === 'object' &&
    value !== null &&
    typeof value.primary === 'string' &&
    typeof value.secondary === 'string' &&
    typeof value.background === 'string' &&
    typeof value.surface === 'string' &&
    typeof value.text === 'object' &&
    typeof value.text.primary === 'string' &&
    typeof value.text.secondary === 'string' &&
    typeof value.text.inverse === 'string'
  );
}

// ================================================================
// Event Type Guards
// ================================================================

export function isChatEvent(value: any): value is ChatEvent {
  return (
    typeof value === 'object' &&
    value !== null &&
    typeof value.type === 'string' &&
    value.timestamp instanceof Date &&
    value.data !== undefined
  );
}

export function isChatEventType(value: any): value is ChatEventType {
  return Object.values(CHAT_EVENTS).includes(value);
}

// ================================================================
// Configuration Validators
// ================================================================

export function validateUnifiedChatLibraryConfig(
  config: Partial<UnifiedCustomerChatLibraryConfig>
): { isValid: boolean; errors: string[] } {
  const errors: string[] = [];

  // Validate breakpoints
  if (config.mobileBreakpoint !== undefined) {
    if (typeof config.mobileBreakpoint !== 'number' || config.mobileBreakpoint <= 0) {
      errors.push('mobileBreakpoint must be a positive number');
    }
  }

  if (config.tabletBreakpoint !== undefined) {
    if (typeof config.tabletBreakpoint !== 'number' || config.tabletBreakpoint <= 0) {
      errors.push('tabletBreakpoint must be a positive number');
    }
  }

  if (config.desktopBreakpoint !== undefined) {
    if (typeof config.desktopBreakpoint !== 'number' || config.desktopBreakpoint <= 0) {
      errors.push('desktopBreakpoint must be a positive number');
    }
  }

  // Validate chat mode
  if (config.defaultChatMode !== undefined && !isChatMode(config.defaultChatMode)) {
    errors.push('defaultChatMode must be a valid ChatMode');
  }

  // Validate API config
  if (config.api !== undefined && !isApiConfig(config.api)) {
    errors.push('api configuration is invalid');
  }

  // Validate UI config
  if (config.ui !== undefined) {
    if (typeof config.ui !== 'object') {
      errors.push('ui configuration must be an object');
    } else {
      if (config.ui.theme !== undefined && 
          typeof config.ui.theme !== 'string' && 
          !isChatbotTheme(config.ui.theme)) {
        errors.push('ui.theme must be a theme name or ChatbotTheme object');
      }
      
      if (config.ui.brandName !== undefined && typeof config.ui.brandName !== 'string') {
        errors.push('ui.brandName must be a string');
      }
    }
  }

  // Validate i18n config
  if (config.i18n !== undefined) {
    if (typeof config.i18n !== 'object') {
      errors.push('i18n configuration must be an object');
    } else {
      if (config.i18n.defaultLanguage !== undefined && 
          !isSupportedLanguage(config.i18n.defaultLanguage)) {
        errors.push('i18n.defaultLanguage must be a supported language');
      }
    }
  }

  return {
    isValid: errors.length === 0,
    errors
  };
}

// ================================================================
// Runtime Type Checking Utilities
// ================================================================

export function assertIsMessage(value: any, context?: string): asserts value is Message {
  if (!isMessage(value)) {
    throw new TypeError(`Expected Message${context ? ` in ${context}` : ''}, got ${typeof value}`);
  }
}

export function assertIsChatSession(value: any, context?: string): asserts value is ChatSession {
  if (!isChatSession(value)) {
    throw new TypeError(`Expected ChatSession${context ? ` in ${context}` : ''}, got ${typeof value}`);
  }
}

export function assertIsDeviceInfo(value: any, context?: string): asserts value is DeviceInfo {
  if (!isDeviceInfo(value)) {
    throw new TypeError(`Expected DeviceInfo${context ? ` in ${context}` : ''}, got ${typeof value}`);
  }
}

export function assertIsChatMode(value: any, context?: string): asserts value is ChatMode {
  if (!isChatMode(value)) {
    throw new TypeError(`Expected ChatMode${context ? ` in ${context}` : ''}, got ${typeof value}`);
  }
}

// ================================================================
// Validation Helpers
// ================================================================

export function isValidUrl(url: string): boolean {
  try {
    new URL(url);
    return true;
  } catch {
    return false;
  }
}

export function isValidApiKey(apiKey: string): boolean {
  return typeof apiKey === 'string' && apiKey.length > 0 && apiKey.trim() === apiKey;
}

export function isValidEmailAddress(email: string): boolean {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

export function isValidSessionId(sessionId: string): boolean {
  return typeof sessionId === 'string' && sessionId.length > 0 && !/\s/.test(sessionId);
}

export function isValidMessageContent(content: string): boolean {
  return typeof content === 'string' && content.trim().length > 0;
}

// ================================================================
// Data Sanitization
// ================================================================

export function sanitizeMessage(message: Partial<Message>): Message | null {
  try {
    if (!message.content || !isValidMessageContent(message.content)) {
      return null;
    }

    const sanitized: Message = {
      id: message.id || `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      content: message.content.trim(),
      sender: ['user', 'ai', 'system'].includes(message.sender as any) ? message.sender as any : 'user',
      timestamp: message.timestamp instanceof Date ? message.timestamp : new Date(),
      type: ['text', 'image', 'file', 'action'].includes(message.type as any) ? message.type as any : 'text',
      metadata: typeof message.metadata === 'object' ? message.metadata : undefined,
      status: ['sending', 'sent', 'delivered', 'read', 'error'].includes(message.status as any) 
        ? message.status as any 
        : 'sent'
    };

    return isMessage(sanitized) ? sanitized : null;
  } catch (error) {
    console.error('Error sanitizing message:', error);
    return null;
  }
}

export function sanitizeApiConfig(config: Partial<ApiConfig>): ApiConfig {
  const sanitized: ApiConfig = {};

  if (config.baseUrl && typeof config.baseUrl === 'string' && isValidUrl(config.baseUrl)) {
    sanitized.baseUrl = config.baseUrl.replace(/\/$/, ''); // Remove trailing slash
  }

  if (config.apiKey && isValidApiKey(config.apiKey)) {
    sanitized.apiKey = config.apiKey;
  }

  if (typeof config.timeout === 'number' && config.timeout > 0) {
    sanitized.timeout = Math.min(config.timeout, 60000); // Max 60 seconds
  }

  if (typeof config.retryAttempts === 'number' && config.retryAttempts >= 0) {
    sanitized.retryAttempts = Math.min(config.retryAttempts, 5); // Max 5 retries
  }

  if (config.headers && typeof config.headers === 'object') {
    sanitized.headers = { ...config.headers };
  }

  return sanitized;
}

// ================================================================
// Performance Validation
// ================================================================

export function validatePerformanceConfig(config: any): boolean {
  return (
    typeof config === 'object' &&
    typeof config.enableOptimization === 'boolean' &&
    typeof config.memoryThreshold === 'number' &&
    config.memoryThreshold > 0 &&
    config.memoryThreshold <= 1 &&
    typeof config.maxCacheSize === 'number' &&
    config.maxCacheSize > 0
  );
}

export function validateAccessibilityConfig(config: any): boolean {
  return (
    typeof config === 'object' &&
    typeof config.enableScreenReader === 'boolean' &&
    typeof config.enableKeyboardNavigation === 'boolean' &&
    typeof config.enableHighContrast === 'boolean' &&
    typeof config.enableFocusVisible === 'boolean' &&
    typeof config.ariaLabels === 'object'
  );
}

// ================================================================
// Error Handling
// ================================================================

export class ChatLibraryTypeError extends Error {
  constructor(
    message: string,
    public readonly expectedType: string,
    public readonly actualType: string,
    public readonly context?: string
  ) {
    super(message);
    this.name = 'ChatLibraryTypeError';
  }
}

export function createTypeError(
  expectedType: string,
  actualValue: any,
  context?: string
): ChatLibraryTypeError {
  const actualType = actualValue === null ? 'null' : typeof actualValue;
  const message = `Expected ${expectedType}${context ? ` in ${context}` : ''}, got ${actualType}`;
  return new ChatLibraryTypeError(message, expectedType, actualType, context);
}

// ================================================================
// Development Helpers
// ================================================================

export function logTypeValidation(value: any, typeName: string, isValid: boolean): void {
  if (process.env.NODE_ENV === 'development') {
    console.log(`Type validation for ${typeName}:`, {
      value,
      isValid,
      type: typeof value,
      constructor: value?.constructor?.name
    });
  }
}

export function validateAndLog<T>(
  value: any,
  validator: (val: any) => val is T,
  typeName: string
): value is T {
  const isValid = validator(value);
  logTypeValidation(value, typeName, isValid);
  return isValid;
}