import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';

export function assertNonEmptyString(entityName: string, fieldName: string, value: unknown): void {
  if (typeof value !== 'string' || value.trim().length === 0) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_string',
      message: `${fieldName} must be a non-empty string`,
    });
  }
}

export function assertOptionalStringOrNull(entityName: string, fieldName: string, value: unknown): void {
  if (value !== null && value !== undefined && typeof value !== 'string') {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_optional_string',
      message: `${fieldName} must be a string or null`,
    });
  }
}

export function assertDate(entityName: string, fieldName: string, value: unknown): void {
  if (!(value instanceof Date) || isNaN(value.getTime())) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_date',
      message: `${fieldName} must be a valid Date`,
    });
  }
}

export function assertOptionalDate(entityName: string, fieldName: string, value: unknown): void {
  if (value !== null && value !== undefined) {
    assertDate(entityName, fieldName, value);
  }
}

export function assertBoolean(entityName: string, fieldName: string, value: unknown): void {
  if (typeof value !== 'boolean') {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_boolean',
      message: `${fieldName} must be a boolean`,
    });
  }
}

export function assertInteger(entityName: string, fieldName: string, value: unknown): void {
  if (typeof value !== 'number' || !Number.isInteger(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_integer',
      message: `${fieldName} must be an integer`,
    });
  }
}

export function assertOptionalInteger(entityName: string, fieldName: string, value: unknown): void {
  if (value !== null && value !== undefined) {
    assertInteger(entityName, fieldName, value);
  }
}

export function assertStringArray(entityName: string, fieldName: string, value: unknown): void {
  if (!Array.isArray(value) || !value.every(item => typeof item === 'string')) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_string_array',
      message: `${fieldName} must be an array of strings`,
    });
  }
}

export function assertOptionalStringArray(entityName: string, fieldName: string, value: unknown): void {
  if (value !== null && value !== undefined) {
    assertStringArray(entityName, fieldName, value);
  }
}

export function assertObject(entityName: string, fieldName: string, value: unknown): void {
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_object',
      message: `${fieldName} must be an object`,
    });
  }
}

export function assertOptionalObject(entityName: string, fieldName: string, value: unknown): void {
  if (value !== null && value !== undefined) {
    assertObject(entityName, fieldName, value);
  }
}

export function assertNotificationType(entityName: string, fieldName: string, value: unknown): void {
  const validTypes = [
    'system_announcement',
    'race_reminder',
    'protest_filed',
    'protest_resolved',
    'penalty_applied',
    'performance_summary',
    'final_results',
    'sponsorship_approved',
    'friend_request',
    'message_received',
    'achievement_unlocked',
  ];
  
  if (typeof value !== 'string' || !validTypes.includes(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_notification_type',
      message: `${fieldName} must be one of: ${validTypes.join(', ')}`,
    });
  }
}

export function assertNotificationChannel(entityName: string, fieldName: string, value: unknown): void {
  const validChannels = ['in_app', 'email', 'discord', 'push'];
  
  if (typeof value !== 'string' || !validChannels.includes(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_notification_channel',
      message: `${fieldName} must be one of: ${validChannels.join(', ')}`,
    });
  }
}

export function assertNotificationStatus(entityName: string, fieldName: string, value: unknown): void {
  const validStatuses = ['unread', 'read', 'dismissed', 'action_required'];
  
  if (typeof value !== 'string' || !validStatuses.includes(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_notification_status',
      message: `${fieldName} must be one of: ${validStatuses.join(', ')}`,
    });
  }
}

export function assertNotificationUrgency(entityName: string, fieldName: string, value: unknown): void {
  const validUrgencies = ['silent', 'toast', 'modal'];
  
  if (typeof value !== 'string' || !validUrgencies.includes(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_notification_urgency',
      message: `${fieldName} must be one of: ${validUrgencies.join(', ')}`,
    });
  }
}

export function assertNotificationActions(entityName: string, fieldName: string, value: unknown): void {
  if (value === null || value === undefined) {
    return;
  }
  
  if (!Array.isArray(value)) {
    throw new TypeOrmPersistenceSchemaError({
      entityName,
      fieldName,
      reason: 'invalid_actions_array',
      message: `${fieldName} must be an array of action objects`,
    });
  }
  
  for (let i = 0; i < value.length; i++) {
    const action = value[i];
    if (typeof action !== 'object' || action === null) {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}[${i}]`,
        reason: 'invalid_action_object',
        message: `Action at index ${i} must be an object`,
      });
    }
    
    if (typeof action.label !== 'string' || action.label.trim().length === 0) {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}[${i}].label`,
        reason: 'invalid_action_label',
        message: `Action at index ${i} must have a non-empty label`,
      });
    }
    
    if (typeof action.type !== 'string' || !['primary', 'secondary', 'danger'].includes(action.type)) {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}[${i}].type`,
        reason: 'invalid_action_type',
        message: `Action at index ${i} must have type 'primary', 'secondary', or 'danger'`,
      });
    }
  }
}

export function assertChannelPreferences(entityName: string, fieldName: string, value: unknown): void {
  assertObject(entityName, fieldName, value);
  
  const channels = ['in_app', 'email', 'discord', 'push'];
  const obj = value as Record<string, unknown>;
  
  for (const channel of channels) {
    if (!(channel in obj)) {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}.${channel}`,
        reason: 'missing_channel',
        message: `Channel preferences must include ${channel}`,
      });
    }
    
    const pref = obj[channel];
    if (typeof pref !== 'object' || pref === null) {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}.${channel}`,
        reason: 'invalid_channel_preference',
        message: `Channel preference for ${channel} must be an object`,
      });
    }
    
    const prefObj = pref as Record<string, unknown>;
    if (typeof prefObj.enabled !== 'boolean') {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}.${channel}.enabled`,
        reason: 'invalid_enabled_flag',
        message: `Channel preference for ${channel} must have an enabled boolean`,
      });
    }
    
    if (prefObj.settings !== undefined && prefObj.settings !== null && typeof prefObj.settings !== 'object') {
      throw new TypeOrmPersistenceSchemaError({
        entityName,
        fieldName: `${fieldName}.${channel}.settings`,
        reason: 'invalid_settings',
        message: `Channel preference for ${channel} settings must be an object or null`,
      });
    }
  }
}