import { Connection, Keypair } from '@solana/web3.js'
import { 
  DriftClient, 
  Wallet,
  OrderType,
  PositionDirection,
  MarketType,
  convertToNumber,
  BASE_PRECISION,
  PRICE_PRECISION,
  BN,
  type PerpPosition
} from '@drift-labs/sdk'

export interface TradeParams {
  symbol: string
  side: 'BUY' | 'SELL'
  amount: number // USD amount
  orderType?: 'MARKET' | 'LIMIT'
  price?: number
}

export interface TradeResult {
  success: boolean
  txId?: string
  error?: string
  executedPrice?: number
  executedAmount?: number
}

export interface Position {
  symbol: string
  side: 'LONG' | 'SHORT'
  size: number
  entryPrice: number
  unrealizedPnl: number
}

export class DriftTradingService {
  private connection: Connection
  private wallet: Wallet
  private driftClient: DriftClient

  constructor() {
    const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com'
    const secret = process.env.SOLANA_PRIVATE_KEY
    if (!secret) throw new Error('Missing SOLANA_PRIVATE_KEY in env')
    const keypair = Keypair.fromSecretKey(Buffer.from(JSON.parse(secret)))
    this.connection = new Connection(rpcUrl, 'confirmed')
    this.wallet = new Wallet(keypair)
    this.driftClient = new DriftClient({
      connection: this.connection,
      wallet: this.wallet,
      env: 'mainnet-beta',
      opts: { commitment: 'confirmed' }
    })
  }

  async executeTrade(params: TradeParams): Promise<TradeResult> {
    try {
      await this.driftClient.subscribe()
      const marketIndex = await this.getMarketIndex(params.symbol)
      const direction = params.side === 'BUY' ? PositionDirection.LONG : PositionDirection.SHORT
      const orderType = params.orderType === 'LIMIT' ? OrderType.LIMIT : OrderType.MARKET
      const price = params.price ? new BN(Math.round(params.price * PRICE_PRECISION.toNumber())) : undefined
      const baseAmount = new BN(Math.round(params.amount * BASE_PRECISION.toNumber()))
      const txSig = await this.driftClient.placeAndTakePerpOrder({
        marketIndex,
        direction,
        baseAssetAmount: baseAmount,
        orderType,
        price,
        marketType: MarketType.PERP
      })
      // Fetch fill price and amount (simplified)
      return { success: true, txId: txSig }
    } catch (e: any) {
      return { success: false, error: e.message }
    } finally {
      await this.driftClient.unsubscribe()
    }
  }

  async getPositions(): Promise<Position[]> {
    await this.driftClient.subscribe()
    const user = this.driftClient.getUser()
    // Example: check first 10 market indices (should be replaced with actual market list)
    const positions: Position[] = []
    for (let marketIndex = 0; marketIndex < 10; marketIndex++) {
      const p = user.getPerpPosition(marketIndex)
      if (!p || p.baseAssetAmount.isZero()) continue
      // TODO: Calculate unrealizedPnl if SDK exposes it
      positions.push({
        symbol: this.getSymbolFromMarketIndex(marketIndex),
        side: p.baseAssetAmount.gt(new BN(0)) ? 'LONG' : 'SHORT',
        size: convertToNumber(p.baseAssetAmount, BASE_PRECISION),
        entryPrice: convertToNumber(p.quoteEntryAmount, PRICE_PRECISION),
        unrealizedPnl: 0
      })
    }
    await this.driftClient.unsubscribe()
    return positions
  }

  // Helper: map symbol to market index (stub, should use Drift markets config)
  private async getMarketIndex(symbol: string): Promise<number> {
    // TODO: Replace with real mapping
    if (symbol === 'BTCUSD') return 0
    if (symbol === 'ETHUSD') return 1
    throw new Error('Unknown symbol: ' + symbol)
  }

  // Helper: map market index to symbol (stub)
  private getSymbolFromMarketIndex(index: number): string {
    if (index === 0) return 'BTCUSD'
    if (index === 1) return 'ETHUSD'
    return 'UNKNOWN'
  }
}

export const driftTradingService = new DriftTradingService()
