/**
 * Appearance Resolver Utilities
 * 
 * Resolves FieldValue references to actual CSS values
 * Handles both global references and custom values
 * 
 * @since 1.5.0
 */

// ============================================================
// Types
// ============================================================

export interface FieldValue {
  type: 'global' | 'custom';
  value?: string;
  ref?: string;
}

export interface TypographyScale {
  fontFamily?: string;
  fontSize?: string;
  fontWeight?: string;
  lineHeight?: string;
  textTransform?: string;
  textAlign?: string;
  fontStyle?: string;
  textDecoration?: string;
  letterSpacing?: string;
  wordSpacing?: string;
  textShadow?: string;
}

export interface GlobalValues {
  colors?: {
    primary?: string;
    secondary?: string;
    accent?: string;
    text?: string;
    textSecondary?: string;
    textLight?: string;
    textMuted?: string;
    textSubtle?: string;
    background?: string;
    backgroundDark?: string;
    surface?: string;
    surfaceSubtle?: string;
    border?: string;
    success?: string;
    warning?: string;
    error?: string;
    transparent?: string;
    overlayLight?: string;
    borderSoft?: string;
    primaryHover?: string;
    primarySoft?: string;
    whatsappHover?: string;
    custom?: Array<{ name: string; value: string }>;
  };
  typography?: {
    fontFamily?: string;
    heading?: TypographyScale;
    headingLarge?: TypographyScale;
    headingMedium?: TypographyScale;
    headingSmall?: TypographyScale;
    body?: TypographyScale;
    bodyLarge?: TypographyScale;
    bodySmall?: TypographyScale;
    small?: TypographyScale;
    label?: TypographyScale;
    labelLarge?: TypographyScale;
    labelSmall?: TypographyScale;
    button?: TypographyScale;
    buttonLarge?: TypographyScale;
    buttonSmall?: TypographyScale;
    input?: TypographyScale;
    inputLarge?: TypographyScale;
    inputSmall?: TypographyScale;
    custom?: Array<{
      id: string;
      name: string;
    } & TypographyScale>;
  };
  effects?: {
    shadowSmall?: string;
    shadowMedium?: string;
    shadowLarge?: string;
    shadowAvatar?: string;
    transitionDuration?: string;
    transitionTiming?: string;
    borderRadiusSmall?: string;
    borderRadiusMedium?: string;
    borderRadiusLarge?: string;
    borderRadiusFull?: string;
    borderRadiusCircle?: string;
  };
  formFields?: {
    background?: string;
    text?: string;
    border?: string;
    focusBorder?: string;
    borderRadius?: string;
    padding?: string;
    placeholderColor?: string;
    labelColor?: string;
    errorColor?: string;
  };
  buttons?: {
    primary?: {
      background?: string;
      text?: string;
      hoverBackground?: string;
      borderRadius?: string;
      padding?: string;
    };
    secondary?: {
      background?: string;
      text?: string;
      hoverBackground?: string;
      borderRadius?: string;
      padding?: string;
    };
  };
  sizes?: Partial<Record<
    | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
    | 'borderThin'
    | 'iconXSmall' | 'iconSmall' | 'iconMedium' | 'iconLarge'
    | 'headerHeight' | 'avatarMedium' | 'avatarLarge' | 'avatarBorderWidth' | 'avatarIcon' | 'actionButton'
    | 'statusIndicator' | 'statusIndicatorBorder'
    | 'bubbleSize' | 'starRating' | 'emojiSize'
    | 'productImageHeight' | 'productImageMaxHeight' | 'galleryImageHeight' | 'textareaMin' | 'textareaMax'
    | 'windowWidth' | 'windowHeight' | 'messageMaxWidth',
    string
  >>;
  spacing?: Partial<Record<
    | 'none' | 'xxs' | 'xs' | 'xsPlus' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
    | 'containerTight' | 'containerNormal' | 'containerRelaxed' | 'containerSpacious',
    string
  >>;
}

// ============================================================
// Core Resolution Functions
// ============================================================

/**
 * Get nested value from object using dot notation path
 * e.g., "colors.primary" or "typography.heading.fontSize"
 */
