import { NextResponse } from 'next/server'
import { executeWithFailover, getRpcStatus } from '../../../../lib/rpc-failover.js'

export async function POST() {
  try {
    console.log('🧹 Starting orphaned order cleanup...')
    
    // Log RPC status
    const rpcStatus = getRpcStatus()
    console.log('🌐 RPC Status:', rpcStatus)

    // Check if environment is configured
    if (!process.env.SOLANA_PRIVATE_KEY) {
      return NextResponse.json({
        success: false,
        error: 'Drift not configured - missing SOLANA_PRIVATE_KEY'
      }, { status: 400 })
    }

    // Execute cleanup with RPC failover
    const result = await executeWithFailover(async (connection) => {
      // Import Drift SDK components
      const { DriftClient, initialize } = await import('@drift-labs/sdk')
      const { Keypair } = await import('@solana/web3.js')
      const { AnchorProvider } = await import('@coral-xyz/anchor')

      const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY)
      const keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray))
      
      // Use the correct Wallet class
      const { default: NodeWallet } = await import('@coral-xyz/anchor/dist/cjs/nodewallet.js')
      const wallet = new NodeWallet(keypair)

      // Initialize Drift SDK
      const env = 'mainnet-beta'
      const sdkConfig = initialize({ env })
      
      const driftClient = new DriftClient({
        connection,
        wallet,
        programID: sdkConfig.DRIFT_PROGRAM_ID,
        opts: {
          commitment: 'confirmed',
        },
      })

      try {
        await driftClient.subscribe()
        console.log('✅ Connected to Drift for cleanup')

        // Get user account
        let userAccount
        try {
          userAccount = await driftClient.getUserAccount()
        } catch (accountError) {
          await driftClient.unsubscribe()
          throw new Error('No Drift user account found. Please initialize your account first.')
        }

        // Get current positions
        const perpPositions = userAccount.perpPositions || []
        const activePositions = perpPositions.filter(pos => 
          pos.baseAssetAmount && !pos.baseAssetAmount.isZero()
        )

        // Get current orders
        const orders = userAccount.orders || []
        
        // Filter for active orders - handle both numeric and object status formats
        const activeOrders = orders.filter(order => {
          if (order.baseAssetAmount.isZero()) return false
          
          // Handle object-based status (new format)
          if (typeof order.status === 'object') {
            return order.status.hasOwnProperty('open')
          }
          
          // Handle numeric status (old format) 
          return order.status === 0
        })

        console.log(`📋 Raw orders in cleanup: ${orders.length}`);
        orders.forEach((order, index) => {
          if (!order.baseAssetAmount.isZero()) {
            console.log(`📋 Cleanup Order ${index}:`, {
              orderId: order.orderId,
              status: order.status,
              baseAssetAmount: order.baseAssetAmount.toString()
            });
          }
        });
        console.log(`📊 Analysis: ${activePositions.length} active positions, ${activeOrders.length} active orders`)

        // Map positions by market index
        const positionMarkets = new Set(activePositions.map(pos => pos.marketIndex))
        
        // Find orphaned orders (orders for markets where we have no position)
        const orphanedOrders = activeOrders.filter(order => {
          // Check if this order is for a market where we have no position
          const hasPosition = positionMarkets.has(order.marketIndex)
          
          // CRITICAL FIX: Only cancel reduce-only orders if there's NO position
          // Stop Loss and Take Profit orders are reduce-only but should EXIST when we have a position
          const isReduceOnly = order.reduceOnly
          
          // Only cancel orders that are truly orphaned (no position for that market)
          // Do NOT cancel reduce-only orders when we have a position (these are SL/TP!)
          return !hasPosition && !isReduceOnly
        })

        // Additionally, find lingering SL/TP orders when position has changed significantly
        const conflictingOrders = []
        
        for (const order of activeOrders) {
          // Find corresponding position
          const position = activePositions.find(pos => pos.marketIndex === order.marketIndex)
          
          if (position) {
            const positionSide = Number(position.baseAssetAmount) > 0 ? 'long' : 'short'
            const orderDirection = order.direction === 0 ? 'long' : 'short'
            
            // Check for conflicting reduce-only orders
            if (order.reduceOnly) {
              // Reduce-only order should be opposite direction to position
              const correctDirection = positionSide === 'long' ? 'short' : 'long'
              
              if (orderDirection !== correctDirection) {
                console.log(`⚠️ Found conflicting reduce-only order: ${orderDirection} order for ${positionSide} position`)
                conflictingOrders.push(order)
              }
            }
          }
        }

        const ordersToCancel = [...orphanedOrders, ...conflictingOrders]
        
        console.log(`🎯 Found ${orphanedOrders.length} orphaned orders and ${conflictingOrders.length} conflicting orders`)

        const cancelResults = []

        if (ordersToCancel.length > 0) {
          console.log('🧹 Canceling orphaned/conflicting orders...')
          
          for (const order of ordersToCancel) {
            try {
              const marketIndex = order.marketIndex
              const orderId = order.orderId
              
              // Get market symbol for logging
              const marketSymbols = {
                0: 'SOL-PERP',
                1: 'BTC-PERP', 
                2: 'ETH-PERP',
                3: 'APT-PERP',
                4: 'BNB-PERP'
              }
              const symbol = marketSymbols[marketIndex] || `MARKET-${marketIndex}`
              
              console.log(`❌ Canceling order: ${symbol} Order ID ${orderId}`)
              
              // Cancel the order
              const txSig = await driftClient.cancelOrder(orderId)
              
              console.log(`✅ Canceled order ${orderId} for ${symbol}, tx: ${txSig}`)
              
              cancelResults.push({
                orderId: orderId,
                marketIndex: marketIndex,
                symbol: symbol,
                txSignature: txSig,
                success: true,
                reason: orphanedOrders.includes(order) ? 'orphaned' : 'conflicting'
              })
              
              // Small delay between cancellations to avoid rate limits
              await new Promise(resolve => setTimeout(resolve, 100))
              
            } catch (cancelError) {
              console.error(`❌ Failed to cancel order ${order.orderId}:`, cancelError)
              
              cancelResults.push({
                orderId: order.orderId,
                marketIndex: order.marketIndex,
                success: false,
                error: cancelError.message,
                reason: orphanedOrders.includes(order) ? 'orphaned' : 'conflicting'
              })
            }
          }
        } else {
          console.log('✅ No orphaned or conflicting orders found')
        }

        await driftClient.unsubscribe()

        const cleanupResult = {
          success: true,
          summary: {
            activePositions: activePositions.length,
            activeOrders: activeOrders.length,
            orphanedOrders: orphanedOrders.length,
            conflictingOrders: conflictingOrders.length,
            totalCanceled: cancelResults.filter(r => r.success).length,
            totalFailed: cancelResults.filter(r => !r.success).length
          },
          canceledOrders: cancelResults,
          timestamp: Date.now(),
          rpcEndpoint: getRpcStatus().currentEndpoint
        }

        console.log('🧹 Cleanup completed:', cleanupResult.summary)
        return cleanupResult

      } catch (driftError) {
        console.error('❌ Drift cleanup error:', driftError)
        
        try {
          await driftClient.unsubscribe()
        } catch (cleanupError) {
          console.warn('⚠️ Cleanup error:', cleanupError.message)
        }
        
        throw driftError
      }
    }, 3) // Max 3 retries across different RPCs

    return NextResponse.json(result)

  } catch (error) {
    console.error('❌ Orphaned order cleanup API error:', error)
    
    return NextResponse.json({
      success: false,
      error: 'Failed to cleanup orphaned orders',
      details: error.message,
      rpcStatus: getRpcStatus()
    }, { status: 500 })
  }
}

export async function GET() {
  return NextResponse.json({
    message: 'Drift Orphaned Order Cleanup API',
    description: 'Automatically cancels orphaned orders when SL/TP hits but leaves opposite orders open',
    usage: 'POST /api/drift/cleanup-orders',
    features: [
      'Detects orphaned orders (orders for markets with no position)',
      'Finds conflicting reduce-only orders',
      'Automatically cancels problematic orders',
      'Prevents manual cleanup requirement'
    ]
  })
}
