import { CreateExchangeRequest, CreateProviderMappingRequest } from '../types/exchange.types';

export class ValidationError extends Error {
  constructor(
    message: string,
    public field?: string
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

export function validateCreateExchange(data: unknown): CreateExchangeRequest {
  if (!data || typeof data !== 'object') {
    throw new ValidationError('Invalid data provided', 'data');
  }
  const { code, name, country, currency, active = true } = data as Record<string, unknown>;

  if (!code || typeof code !== 'string') {
    throw new ValidationError('Exchange code is required', 'code');
  }

  if (!name || typeof name !== 'string') {
    throw new ValidationError('Exchange name is required', 'name');
  }

  if (!country || typeof country !== 'string') {
    throw new ValidationError('Country is required', 'country');
  }

  if (!currency || typeof currency !== 'string') {
    throw new ValidationError('Currency is required', 'currency');
  }

  if (code.length > 10) {
    throw new ValidationError('Exchange code must be 10 characters or less', 'code');
  }

  if (country.length !== 2) {
    throw new ValidationError('Country must be exactly 2 characters (e.g., US, CA, GB)', 'country');
  }

  if (currency.length !== 3) {
    throw new ValidationError(
      'Currency must be exactly 3 characters (e.g., USD, EUR, CAD)',
      'currency'
    );
  }

  return {
    code: code.toUpperCase().trim(),
    name: name.trim(),
    country: country.toUpperCase().trim(),
    currency: currency.toUpperCase().trim(),
    active: Boolean(active),
  };
}

export function validateCreateProviderMapping(data: unknown): CreateProviderMappingRequest {
  if (!data || typeof data !== 'object') {
    throw new ValidationError('Invalid data provided', 'data');
  }
  const {
    provider,
    provider_exchange_code,
    provider_exchange_name,
    master_exchange_id,
    country_code,
    currency,
    confidence = 1.0,
    active = false,
    verified = false,
  } = data as Record<string, unknown>;

  if (!provider || typeof provider !== 'string') {
    throw new ValidationError('Provider is required', 'provider');
  }

  if (!provider_exchange_code || typeof provider_exchange_code !== 'string') {
    throw new ValidationError('Provider exchange code is required', 'provider_exchange_code');
  }

  if (!master_exchange_id || typeof master_exchange_id !== 'string') {
    throw new ValidationError('Master exchange ID is required', 'master_exchange_id');
  }

  // Validate currency is 3 characters or null
  const cleanCurrency = currency && currency.length <= 3 ? currency : null;

  return {
    provider: provider.trim(),
    provider_exchange_code: provider_exchange_code.trim(),
    provider_exchange_name: provider_exchange_name?.trim(),
    master_exchange_id: master_exchange_id.trim(),
    country_code: country_code?.trim() || null,
    currency: cleanCurrency,
    confidence: Number(confidence),
    active: Boolean(active),
    verified: Boolean(verified),
  };
}

export function validateUpdateExchange(data: unknown): Record<string, unknown> {
  if (!data || typeof data !== 'object') {
    throw new ValidationError('Invalid data provided', 'data');
  }
  const typedData = data as Record<string, unknown>;
  const updates: Record<string, unknown> = {};

  if (typedData.name !== undefined) {
    if (typeof typedData.name !== 'string') {
      throw new ValidationError('Name must be a string', 'name');
    }
    updates.name = typedData.name.trim();
  }

  if (typedData.active !== undefined) {
    updates.active = Boolean(typedData.active);
  }

  if (typedData.visible !== undefined) {
    updates.visible = Boolean(typedData.visible);
  }

  if (typedData.country !== undefined) {
    if (typeof typedData.country !== 'string' || typedData.country.length !== 2) {
      throw new ValidationError('Country must be exactly 2 characters', 'country');
    }
    updates.country = typedData.country.toUpperCase().trim();
  }

  if (typedData.currency !== undefined) {
    if (typeof typedData.currency !== 'string' || typedData.currency.length !== 3) {
      throw new ValidationError('Currency must be exactly 3 characters', 'currency');
    }
    updates.currency = typedData.currency.toUpperCase().trim();
  }

  if (Object.keys(updates).length === 0) {
    throw new ValidationError('No valid fields to update');
  }

  return updates;
}

export function validateUpdateProviderMapping(data: unknown): Record<string, unknown> {
  if (!data || typeof data !== 'object') {
    throw new ValidationError('Invalid data provided', 'data');
  }
  const typedData = data as Record<string, unknown>;
  const updates: Record<string, unknown> = {};

  if (typedData.active !== undefined) {
    updates.active = Boolean(typedData.active);
  }

  if (typedData.verified !== undefined) {
    updates.verified = Boolean(typedData.verified);
  }

  if (typedData.confidence !== undefined) {
    const confidence = Number(typedData.confidence);
    if (isNaN(confidence) || confidence < 0 || confidence > 1) {
      throw new ValidationError('Confidence must be a number between 0 and 1', 'confidence');
    }
    updates.confidence = confidence;
  }

  if (typedData.master_exchange_id !== undefined) {
    if (typeof typedData.master_exchange_id !== 'string') {
      throw new ValidationError('Master exchange ID must be a string', 'master_exchange_id');
    }
    updates.master_exchange_id = typedData.master_exchange_id.trim();
  }

  if (Object.keys(updates).length === 0) {
    throw new ValidationError('No valid fields to update');
  }

  return updates;
}