function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
  const parts = path.split('.');
  let current: unknown = obj;
  
  for (const part of parts) {
    if (current === undefined || current === null) return undefined;
    if (typeof current !== 'object') return undefined;
    current = (current as Record<string, unknown>)[part];
  }
  
  return current;
}

/**
 * Resolve a FieldValue to its actual CSS value
 * 
 * @param field - The field value (can be FieldValue object, string, or undefined)
 * @param globalValues - The global values object for resolving references
 * @param defaultValue - Default value if resolution fails
 * @returns The resolved CSS value string
 */
export function resolveValue(
  field: FieldValue | string | undefined | null,
  globalValues: GlobalValues | undefined | null,
  defaultValue: string
): string {
  // Handle null/undefined
  if (field === null || field === undefined) {
    return defaultValue;
  }
  
  // Handle direct string values (legacy support)
  if (typeof field === 'string') {
    return field || defaultValue;
  }
  
  // Handle custom values
  if (field.type === 'custom') {
    return field.value || defaultValue;
  }
  
  // Handle global references
  if (field.type === 'global' && field.ref) {
    if (!globalValues) {
      return defaultValue;
    }
    
    const value = getNestedValue(globalValues as Record<string, unknown>, field.ref);
    
    // Handle direct string values
    if (typeof value === 'string') {
      return value || defaultValue;
    }
    
    // Handle numeric values (convert to string)
    if (typeof value === 'number') {
      return String(value);
    }
    
    return defaultValue;
  }
  
  return defaultValue;
}

/**
 * Resolve typography settings for an element
 * Returns a React.CSSProperties compatible object
 */
export function resolveTypography(
  typography: Record<string, FieldValue | undefined> | undefined,
  globalValues: GlobalValues | undefined | null,
  defaults: Partial<TypographyScale> = {}
): React.CSSProperties {
  if (!typography) {
    return {
      fontFamily: defaults.fontFamily || 'inherit',
      fontSize: defaults.fontSize || '14px',
      fontWeight: (defaults.fontWeight || '400') as React.CSSProperties['fontWeight'],
      lineHeight: defaults.lineHeight || '1.5',
    };
  }
  
  const textAlign =
    typography.textAlign !== undefined || defaults.textAlign !== undefined
      ? (resolveValue(typography.textAlign, globalValues, defaults.textAlign || 'start') as React.CSSProperties['textAlign'])
      : undefined;
  const textShadowResolved = resolveValue((typography as any).textShadow, globalValues, defaults.textShadow || 'none');

  return {
    fontFamily: resolveValue(typography.fontFamily, globalValues, defaults.fontFamily || 'inherit'),
    fontSize: resolveValue(typography.fontSize, globalValues, defaults.fontSize || '14px'),
    fontWeight: resolveValue(typography.fontWeight, globalValues, defaults.fontWeight || '400') as React.CSSProperties['fontWeight'],
    lineHeight: resolveValue(typography.lineHeight, globalValues, defaults.lineHeight || '1.5'),
    letterSpacing: resolveValue(typography.letterSpacing, globalValues, defaults.letterSpacing || 'normal'),
    textTransform: resolveValue(typography.textTransform, globalValues, defaults.textTransform || 'none') as React.CSSProperties['textTransform'],
    textAlign,
    fontStyle: resolveValue(typography.fontStyle, globalValues, defaults.fontStyle || 'normal') as React.CSSProperties['fontStyle'],
    textDecoration: resolveValue(typography.textDecoration, globalValues, defaults.textDecoration || 'none'),
    wordSpacing: resolveValue(typography.wordSpacing, globalValues, defaults.wordSpacing || 'normal'),
    textShadow: textShadowResolved && textShadowResolved !== 'none' ? textShadowResolved : undefined,
  };
}

// ============================================================
// Color Utilities
// ============================================================

/**
 * Adjust color brightness (for gradients and hover states)
 * 
 * @param color - Hex color string (e.g., "#3BC2D0")
 * @param amount - Amount to adjust (-255 to 255, negative = darker)
 * @returns Adjusted hex color string
 */
