import { PacificaClient } from './PacificaClient'
import { randomUUID } from 'crypto'
import { logger } from '../../utils/logger.js'

export interface OrderCreatePayload {
  account: string
  symbol: string
  amount: string
  side: 'bid' | 'ask'
  reduceOnly: boolean
  clientOrderId?: string
  tif?: 'GTC' | 'IOC' | 'ALO'
  price?: string
  // For market orders per docs
  slippagePercent?: string // maps to slippage_percent
  takeProfit?: { stopPrice: string; limitPrice?: string; clientOrderId?: string }
  stopLoss?: { stopPrice: string; limitPrice?: string; clientOrderId?: string }
  agentWallet?: string
  expiryWindow?: number
}

export interface CancelOrderPayload {
  account: string
  symbol: string
  orderId?: number
  clientOrderId?: string
  agentWallet?: string
  expiryWindow?: number
}

export class PacificaOrdersAdapter {
  constructor(private client: PacificaClient) {}

  private normalizeSymbol(input?: string) {
    if (!input) return input as any
    const s = String(input).toUpperCase()
    if (s.includes('-')) return s.split('-')[0]
    if (s.endsWith('USDT')) return s.replace('USDT', '')
    if (s.endsWith('USD')) return s.replace('USD', '')
    return s
  }

  async createMarketOrder(payload: OrderCreatePayload) {
    // For market orders, only use required fields per API docs
    const marketPayload: OrderCreatePayload = {
      account: payload.account,
      symbol: payload.symbol,
      amount: payload.amount,
      side: payload.side,
      reduceOnly: payload.reduceOnly,
      slippagePercent: payload.slippagePercent || '0.5',
    }

    return await this.sendSigned(this.client.endpoints.orderCreateMarket, 'create_market_order', marketPayload)
  }

  async createLimitOrder(payload: OrderCreatePayload) {
    return await this.sendSigned(this.client.endpoints.orderCreateLimit, 'create_order', payload)
  }

  async createStopOrder(payload: OrderCreatePayload) {
    return await this.sendSigned(this.client.endpoints.orderCreateStop, 'create_stop_order', payload)
  }

  async cancelOrder(payload: CancelOrderPayload) {
    return await this.sendSigned(this.client.endpoints.orderCancel, 'cancel_order', payload)
  }

  async cancelAll(payload: { symbol?: string; allSymbols?: boolean; excludeReduceOnly?: boolean }) {
    const account = this.client.requireAccount()
    const data = {
      all_symbols: payload.allSymbols ?? !payload.symbol,
      exclude_reduce_only: payload.excludeReduceOnly ?? false,
      symbol: this.normalizeSymbol(payload.symbol),
    } as any
    const { signature, timestamp, expiryWindow } = await this.client.signOperation('cancel_all_orders', data, 30000)
    const body = { account, ...data, signature, timestamp, expiry_window: expiryWindow }
    return await this.client.post(this.client.endpoints.orderCancelAll, body, { skipHeaderSig: true })
  }

  async openOrders(symbol?: string, account?: string) {
    const query: Record<string, string> = { account: this.client.requireAccount(account) }
    if (symbol) query.symbol = symbol
    return await this.client.get<any>(this.client.endpoints.openOrders, query)
  }

