import { EventEmitter } from 'events'
import { ExchangeAdapter, PlaceOrderReq, Order, Position, Balance, Depth } from '../ExchangeAdapter'
import { FutureConnector } from './FutureConnector'

export class BinanceAdapter implements ExchangeAdapter {
  private ee = new EventEmitter()
  constructor(private connector: FutureConnector) {}

  name() {
    return 'binance'
  }
  async time(): Promise<number> {
    return Date.now()
  }
  async symbols(): Promise<string[]> {
    return await this.connector.getSymbols()
  }

  async balances(): Promise<Balance[]> {
    const assets = await this.connector.getAssetsInfo()
    return assets.map((a: any) => ({
      asset: a.asset,
      total: String(a.walletBalance),
      free: String(a.availableBalance),
    }))
  }

  async positions(): Promise<Position[]> {
    const positions = await this.connector.getAllPositions()
    return positions.map((p: any) => ({
      symbol: p.symbol,
      side: Number(p.positionAmt) >= 0 ? 'LONG' : 'SHORT',
      qty: String(p.positionAmt),
      entryPrice: String(p.entryPrice ?? '0'),
      unrealizedPnl: String(p.unrealizedProfit ?? '0'),
      leverage: Number(p.leverage ?? 0),
    }))
  }

  async placeOrder(req: PlaceOrderReq): Promise<Order> {
    if (req.type === 'MARKET') {
      const r = await this.connector.openMarketOrder(
        req.symbol,
        req.side === 'BUY' ? 'long' : 'short',
        Number(req.quantity),
      )
      return {
        id: String((r as any)?.orderId ?? Date.now()),
        symbol: req.symbol,
        status: 'NEW',
        side: req.side,
        type: req.type,
        origQty: req.quantity,
        executedQty: '0',
        updateTime: Date.now(),
      }
    } else {
      const r = await this.connector.openLimitOrder(
        req.symbol,
        req.side === 'BUY' ? 'long' : 'short',
        Number(req.quantity),
        Number(req.price ?? 0),
      )
      return {
        id: String((r as any)?.orderId ?? Date.now()),
        symbol: req.symbol,
        status: 'NEW',
        side: req.side,
        type: req.type,
        price: req.price,
        origQty: req.quantity,
        executedQty: '0',
        updateTime: Date.now(),
      }
    }
  }

  async cancelOrder(symbol: string, orderId: string): Promise<void> {
    await this.connector.cancelOrder(symbol, Number(orderId))
  }

  async cancelAll(symbol: string): Promise<void> {
    await this.connector.cancelAllOrders(symbol)
  }

  async getOrder(symbol: string, orderId: string): Promise<Order> {
    const r = await this.connector.getOrderHistory(symbol)
    const o = (Array.isArray(r) ? r : []).find((x: any) => String(x.orderId) === String(orderId)) || {}
    return {
      id: String(orderId),
      symbol,
      status: ((o.status ?? 'NEW') as string).toUpperCase() as any,
      side: ((o.side ?? 'BUY') as string).toUpperCase() as any,
      type: ((o.type ?? 'LIMIT') as string).toUpperCase() as any,
      price: String(o.price ?? '0'),
      origQty: String(o.origQty ?? '0'),
      executedQty: String(o.executedQty ?? '0'),
      updateTime: o.updateTime ?? Date.now(),
    }
  }

  async openOrders(symbol: string): Promise<Order[]> {
    const orders = await this.connector.getCurrentAllOpenOrders(symbol)
    return (Array.isArray(orders) ? orders : []).map((o: any) => ({
      id: String(o.orderId || Date.now()),
      symbol: o.symbol || symbol,
      status: ((o.status || 'NEW') as string).toUpperCase() as any,
      side: ((o.side || 'BUY') as string).toUpperCase() as any,
      type: ((o.type || 'LIMIT') as string).toUpperCase() as any,
      price: String(o.price || '0'),
      origQty: String(o.origQty || '0'),
      executedQty: String(o.executedQty || '0'),
      updateTime: o.updateTime || Date.now(),
    }))
  }

  async leverage(symbol: string, lev: number): Promise<void> {
    await this.connector.setLeverage(symbol, lev)
  }

  async depth(symbol: string, limit = 50): Promise<Depth> {
    const data = await this.connector.getDepth(symbol, limit)
    return {
      bids: (Array.isArray(data.bids) ? data.bids : []).map((b: any) => ({
        price: String(b[0] || '0'),
        qty: String(b[1] || '0'),
      })),
      asks: (Array.isArray(data.asks) ? data.asks : []).map((a: any) => ({
        price: String(a[0] || '0'),
        qty: String(a[1] || '0'),
      })),
      ts: Date.now(),
    }
  }

  ws() {
    return this.ee
  }
}