export function adjustColor(color: string, amount: number): string {
  // Handle invalid input
  if (!color || !color.startsWith('#')) {
    return color || '#000000';
  }
  
  const hex = color.replace('#', '');
  
  // Handle short hex (#RGB)
  const fullHex = hex.length === 3 
    ? hex.split('').map(c => c + c).join('')
    : hex;
  
  const num = parseInt(fullHex, 16);
  
  if (isNaN(num)) {
    return color;
  }
  
  const r = Math.min(255, Math.max(0, (num >> 16) + amount));
  const g = Math.min(255, Math.max(0, ((num >> 8) & 0x00FF) + amount));
  const b = Math.min(255, Math.max(0, (num & 0x0000FF) + amount));
  
  return `#${(1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1)}`;
}

/**
 * Create a gradient background from a single color
 */
export function createGradient(color: string, direction: string = '135deg'): string {
  return `linear-gradient(${direction}, ${color} 0%, ${adjustColor(color, -20)} 100%)`;
}

/**
 * Get contrasting text color (black or white) based on background
 */
export function getContrastColor(hexColor: string): string {
  if (!hexColor || !hexColor.startsWith('#')) {
    return '#000000';
  }
  
  const hex = hexColor.replace('#', '');
  const fullHex = hex.length === 3 
    ? hex.split('').map(c => c + c).join('')
    : hex;
  
  const r = parseInt(fullHex.slice(0, 2), 16);
  const g = parseInt(fullHex.slice(2, 4), 16);
  const b = parseInt(fullHex.slice(4, 6), 16);
  
  // Calculate luminance
  const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
  
  return luminance > 0.5 ? '#000000' : '#FFFFFF';
}

// ============================================================
// Batch Resolution
// ============================================================

/**
 * Resolve multiple field values at once
 */
export function resolveMultiple<T extends Record<string, FieldValue | string | undefined>>(
  fields: T,
  globalValues: GlobalValues | undefined | null,
  defaults: Record<keyof T, string>
): Record<keyof T, string> {
  const result = {} as Record<keyof T, string>;
  
  for (const key of Object.keys(fields) as Array<keyof T>) {
    result[key] = resolveValue(fields[key], globalValues, defaults[key]);
  }
  
  return result;
}

// ============================================================
// Default Values
// ============================================================

export const DEFAULT_GLOBAL_VALUES: GlobalValues = {
  colors: {
    primary: '#3BC2D0',
    secondary: '#E32774',
    accent: '#6366F1',
    text: '#1F2937',
    textSecondary: '#374151',
    textMuted: '#6B7280',
    background: '#FFFFFF',
    surface: '#F9FAFB',
    surfaceSubtle: '#F3F4F6',
    border: '#E5E7EB',
    success: '#10B981',
    warning: '#F59E0B',
    error: '#EF4444',
    custom: [],
  },
  typography: {
    fontFamily: '"Open Sans", sans-serif',
    heading: {
      fontFamily: '"Open Sans", sans-serif',
      fontSize: '18px',
      fontWeight: '600',
      lineHeight: '1.3',
    },
    body: {
      fontFamily: '"Open Sans", sans-serif',
      fontSize: '14px',
      fontWeight: '400',
      lineHeight: '1.5',
    },
    small: {
      fontFamily: '"Open Sans", sans-serif',
      fontSize: '12px',
      fontWeight: '400',
      lineHeight: '1.4',
    },
    button: {
      fontFamily: '"Open Sans", sans-serif',
      fontSize: '14px',
      fontWeight: '500',
      lineHeight: '1',
    },
  },
  effects: {
    shadowSmall: '0 1px 2px rgba(0,0,0,0.05)',
    shadowMedium: '0 4px 6px rgba(0,0,0,0.1)',
    shadowLarge: '0 10px 40px rgba(0,0,0,0.15)',
    transitionDuration: '200ms',
    transitionTiming: 'ease-out',
    borderRadiusSmall: '4px',
    borderRadiusMedium: '8px',
    borderRadiusLarge: '16px',
    borderRadiusFull: '9999px',
  },
  formFields: {
    background: '#FFFFFF',
    text: '#1F2937',
    border: '#E5E7EB',
    focusBorder: '#3BC2D0',
    borderRadius: '8px',
    padding: '12px 16px',
    placeholderColor: '#9CA3AF',
    labelColor: '#374151',
    errorColor: '#EF4444',
  },
};

// ============================================================
// Value Clamping - Prevent extreme values
// ============================================================