  async batch(actions: Array<{ type: 'Create' | 'Cancel'; data: OrderCreatePayload | CancelOrderPayload }>) {
    const signedActions = await Promise.all(
      actions.map(async action => {
        if (action.type === 'Create') {
          const raw = action.data as any
          // Normalize incoming fields from external callers (reduce_only -> reduceOnly)
          const payload: OrderCreatePayload = {
            account: raw.account,
            symbol: raw.symbol,
            amount: raw.amount,
            side: raw.side,
            reduceOnly: raw.reduceOnly !== undefined ? raw.reduceOnly : raw.reduce_only ?? false,
            clientOrderId: raw.clientOrderId ?? raw.client_order_id,
            tif: raw.tif,
            price: raw.price,
            slippagePercent: raw.slippagePercent ?? raw.slippage_percent,
            takeProfit: raw.takeProfit,
            stopLoss: raw.stopLoss,
            agentWallet: raw.agentWallet ?? raw.agent_wallet,
            expiryWindow: raw.expiryWindow,
          }
          const transformed = this.transformCreatePayload(
            payload,
            this.client.cfg.agentPrivateKey ? this.client.requireAgentWallet(payload.agentWallet) : undefined,
          )
          const dataToSign = this.pickOrderSignFields('create_order', transformed)
          const { signature, timestamp, expiryWindow } = await this.client.signOperation(
            'create_order',
            dataToSign,
            payload.expiryWindow ?? 30000,
          )
          return { type: 'Create', data: { ...transformed, signature, timestamp, expiry_window: expiryWindow } }
        }
        const cp = action.data as CancelOrderPayload
        const transformedCancel = this.transformCancelPayload(cp)
        const cancelSign = this.pickCancelSignFields(transformedCancel)
        const { signature, timestamp, expiryWindow } = await this.client.signOperation(
          'cancel_order',
          cancelSign,
          cp.expiryWindow ?? 30000,
        )
        return { type: 'Cancel', data: { ...transformedCancel, signature, timestamp, expiry_window: expiryWindow } }
      }),
    )
    return await this.client.post(this.client.endpoints.orderBatch, { actions: signedActions }, { skipHeaderSig: true })
  }

  private transformCreatePayload(payload: OrderCreatePayload, agentWallet?: string, isMarketOrder = false) {
    const clientOrderId = payload.clientOrderId || randomUUID()

    // For market orders, use minimal required fields per API error messages
    if (isMarketOrder) {
      return {
        account: payload.account,
        symbol: this.normalizeSymbol(payload.symbol),
        amount: payload.amount, // API expects 'amount'
        side: payload.side, // API expects 'bid'/'ask'
        reduce_only: payload.reduceOnly,
        slippage_percent: payload.slippagePercent || '1.0', // Required field
        agent_wallet: agentWallet ?? payload.agentWallet,
      }
    }

    // For limit orders and others, include all fields
    const takeProfit = payload.takeProfit
      ? {
          stop_price: payload.takeProfit.stopPrice,
          limit_price: payload.takeProfit.limitPrice,
          client_order_id: payload.takeProfit.clientOrderId,
        }
      : undefined
    const stopLoss = payload.stopLoss
      ? {
          stop_price: payload.stopLoss.stopPrice,
          limit_price: payload.stopLoss.limitPrice,
          client_order_id: payload.stopLoss.clientOrderId,
        }
      : undefined

    return {
      account: payload.account,
      symbol: this.normalizeSymbol(payload.symbol),
      amount: payload.amount,
      side: payload.side,
      reduce_only: payload.reduceOnly,
      client_order_id: clientOrderId,
      tif: payload.tif ?? 'GTC',
      price: payload.price,
      slippage_percent: payload.slippagePercent,
      take_profit: takeProfit,
      stop_loss: stopLoss,
      agent_wallet: agentWallet ?? payload.agentWallet,
    }
  }

  private async buildSignedPayload(
    operation: string,
    data: Record<string, any>,
    expiryWindow = 30000,
    useAgent = false,
  ) {
    const signer = useAgent
      ? this.client.signOperationWithAgent.bind(this.client)
      : this.client.signOperation.bind(this.client)
    const { signature, timestamp, expiryWindow: ew } = await signer(operation, data, expiryWindow)
    return {
      ...data,
      signature,
      timestamp,
      expiry_window: ew,
    }
  }

