import WebSocket from 'ws'
import { EventEmitter } from 'events'
import { logger } from '../../utils/logger.js'

interface PacificaOrderbookEntry {
  p: string  // Price (highest bid or lowest ask)
  a: string  // Total amount at price level
  n: number  // Number of orders at price level
}

interface PacificaOrderbook {
  symbol: string
  bids: PacificaOrderbookEntry[]
  asks: PacificaOrderbookEntry[]
  timestamp: number
}

interface PacificaOrderbookUpdate {
  channel: string
  data: {
    l: [PacificaOrderbookEntry[], PacificaOrderbookEntry[]]  // [bids, asks]
    s: string  // Symbol
    t: number  // Timestamp
  }
}

export interface PacificaWebSocketOrderbookConfig {
  wsUrl: string
  symbols: string[]
  aggLevel?: number  // 1, 2, 5, 10, 100, 1000
  reconnectInterval?: number
  maxReconnectAttempts?: number
  heartbeatInterval?: number
}

/**
 * Pacifica专用WebSocket订单簿服务
 * 基于官方API文档实现实时订单簿数据获取
 */
export class PacificaWebSocketOrderbookService extends EventEmitter {
  private ws: WebSocket | null = null
  private config: Required<PacificaWebSocketOrderbookConfig>
  private orderbooks: Map<string, PacificaOrderbook> = new Map()
  private reconnectAttempts = 0
  private isConnected = false
  private heartbeatTimer: NodeJS.Timeout | null = null
  private reconnectTimer: NodeJS.Timeout | null = null
  private lastHeartbeat = Date.now()
  private subscriptionIds: Map<string, number> = new Map()

  constructor(config: PacificaWebSocketOrderbookConfig) {
    super()

    this.config = {
      wsUrl: config.wsUrl,
      symbols: config.symbols,
      aggLevel: config.aggLevel || 1,
      reconnectInterval: config.reconnectInterval || 5000,
      maxReconnectAttempts: config.maxReconnectAttempts || 10,
      heartbeatInterval: config.heartbeatInterval || 30000
    }

    logger.info('🌊 PacificaWebSocketOrderbookService 已创建', {
      wsUrl: this.config.wsUrl,
      symbols: this.config.symbols,
      aggLevel: this.config.aggLevel
    })
  }

  /**
   * 启动WebSocket连接并开始接收orderbook数据
   */
  async start(): Promise<void> {
    logger.info('🚀 启动Pacifica WebSocket orderbook服务...')

    try {
      await this.connect()
      this.startHeartbeat()
      logger.info('✅ Pacifica WebSocket orderbook服务启动成功')
    } catch (error: any) {
      logger.error('❌ Pacifica WebSocket orderbook服务启动失败:', error)
      throw error
    }
  }

  /**
   * 停止WebSocket连接和服务
   */
  async stop(): Promise<void> {
    logger.info('🛑 停止Pacifica WebSocket orderbook服务...')

    this.stopHeartbeat()
    this.stopReconnectTimer()

    if (this.ws) {
      this.ws.close()
      this.ws = null
    }

    this.isConnected = false
    this.orderbooks.clear()
    this.subscriptionIds.clear()
    logger.info('✅ Pacifica WebSocket orderbook服务已停止')
  }

  /**
   * 建立WebSocket连接
   */
  private async connect(): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        // 直接连接Pacifica WebSocket，不使用代理
        this.ws = new WebSocket(this.config.wsUrl, {
          headers: {
            'User-Agent': 'Pacifica-Trading-Bot/1.0'
          }
        })

        this.ws.on('open', () => {
          logger.info('🔗 Pacifica WebSocket连接已建立')
          this.isConnected = true
          this.reconnectAttempts = 0
          this.lastHeartbeat = Date.now()

          // 订阅orderbook数据
          this.subscribeToOrderbooks()
          resolve()
        })

        this.ws.on('message', (data: Buffer) => {
          try {
            const message = JSON.parse(data.toString())
            this.handleMessage(message)
            this.lastHeartbeat = Date.now()
          } catch (error: any) {
            logger.error('解析Pacifica WebSocket消息失败:', error)
          }
        })

