/**
 * 统一精度和步进校验工具
 * 处理不同交易所的价格和数量精度要求
 */

export interface PrecisionConfig {
  tickSize: string // 价格步进
  stepSize: string // 数量步进
  minQty: string // 最小数量
  maxQty: string // 最大数量
  minNotional: string // 最小名义价值
  maxNotional?: string // 最大名义价值
  precision?: number // 精度位数
}

export interface ExchangeSymbolInfo {
  symbol: string
  status: string
  baseAsset: string
  quoteAsset: string
  precision: PrecisionConfig
}

export class PrecisionValidator {
  private static exchangeConfigs = new Map<string, Map<string, ExchangeSymbolInfo>>()

  /**
   * 更新交易所符号配置
   */
  static updateExchangeConfig(exchange: string, symbolsInfo: ExchangeSymbolInfo[]): void {
    const exchangeMap = new Map<string, ExchangeSymbolInfo>()
    symbolsInfo.forEach(info => {
      exchangeMap.set(info.symbol, info)
    })
    this.exchangeConfigs.set(exchange, exchangeMap)
  }

  /**
   * 获取符号精度配置
   */
  static getSymbolConfig(exchange: string, symbol: string): ExchangeSymbolInfo | null {
    const exchangeMap = this.exchangeConfigs.get(exchange)
    return exchangeMap?.get(symbol) || null
  }

  /**
   * 格式化价格到正确精度
   */
  static formatPrice(price: number | string, tickSize: string): string {
    const numPrice = Number(price)
    const numTickSize = Number(tickSize)

    if (numTickSize <= 0) return String(numPrice)

    // 计算精度位数
    const decimals = this.countDecimals(numTickSize)

    // 舍入到最近的tick
    const rounded = Math.floor(numPrice / numTickSize) * numTickSize

    return rounded.toFixed(decimals)
  }

  /**
   * 格式化数量到正确精度
   */
  static formatQuantity(quantity: number | string, stepSize: string): string {
    const numQuantity = Number(quantity)
    const numStepSize = Number(stepSize)

    if (numStepSize <= 0) return String(numQuantity)

    // 计算精度位数
    const decimals = this.countDecimals(numStepSize)

    // 舍入到最近的step
    const rounded = Math.floor(numQuantity / numStepSize) * numStepSize

    return rounded.toFixed(decimals)
  }

  /**
   * 验证订单参数
   */
  static validateOrder(
    exchange: string,
    symbol: string,
    price: string,
    quantity: string,
  ): { valid: boolean; errors: string[]; adjustedPrice?: string; adjustedQuantity?: string } {
    const config = this.getSymbolConfig(exchange, symbol)
    const errors: string[] = []

    if (!config) {
      return { valid: false, errors: [`未找到 ${exchange}:${symbol} 的配置信息`] }
    }

    const numPrice = Number(price)
    const numQuantity = Number(quantity)
    const numMinQty = Number(config.precision.minQty)
    const numMaxQty = Number(config.precision.maxQty)
    const numMinNotional = Number(config.precision.minNotional)

    // 验证数量范围
    if (numQuantity < numMinQty) {
      errors.push(`数量 ${quantity} 小于最小值 ${config.precision.minQty}`)
    }
    if (numMaxQty > 0 && numQuantity > numMaxQty) {
      errors.push(`数量 ${quantity} 超过最大值 ${config.precision.maxQty}`)
    }

    // 验证名义价值
    const notional = numPrice * numQuantity
    if (notional < numMinNotional) {
      errors.push(`名义价值 ${notional} 小于最小值 ${config.precision.minNotional}`)
    }

    // 格式化价格和数量
    const adjustedPrice = this.formatPrice(price, config.precision.tickSize)
    const adjustedQuantity = this.formatQuantity(quantity, config.precision.stepSize)

    // 检查是否需要调整
    if (adjustedPrice !== price) {
      errors.push(`价格已调整: ${price} -> ${adjustedPrice}`)
    }
    if (adjustedQuantity !== quantity) {
      errors.push(`数量已调整: ${quantity} -> ${adjustedQuantity}`)
    }

    return {
      valid: errors.length === 0,
      errors,
      adjustedPrice,
      adjustedQuantity,
    }
  }