  private async sendSigned(path: string, operation: string, payload: OrderCreatePayload | CancelOrderPayload) {
    const isOrder = operation.startsWith('create_')
    const useAgent = isOrder && !!this.client.cfg.agentPrivateKey
    if (operation === 'cancel_order') {
      const transformed = this.transformCancelPayload(payload as CancelOrderPayload)
      const expiryWindow = (payload as any).expiryWindow ?? 30000
      const dataToSign = this.pickCancelSignFields(transformed)
      const {
        signature,
        timestamp,
        expiryWindow: ew,
      } = await this.client.signOperation(operation, dataToSign, expiryWindow)
      const finalBody = { ...transformed, signature, timestamp, expiry_window: ew }
      if (process.env.NODE_ENV === 'development' && process.env.PACIFICA_DEBUG === '1') {
        logger.debug('Pacifica订单签名调试', {
          operation,
          signDataLength: JSON.stringify(dataToSign).length,
          signaturePreview: `b58(${String((finalBody as any).signature).slice(0, 8)}...)`,
        })
      }
      return await this.client.post(path, finalBody, { skipHeaderSig: true })
    }
    // create_* flow: sign ONLY the operation fields per docs, NOT account/agent_wallet
    const transformed =
      operation === 'create_stop_order'
        ? (() => {
            const p = payload as OrderCreatePayload
            const clientId = p.clientOrderId || randomUUID()
            return {
              account: p.account,
              symbol: this.normalizeSymbol(p.symbol),
              side: p.side,
              reduce_only: p.reduceOnly,
              stop_order: {
                stop_price: p.stopLoss?.stopPrice,
                limit_price: p.stopLoss?.limitPrice,
                client_order_id: clientId,
                amount: p.amount,
              },
              agent_wallet: useAgent ? this.client.requireAgentWallet(p.agentWallet) : p.agentWallet,
            }
          })()
        : this.transformCreatePayload(
            payload as OrderCreatePayload,
            useAgent ? this.client.requireAgentWallet((payload as OrderCreatePayload).agentWallet) : undefined,
            operation === 'create_market_order',
          )
    const expiryWindow = (payload as any).expiryWindow ?? 5000
    const dataToSign: Record<string, any> = this.pickOrderSignFields(operation, transformed)
    const signer = useAgent
      ? this.client.signOperationWithAgent.bind(this.client)
      : this.client.signOperation.bind(this.client)
    const { signature, timestamp, expiryWindow: ew } = await signer(operation, dataToSign, expiryWindow)
    const finalBody = {
      ...transformed,
      timestamp,
      expiry_window: ew,
      signature,
    }
    if (process.env.NODE_ENV === 'development' && process.env.PACIFICA_DEBUG === '1') {
      logger.debug('Pacifica创建订单调试', {
        operation,
        signDataLength: JSON.stringify(dataToSign).length,
        signaturePreview: `b58(${String(finalBody.signature).slice(0, 8)}...)`,
      })
    }
    return await this.client.post(path, finalBody, { skipHeaderSig: true })
  }

  private pickOrderSignFields(operation: string, transformed: Record<string, any>) {
    const base: Record<string, any> = {
      symbol: transformed.symbol,
      reduce_only: transformed.reduce_only,
      side: transformed.side,
    }
    if (operation === 'create_market_order') {
      // Market order fields per API requirements
      base.amount = transformed.amount
      if (transformed.slippage_percent !== undefined) {
        base.slippage_percent = transformed.slippage_percent
      }
      return base
    }
    // For other orders
    base.amount = transformed.amount || transformed.quantity
    // Add client_order_id for other order types
    base.client_order_id = transformed.client_order_id
    if (operation === 'create_stop_order') {
      base.side = transformed.side
      base.reduce_only = transformed.reduce_only
      base.stop_order = {
        stop_price: transformed.stop_order?.stop_price,
        limit_price: transformed.stop_order?.limit_price,
        amount: transformed.stop_order?.amount,
        client_order_id: transformed.stop_order?.client_order_id,
      }
      return base
    }
    if (operation === 'create_stop_order') {
      if (transformed.stop_price !== undefined) base.stop_price = transformed.stop_price
      if (transformed.limit_price !== undefined) base.limit_price = transformed.limit_price
      return base
    }
    // create_order (limit)
    if (transformed.tif !== undefined) base.tif = transformed.tif
    if (transformed.price !== undefined) base.price = transformed.price
    return base
  }

  private transformCancelPayload(payload: CancelOrderPayload) {
    if (!payload.orderId && !payload.clientOrderId) {
      throw new Error('PacificaOrdersAdapter: orderId or clientOrderId required')
    }
    return {
      account: payload.account,
      symbol: this.normalizeSymbol(payload.symbol),
      order_id: payload.orderId,
      client_order_id: payload.clientOrderId,
    }
  }

  private pickCancelSignFields(transformed: Record<string, any>) {
    const base: Record<string, any> = { symbol: transformed.symbol }
    if (transformed.order_id !== undefined && transformed.order_id !== null) base.order_id = transformed.order_id
    else if (transformed.client_order_id) base.client_order_id = transformed.client_order_id
    return base
  }
}