        this.ws.on('close', (code: number, reason: string) => {
          logger.warn('Pacifica WebSocket连接已关闭', { code, reason: reason.toString() })
          this.isConnected = false

          if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
            this.scheduleReconnect()
          } else {
            logger.error('❌ Pacifica WebSocket重连次数已达上限，停止重连')
            this.emit('error', new Error('Pacifica WebSocket重连失败'))
          }
        })

        this.ws.on('error', (error: Error) => {
          logger.error('Pacifica WebSocket连接错误:', error)
          this.isConnected = false

          if (this.reconnectAttempts === 0) {
            reject(error)
          }
        })

        this.ws.on('ping', () => {
          this.ws?.pong()
          this.lastHeartbeat = Date.now()
        })

      } catch (error: any) {
        logger.error('创建Pacifica WebSocket连接失败:', error)
        reject(error)
      }
    })
  }

  /**
   * 订阅orderbook数据流 (按照Pacifica API格式)
   */
  private subscribeToOrderbooks(): void {
    if (!this.ws || !this.isConnected) {
      logger.error('Pacifica WebSocket未连接，无法订阅orderbook')
      return
    }

    for (const symbol of this.config.symbols) {
      const subscriptionId = Date.now() + Math.random()
      this.subscriptionIds.set(symbol, subscriptionId)

      const subscribeMessage = {
        method: 'subscribe',
        params: {
          source: 'book',
          symbol: symbol,
          agg_level: this.config.aggLevel
        },
        id: subscriptionId
      }

      logger.info('📊 订阅Pacifica orderbook数据:', { symbol, message: subscribeMessage })
      this.ws.send(JSON.stringify(subscribeMessage))
    }
  }

  /**
   * 处理WebSocket消息
   */
  private handleMessage(message: any): void {
    try {
      // 处理订阅确认
      if (message.result === 'success' && message.id) {
        logger.info('✅ Pacifica orderbook订阅确认:', message)
        return
      }

      // 处理orderbook更新
      if (message.channel === 'book' && message.data) {
        this.processOrderbookUpdate(message as PacificaOrderbookUpdate)
      }

    } catch (error: any) {
      logger.error('处理Pacifica WebSocket消息失败:', error)
    }
  }

  /**
   * 处理orderbook更新
   */
  private processOrderbookUpdate(update: PacificaOrderbookUpdate): void {
    try {
      const { data } = update
      const symbol = data.s
      const timestamp = data.t
      const [bids, asks] = data.l

      // 构建orderbook
      const orderbook: PacificaOrderbook = {
        symbol,
        bids: bids.map(entry => ({
          p: entry.p,
          a: entry.a,
          n: entry.n
        })).filter(entry => parseFloat(entry.a) > 0), // 过滤掉0数量的条目

        asks: asks.map(entry => ({
          p: entry.p,
          a: entry.a,
          n: entry.n
        })).filter(entry => parseFloat(entry.a) > 0), // 过滤掉0数量的条目

        timestamp
      }

      // 按价格排序
      orderbook.bids.sort((a, b) => parseFloat(b.p) - parseFloat(a.p)) // 买单按价格从高到低
      orderbook.asks.sort((a, b) => parseFloat(a.p) - parseFloat(b.p)) // 卖单按价格从低到高

      // 更新orderbook缓存
      this.orderbooks.set(symbol, orderbook)

      // 发出orderbook更新事件
      this.emit('orderbook', orderbook)

      logger.debug('📈 Pacifica orderbook已更新:', {
        symbol,
        bidsCount: orderbook.bids.length,
        asksCount: orderbook.asks.length,
        bestBid: orderbook.bids[0]?.p,
        bestAsk: orderbook.asks[0]?.p,
        timestamp
      })

    } catch (error: any) {
      logger.error('处理Pacifica orderbook更新失败:', error)
    }
  }

  /**
   * 获取指定symbol的orderbook
   */
  getOrderbook(symbol: string): PacificaOrderbook | null {
    return this.orderbooks.get(symbol.toUpperCase()) || null
  }

  /**
   * 获取所有orderbook
   */
  getAllOrderbooks(): Map<string, PacificaOrderbook> {
    return new Map(this.orderbooks)
  }

  /**
   * 获取最佳买卖价
   */
  getBestPrices(symbol: string): { bestBid: number; bestAsk: number; spread: number } | null {
    const orderbook = this.getOrderbook(symbol)
    if (!orderbook || orderbook.bids.length === 0 || orderbook.asks.length === 0) {
      return null
    }

    const bestBid = parseFloat(orderbook.bids[0].p)
    const bestAsk = parseFloat(orderbook.asks[0].p)
    const spread = (bestAsk - bestBid) / bestBid

    return { bestBid, bestAsk, spread }
  }

  /**
   * 计算指定深度的平均价格
   */
  getDepthAveragePrice(symbol: string, side: 'bid' | 'ask', usdAmount: number): number | null {
    const orderbook = this.getOrderbook(symbol)
    if (!orderbook) return null

    const entries = side === 'bid' ? orderbook.bids : orderbook.asks
    let totalValue = 0
    let totalSize = 0
    let remainingUsd = usdAmount

    for (const entry of entries) {
      if (remainingUsd <= 0) break

      const price = parseFloat(entry.p)
      const size = parseFloat(entry.a)
      const entryUsdValue = price * size
      const usedUsdValue = Math.min(entryUsdValue, remainingUsd)
      const usedSize = usedUsdValue / price

      totalValue += usedUsdValue
      totalSize += usedSize
      remainingUsd -= usedUsdValue
    }

    return totalSize > 0 ? totalValue / totalSize : null
  }

  /**
   * 启动心跳检测
   */
  private startHeartbeat(): void {
    this.heartbeatTimer = setInterval(() => {
      const now = Date.now()
      const timeSinceLastHeartbeat = now - this.lastHeartbeat

      if (timeSinceLastHeartbeat > this.config.heartbeatInterval * 2) {
        logger.warn('Pacifica心跳超时，准备重连...', {
          timeSinceLastHeartbeat,
          heartbeatInterval: this.config.heartbeatInterval
        })

        this.scheduleReconnect()
      } else if (this.ws && this.isConnected) {
        // 发送ping
        this.ws.ping()
      }
    }, this.config.heartbeatInterval)
  }

  /**
   * 停止心跳检测
   */
  private stopHeartbeat(): void {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer)
      this.heartbeatTimer = null
    }
  }

  /**
   * 安排重连
   */
  private scheduleReconnect(): void {
    if (this.reconnectTimer) return // 避免重复安排

    this.reconnectAttempts++
    const delay = this.config.reconnectInterval * Math.pow(2, Math.min(this.reconnectAttempts - 1, 5)) // 指数退避

    logger.info(`⏰ 安排Pacifica重连 (${this.reconnectAttempts}/${this.config.maxReconnectAttempts})，延迟: ${delay}ms`)

    this.reconnectTimer = setTimeout(async () => {
      this.reconnectTimer = null

      if (this.ws) {
        this.ws.close()
        this.ws = null
      }

      try {
        await this.connect()
        this.startHeartbeat()
        logger.info('✅ Pacifica WebSocket重连成功')
      } catch (error: any) {
        logger.error('❌ Pacifica WebSocket重连失败:', error)
      }
    }, delay)
  }

  /**
   * 停止重连定时器
   */
  private stopReconnectTimer(): void {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer)
      this.reconnectTimer = null
    }
  }

  /**
   * 获取连接状态
   */
  isServiceConnected(): boolean {
    return this.isConnected && this.ws?.readyState === WebSocket.OPEN
  }

  /**
   * 获取服务统计
   */
  getStats(): {
    isConnected: boolean
    orderbooksCount: number
    symbols: string[]
    reconnectAttempts: number
    lastHeartbeat: number
    aggLevel: number
  } {
    return {
      isConnected: this.isConnected,
      orderbooksCount: this.orderbooks.size,
      symbols: Array.from(this.orderbooks.keys()),
      reconnectAttempts: this.reconnectAttempts,
      lastHeartbeat: this.lastHeartbeat,
      aggLevel: this.config.aggLevel
    }
  }

  /**
   * 转换为标准orderbook格式 (用于与现有系统兼容)
   */
  getStandardOrderbook(symbol: string): {
    bids: Array<{ price: number; size: number }>
    asks: Array<{ price: number; size: number }>
    timestamp: number
  } | null {
    const pacificaOrderbook = this.getOrderbook(symbol)
    if (!pacificaOrderbook) return null

    return {
      bids: pacificaOrderbook.bids.map(entry => ({
        price: parseFloat(entry.p),
        size: parseFloat(entry.a)
      })),
      asks: pacificaOrderbook.asks.map(entry => ({
        price: parseFloat(entry.p),
        size: parseFloat(entry.a)
      })),
      timestamp: pacificaOrderbook.timestamp
    }
  }
}