  /**
   * 自动调整订单参数使其符合精度要求
   */
  static adjustOrderParams(
    exchange: string,
    symbol: string,
    price: number | string,
    quantity: number | string,
    direction: 'up' | 'down' = 'down',
  ): { price: string; quantity: string; valid: boolean; warnings: string[] } {
    const config = this.getSymbolConfig(exchange, symbol)
    const warnings: string[] = []

    if (!config) {
      return {
        price: String(price),
        quantity: String(quantity),
        valid: false,
        warnings: [`未找到 ${exchange}:${symbol} 的配置`],
      }
    }

    const adjustedPrice = this.formatPrice(price, config.precision.tickSize)
    let adjustedQuantity = this.formatQuantity(quantity, config.precision.stepSize)

    // 确保满足最小数量要求
    const numAdjustedQuantity = Number(adjustedQuantity)
    const numMinQty = Number(config.precision.minQty)

    if (numAdjustedQuantity < numMinQty) {
      adjustedQuantity = config.precision.minQty
      warnings.push(`数量调整到最小值: ${adjustedQuantity}`)
    }

    // 确保满足最小名义价值要求
    const notional = Number(adjustedPrice) * Number(adjustedQuantity)
    const numMinNotional = Number(config.precision.minNotional)

    if (notional < numMinNotional) {
      if (direction === 'up') {
        // 通过增加数量来满足最小名义价值
        const minQuantityForNotional = numMinNotional / Number(adjustedPrice)
        adjustedQuantity = this.formatQuantity(minQuantityForNotional, config.precision.stepSize)
        warnings.push(`为满足最小名义价值，数量调整为: ${adjustedQuantity}`)
      } else {
        warnings.push(`名义价值 ${notional} 低于最小值 ${numMinNotional}`)
      }
    }

    const validation = this.validateOrder(exchange, symbol, adjustedPrice, adjustedQuantity)

    return {
      price: adjustedPrice,
      quantity: adjustedQuantity,
      valid: validation.valid,
      warnings,
    }
  }

  /**
   * 批量调整多个订单
   */
  static adjustBatchOrders(
    exchange: string,
    orders: Array<{ symbol: string; price: number | string; quantity: number | string }>,
  ): Array<{ symbol: string; price: string; quantity: string; valid: boolean; warnings: string[] }> {
    return orders.map(order => ({
      symbol: order.symbol,
      ...this.adjustOrderParams(exchange, order.symbol, order.price, order.quantity),
    }))
  }

  /**
   * 计算小数位数
   */
  private static countDecimals(value: number | string): number {
    const str = String(value)
    const decimalIndex = str.indexOf('.')
    return decimalIndex >= 0 ? str.length - decimalIndex - 1 : 0
  }

  /**
   * 获取建议的订单参数
   */
  static getSuggestedOrderSize(
    exchange: string,
    symbol: string,
    targetNotional: number,
    currentPrice: number,
  ): { price: string; quantity: string; actualNotional: number } | null {
    const config = this.getSymbolConfig(exchange, symbol)
    if (!config) return null

    const baseQuantity = targetNotional / currentPrice
    const adjustedPrice = this.formatPrice(currentPrice, config.precision.tickSize)
    const adjustedQuantity = this.formatQuantity(baseQuantity, config.precision.stepSize)

    // 确保满足最小要求
    const result = this.adjustOrderParams(exchange, symbol, adjustedPrice, adjustedQuantity, 'up')

    return {
      price: result.price,
      quantity: result.quantity,
      actualNotional: Number(result.price) * Number(result.quantity),
    }
  }

  /**
   * 清理配置缓存
   */
  static clearCache(): void {
    this.exchangeConfigs.clear()
  }
}
