import { Connection, Keypair, VersionedTransaction } from '@solana/web3.js'
import fetch from 'cross-fetch'

export interface TriggerOrder {
  orderId: string
  inputMint: string
  outputMint: string
  makingAmount: string
  takingAmount: string
  targetPrice: number
  side: 'BUY' | 'SELL'
  orderType: 'STOP_LOSS' | 'TAKE_PROFIT' | 'LIMIT'
  status: 'PENDING' | 'EXECUTED' | 'CANCELLED' | 'EXPIRED'
  createdAt: number
  executedAt?: number
  txId?: string
  requestId?: string
}

class JupiterTriggerService {
  private connection: Connection
  private keypair: Keypair | null = null
  private activeOrders: TriggerOrder[] = []
  
  // Token mint addresses
  private tokens = {
    SOL: 'So11111111111111111111111111111111111111112', // Wrapped SOL
    USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
    USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
  }

  constructor() {
    const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com'
    this.connection = new Connection(rpcUrl, 'confirmed')
    this.initializeWallet()
  }

  private initializeWallet() {
    try {
      if (process.env.SOLANA_PRIVATE_KEY) {
        const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY)
        this.keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray))
        console.log('✅ Jupiter Trigger wallet initialized:', this.keypair.publicKey.toString())
      } else {
        console.warn('⚠️ No SOLANA_PRIVATE_KEY found for Jupiter Trigger')
      }
    } catch (error) {
      console.error('❌ Failed to initialize Jupiter Trigger wallet:', error)
    }
  }

  /**
   * Create a stop loss order
   * When current price drops to stopPrice, sell the token
   */
  async createStopLossOrder(params: {
    tokenSymbol: string
    amount: number // Amount of tokens to sell
    stopPrice: number // Price at which to trigger the sale
    slippageBps?: number // Optional slippage (default 0 for exact execution)
    expiredAt?: number // Optional expiry timestamp
  }): Promise<{
    success: boolean
    orderId?: string
    requestId?: string
    transaction?: string
    error?: string
  }> {
    if (!this.keypair) {
      return { success: false, error: 'Wallet not initialized' }
    }

    try {
      const { tokenSymbol, amount, stopPrice, slippageBps = 0, expiredAt } = params
      
      console.log('🛑 Creating stop loss order:', params)

      // Determine mint addresses
      const inputMint = tokenSymbol === 'SOL' ? this.tokens.SOL : this.tokens.USDC
      const outputMint = tokenSymbol === 'SOL' ? this.tokens.USDC : this.tokens.SOL
      
      // Calculate amounts
      const makingAmount = tokenSymbol === 'SOL' 
        ? Math.floor(amount * 1_000_000_000).toString() // SOL has 9 decimals
        : Math.floor(amount * 1_000_000).toString() // USDC has 6 decimals
      
      const takingAmount = tokenSymbol === 'SOL'
        ? Math.floor(amount * stopPrice * 1_000_000).toString() // Convert to USDC
        : Math.floor(amount / stopPrice * 1_000_000_000).toString() // Convert to SOL

      const orderParams: any = {
        inputMint,
        outputMint,
        maker: this.keypair.publicKey.toString(),
        payer: this.keypair.publicKey.toString(),
        params: {
          makingAmount,
          takingAmount,
        },
        computeUnitPrice: "auto"
      }

      // Add optional parameters
      if (slippageBps > 0) {
        orderParams.params.slippageBps = slippageBps.toString()
      }
      if (expiredAt) {
        orderParams.params.expiredAt = expiredAt.toString()
      }

      // Create the trigger order
      const response = await fetch('https://api.jup.ag/trigger/v1/createOrder', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(orderParams)
      })

      if (!response.ok) {
        const error = await response.json()
        throw new Error(`Trigger API error: ${error.error || response.status}`)
      }

      const result = await response.json()
      
      // Store the order locally
      const order: TriggerOrder = {
        orderId: result.order,
        inputMint,
        outputMint,
        makingAmount,
        takingAmount,
        targetPrice: stopPrice,
        side: 'SELL',
        orderType: 'STOP_LOSS',
        status: 'PENDING',
        createdAt: Date.now(),
        requestId: result.requestId
      }

      this.activeOrders.push(order)

      console.log('✅ Stop loss order created:', result.order)
      
      return {
        success: true,
        orderId: result.order,
        requestId: result.requestId,
        transaction: result.transaction
      }

    } catch (error: any) {
      console.error('❌ Failed to create stop loss order:', error)
      return { success: false, error: error.message }
    }
  }

  /**
   * Create a take profit order
   * When current price rises to targetPrice, sell the token
   */
  async createTakeProfitOrder(params: {
    tokenSymbol: string
    amount: number // Amount of tokens to sell
    targetPrice: number // Price at which to trigger the sale
    slippageBps?: number // Optional slippage (default 0 for exact execution)
    expiredAt?: number // Optional expiry timestamp
  }): Promise<{
    success: boolean
    orderId?: string
    requestId?: string
    transaction?: string
    error?: string
  }> {
    if (!this.keypair) {
      return { success: false, error: 'Wallet not initialized' }
    }

    try {
      const { tokenSymbol, amount, targetPrice, slippageBps = 0, expiredAt } = params
      
      console.log('🎯 Creating take profit order:', params)

      // Determine mint addresses
      const inputMint = tokenSymbol === 'SOL' ? this.tokens.SOL : this.tokens.USDC
      const outputMint = tokenSymbol === 'SOL' ? this.tokens.USDC : this.tokens.SOL
      
      // Calculate amounts
      const makingAmount = tokenSymbol === 'SOL' 
        ? Math.floor(amount * 1_000_000_000).toString() // SOL has 9 decimals
        : Math.floor(amount * 1_000_000).toString() // USDC has 6 decimals
      
      const takingAmount = tokenSymbol === 'SOL'
        ? Math.floor(amount * targetPrice * 1_000_000).toString() // Convert to USDC
        : Math.floor(amount / targetPrice * 1_000_000_000).toString() // Convert to SOL

      const orderParams: any = {
        inputMint,
        outputMint,
        maker: this.keypair.publicKey.toString(),
        payer: this.keypair.publicKey.toString(),
        params: {
          makingAmount,
          takingAmount,
        },
        computeUnitPrice: "auto"
      }

      // Add optional parameters
      if (slippageBps > 0) {
        orderParams.params.slippageBps = slippageBps.toString()
      }
      if (expiredAt) {
        orderParams.params.expiredAt = expiredAt.toString()
      }

      // Create the trigger order
      const response = await fetch('https://api.jup.ag/trigger/v1/createOrder', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(orderParams)
      })

      if (!response.ok) {
        const error = await response.json()
        throw new Error(`Trigger API error: ${error.error || response.status}`)
      }

      const result = await response.json()
      
      // Store the order locally
      const order: TriggerOrder = {
        orderId: result.order,
        inputMint,
        outputMint,
        makingAmount,
        takingAmount,
        targetPrice: targetPrice,
        side: 'SELL',
        orderType: 'TAKE_PROFIT',
        status: 'PENDING',
        createdAt: Date.now(),
        requestId: result.requestId
      }

      this.activeOrders.push(order)

      console.log('✅ Take profit order created:', result.order)
      
      return {
        success: true,
        orderId: result.order,
        requestId: result.requestId,
        transaction: result.transaction
      }

    } catch (error: any) {
      console.error('❌ Failed to create take profit order:', error)
      return { success: false, error: error.message }
    }
  }

  /**
   * Execute (sign and send) a trigger order transaction
   */
  async executeOrder(transaction: string, requestId: string): Promise<{
    success: boolean
    txId?: string
    error?: string
  }> {
    if (!this.keypair) {
      return { success: false, error: 'Wallet not initialized' }
    }

    try {
      console.log('⚡ Executing trigger order transaction')

      // Deserialize and sign transaction
      const transactionBuf = Buffer.from(transaction, 'base64')
      const versionedTransaction = VersionedTransaction.deserialize(transactionBuf)
      versionedTransaction.sign([this.keypair])

      // Send via Jupiter's execute endpoint
      const response = await fetch('https://api.jup.ag/trigger/v1/execute', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          requestId,
          transaction: Buffer.from(versionedTransaction.serialize()).toString('base64')
        })
      })

      if (!response.ok) {
        const error = await response.json()
        throw new Error(`Execute API error: ${error.error || response.status}`)
      }

      const result = await response.json()
      console.log('✅ Trigger order executed:', result.txId)

      // Update local order status
      const order = this.activeOrders.find(o => o.requestId === requestId)
      if (order) {
        order.status = 'PENDING'
        order.txId = result.txId
      }

      return {
        success: true,
        txId: result.txId
      }

    } catch (error: any) {
      console.error('❌ Failed to execute trigger order:', error)
      return { success: false, error: error.message }
    }
  }

  /**
   * Cancel a trigger order
   */
  async cancelOrder(orderId: string): Promise<{
    success: boolean
    txId?: string
    error?: string
  }> {
    if (!this.keypair) {
      return { success: false, error: 'Wallet not initialized' }
    }

    try {
      console.log('❌ Cancelling trigger order:', orderId)

      const response = await fetch('https://api.jup.ag/trigger/v1/cancelOrder', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          order: orderId,
          owner: this.keypair.publicKey.toString(),
          computeUnitPrice: "auto"
        })
      })

      if (!response.ok) {
        const error = await response.json()
        throw new Error(`Cancel API error: ${error.error || response.status}`)
      }

      const result = await response.json()

      // Sign and send the cancel transaction
      const transactionBuf = Buffer.from(result.transaction, 'base64')
      const versionedTransaction = VersionedTransaction.deserialize(transactionBuf)
      versionedTransaction.sign([this.keypair])

      const txId = await this.connection.sendTransaction(versionedTransaction)
      const confirmation = await this.connection.confirmTransaction(txId, 'confirmed')

      if (confirmation.value.err) {
        throw new Error(`Cancel transaction failed: ${confirmation.value.err}`)
      }

      // Update local order status
      const order = this.activeOrders.find(o => o.orderId === orderId)
      if (order) {
        order.status = 'CANCELLED'
      }

      console.log('✅ Trigger order cancelled:', txId)
      
      return {
        success: true,
        txId
      }

    } catch (error: any) {
      console.error('❌ Failed to cancel trigger order:', error)
      return { success: false, error: error.message }
    }
  }

  /**
   * Get active trigger orders for the wallet
   */
  async getTriggerOrders(): Promise<TriggerOrder[]> {
    if (!this.keypair) {
      return []
    }

    try {
      const response = await fetch(`https://api.jup.ag/trigger/v1/getTriggerOrders?wallet=${this.keypair.publicKey.toString()}&active=true`)
      
      if (!response.ok) {
        throw new Error(`Get orders API error: ${response.status}`)
      }

      const result = await response.json()
      console.log('📊 Retrieved trigger orders:', result.orders?.length || 0)
      
      return result.orders || []

    } catch (error: any) {
      console.error('❌ Failed to get trigger orders:', error)
      return this.activeOrders // Fallback to local orders
    }
  }

  /**
   * Create both stop loss and take profit orders for a trade
   */
  async createTradingOrders(params: {
    tokenSymbol: string
    amount: number
    stopLoss?: number
    takeProfit?: number
    slippageBps?: number
    expiredAt?: number
  }): Promise<{
    success: boolean
    stopLossOrder?: string
    takeProfitOrder?: string
    transactions?: string[]
    error?: string
  }> {
    const { tokenSymbol, amount, stopLoss, takeProfit, slippageBps, expiredAt } = params
    const results: any = { success: true, transactions: [] }

    try {
      // Create stop loss order
      if (stopLoss) {
        const slResult = await this.createStopLossOrder({
          tokenSymbol,
          amount,
          stopPrice: stopLoss,
          slippageBps,
          expiredAt
        })

        if (slResult.success) {
          results.stopLossOrder = slResult.orderId
          results.transactions.push(slResult.transaction)
        } else {
          console.warn('⚠️ Failed to create stop loss order:', slResult.error)
        }
      }

      // Create take profit order
      if (takeProfit) {
        const tpResult = await this.createTakeProfitOrder({
          tokenSymbol,
          amount,
          targetPrice: takeProfit,
          slippageBps,
          expiredAt
        })

        if (tpResult.success) {
          results.takeProfitOrder = tpResult.orderId
          results.transactions.push(tpResult.transaction)
        } else {
          console.warn('⚠️ Failed to create take profit order:', tpResult.error)
        }
      }

      return results

    } catch (error: any) {
      console.error('❌ Failed to create trading orders:', error)
      return { success: false, error: error.message }
    }
  }

  getLocalOrders(): TriggerOrder[] {
    return this.activeOrders
  }

  isConfigured(): boolean {
    return this.keypair !== null
  }
}

export const jupiterTriggerService = new JupiterTriggerService()
export default JupiterTriggerService