/**
 * Size limits for different element contexts
 * Prevents issues like 77px font size in headers
 */
export const SIZE_LIMITS = {
  fontSize: {
    header: { min: 10, max: 32 },
    body: { min: 10, max: 24 },
    small: { min: 8, max: 16 },
    button: { min: 10, max: 20 },
    default: { min: 8, max: 48 },
  },
  height: {
    header: { min: 40, max: 80 },
    chatWindow: { min: 300, max: 800 },
    chatBubble: { min: 40, max: 80 },
    image: { min: 80, max: 400 },
    default: { min: 20, max: 500 },
  },
  width: {
    chatWindow: { min: 280, max: 500 },
    default: { min: 50, max: 800 },
  },
  padding: {
    default: { min: 0, max: 50 },
  },
  borderRadius: {
    default: { min: 0, max: 50 },
  },
  lineHeight: {
    default: { min: 0.8, max: 3 },
  },
  letterSpacing: {
    default: { min: -5, max: 10 },
  },
};

type SizeContext = keyof typeof SIZE_LIMITS.fontSize;
type HeightContext = keyof typeof SIZE_LIMITS.height;
type WidthContext = keyof typeof SIZE_LIMITS.width;

/**
 * Parse a size value like "16px" to a number
 */
export function parseSize(value: string | undefined, defaultValue: number = 0): number {
  if (!value) return defaultValue;
  const num = parseFloat(value);
  return isNaN(num) ? defaultValue : num;
}

/**
 * Clamp a font size to safe limits
 */
export function clampFontSize(
  value: string | undefined,
  context: SizeContext = 'default',
  defaultValue: string = '14px'
): string {
  const limits = SIZE_LIMITS.fontSize[context] || SIZE_LIMITS.fontSize.default;
  const numValue = parseSize(value, parseSize(defaultValue));
  const clamped = Math.min(Math.max(numValue, limits.min), limits.max);
  return `${clamped}px`;
}

/**
 * Clamp a height value to safe limits
 */
export function clampHeight(
  value: string | undefined,
  context: HeightContext = 'default',
  defaultValue: string = '60px'
): string {
  const limits = SIZE_LIMITS.height[context] || SIZE_LIMITS.height.default;
  const numValue = parseSize(value, parseSize(defaultValue));
  const clamped = Math.min(Math.max(numValue, limits.min), limits.max);
  return `${clamped}px`;
}

/**
 * Clamp a width value to safe limits
 */
export function clampWidth(
  value: string | undefined,
  context: WidthContext = 'default',
  defaultValue: string = '380px'
): string {
  const limits = SIZE_LIMITS.width[context] || SIZE_LIMITS.width.default;
  const numValue = parseSize(value, parseSize(defaultValue));
  const clamped = Math.min(Math.max(numValue, limits.min), limits.max);
  return `${clamped}px`;
}

/**
 * Clamp a line height value to safe limits
 */
export function clampLineHeight(
  value: string | undefined,
  defaultValue: string = '1.5'
): string {
  const limits = SIZE_LIMITS.lineHeight.default;
  const numValue = parseFloat(value || defaultValue) || 1.5;
  const clamped = Math.min(Math.max(numValue, limits.min), limits.max);
  return clamped.toString();
}

/**
 * Clamp a resolved typography object to safe limits
 */
export function clampTypography(
  typography: React.CSSProperties,
  context: SizeContext = 'default'
): React.CSSProperties {
  return {
    ...typography,
    fontSize: clampFontSize(typography.fontSize as string | undefined, context),
    lineHeight: clampLineHeight(typography.lineHeight as string | undefined),
  };
}

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

/**
 * Check if a value is a FieldValue object
 */
export function isFieldValue(value: unknown): value is FieldValue {
  return (
    typeof value === 'object' &&
    value !== null &&
    'type' in value &&
    (value.type === 'global' || value.type === 'custom')
  );
}

/**
 * Check if a FieldValue is a global reference
 */
export function isGlobalRef(value: FieldValue): boolean {
  return value.type === 'global' && !!value.ref;
}

/**
 * Check if a FieldValue is a custom value
 */
export function isCustomValue(value: FieldValue): boolean {
  return value.type === 'custom';
}
