import { Connection, PublicKey } from '@solana/web3.js';

// Types
export interface TradingBalance {
  totalValue: number;
  availableBalance: number;
  marginUsed: number;
  unrealizedPnl: number;
  positions: {
    symbol: string;
    size: number;
    notionalValue: number;
    unrealizedPnl: number;
    side: 'long' | 'short';
  }[];
}

export interface Position {
  symbol: string;
  side: 'long' | 'short';
  size: number;
  entryPrice: number;
  markPrice: number;
  unrealizedPnl: number;
  notionalValue: number;
}

export interface OrderRequest {
  symbol: string;
  side: 'buy' | 'sell';
  type: 'market' | 'limit';
  amount: number;
  price?: number;
}

export interface OrderResponse {
  success: boolean;
  orderId?: string;
  error?: string;
}

export interface TradeParams {
  symbol: string;
  side: 'BUY' | 'SELL';
  amount: number;
  orderType: 'MARKET' | 'LIMIT';
  price?: number;
  stopLoss?: number;
  takeProfit?: number;
  stopLossType?: string;
  takeProfitType?: string;
}

export interface TradeResult {
  success: boolean;
  txId?: string;
  executedPrice?: number;
  executedAmount?: number;
  conditionalOrders?: any[];
  error?: string;
}

class DriftTradingService {
  private connection: Connection;
  private readonly accountPDA = '7LonnWut5i3h36xyMA5jbwnGFbnzXUPY2dsPfNaSsrTk';

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

  async initialize(): Promise<void> {
    console.log('🚀 Initializing Direct Drift Trading Service...');
    console.log('✅ Direct service ready - no SDK subscriptions needed');
  }

  async login(): Promise<{ success: boolean; message?: string }> {
    console.log('🔐 Login to direct drift service...');
    // In direct mode, we don't need to login since we're just reading account data
    return {
      success: true,
      message: 'Direct service - no login required'
    };
  }

  private async getAccountData(): Promise<Buffer> {
    try {
      const accountInfo = await this.connection.getAccountInfo(
        new PublicKey(this.accountPDA)
      );
      
      if (!accountInfo) {
        throw new Error('Account not found');
      }

      return accountInfo.data;
    } catch (error) {
      console.error('❌ Failed to fetch account data:', error);
      throw error;
    }
  }

  private parseAccountData(data: Buffer) {
    try {
      // Extract USDC balance at offset 106
      const usdcBalance = data.readBigInt64LE(106);
      const usdcValue = Number(usdcBalance) / 1_000_000; // USDC has 6 decimals

      // Extract SOL position at offset 432 (most current/accurate location)
      const solPosition = data.readBigInt64LE(432);
      const solAmount = Number(solPosition) / 1_000_000_000; // SOL has 9 decimals

      // Estimate SOL price (you could fetch this from an oracle)
      const solPrice = 17.11; // Current approximate price
      const solValue = solAmount * solPrice;

      // Calculate basic total from current positions
      let totalValue = usdcValue + solValue;

      // If we have a very low total but no active positions, this might indicate
      // settlement lag where profits from closed positions aren't yet reflected
      if (totalValue < 10 && solAmount === 0) {
        console.log(`⚠️  Low balance detected with no positions - possible settlement lag`);
        console.log(`   This often happens after position closure before profit settlement`);
        
        // In this case, we might want to use the last known total or a fallback
        // For now, we'll note this condition but keep the calculated value
      }

      console.log(`💰 Parsed account data:`);
      console.log(`   USDC Balance: $${usdcValue.toFixed(2)}`);
      console.log(`   SOL Position: ${solAmount.toFixed(6)} SOL`);
      console.log(`   SOL Value: $${solValue.toFixed(2)} (@ $${solPrice})`);
      console.log(`   Total Value: $${totalValue.toFixed(2)}`);

      return {
        usdcBalance: usdcValue,
        solPosition: solAmount,
        solPrice,
        solValue,
        totalValue,
        settlementPending: totalValue < 10 && solAmount === 0
      };
    } catch (error) {
      console.error('❌ Failed to parse account data:', error);
      throw error;
    }
  }

  async getTradingBalance(): Promise<TradingBalance> {
    try {
      const data = await this.getAccountData();
      const parsed = this.parseAccountData(data);

      // Calculate unrealized PnL (SOL value minus some baseline)
      const unrealizedPnl = parsed.solValue - (parsed.solPosition * 15); // Assuming $15 entry price

      return {
        totalValue: parsed.totalValue,
        availableBalance: parsed.usdcBalance,
        marginUsed: 0, // Not available without full account parsing
        unrealizedPnl,
        positions: parsed.solPosition > 0 ? [{
          symbol: 'SOL',
          size: parsed.solPosition,
          notionalValue: parsed.solValue,
          unrealizedPnl,
          side: 'long' as const
        }] : [],
        // Add settlement status info
        ...(parsed.settlementPending && {
          _meta: {
            settlementPending: true,
            note: 'Low balance with no positions may indicate settlement lag after position closure'
          }
        })
      };
    } catch (error) {
      console.error('❌ Failed to get trading balance:', error);
      throw error;
    }
  }

  async getPositions(): Promise<Position[]> {
    try {
      const data = await this.getAccountData();
      const parsed = this.parseAccountData(data);

      if (parsed.solPosition <= 0) {
        return [];
      }

      const unrealizedPnl = parsed.solValue - (parsed.solPosition * 15); // Assuming $15 entry

      return [{
        symbol: 'SOL',
        side: 'long',
        size: parsed.solPosition,
        entryPrice: 15, // Estimated entry price
        markPrice: parsed.solPrice,
        unrealizedPnl,
        notionalValue: parsed.solValue
      }];
    } catch (error) {
      console.error('❌ Failed to get positions:', error);
      throw error;
    }
  }

  async placeOrder(orderRequest: OrderRequest): Promise<OrderResponse> {
    console.log('📝 Order placement not implemented in direct mode:', orderRequest);
    return {
      success: false,
      error: 'Order placement requires SDK integration'
    };
  }

  async executeTrade(tradeParams: TradeParams): Promise<TradeResult> {
    console.log('🎯 Execute Trade Request:', tradeParams);
    
    try {
      // Simulated trade execution only
      console.log(`📝 Simulating ${tradeParams.side} ${tradeParams.amount} ${tradeParams.symbol}`);
      console.log(`💰 Order Type: ${tradeParams.orderType}`);
      
      if (tradeParams.price) {
        console.log(`💲 Price: $${tradeParams.price}`);
      }
      
      if (tradeParams.stopLoss) {
        console.log(`🛑 Stop Loss: $${tradeParams.stopLoss}`);
      }
      
      if (tradeParams.takeProfit) {
        console.log(`🎯 Take Profit: $${tradeParams.takeProfit}`);
      }

      // Return simulated success response
      return {
        success: true,
        txId: 'simulated_' + Date.now(),
        executedPrice: tradeParams.price || (tradeParams.symbol === 'SOL' ? 17.11 : 100),
        executedAmount: tradeParams.amount,
        conditionalOrders: [],
        error: undefined
      };
      
    } catch (error: any) {
      console.error('❌ Trade execution failed:', error);
      return {
        success: false,
        error: error.message || 'Trade execution failed'
      };
    }
  }

  async disconnect(): Promise<void> {
    console.log('✅ Direct service disconnected (no cleanup needed)');
  }

  async getServiceStatus(): Promise<{
    drift: { connected: boolean; accountPDA: string };
  }> {
    return {
      drift: {
        connected: true,
        accountPDA: this.accountPDA
      }
    };
  }
}

// Export singleton instance
export const driftTradingService = new DriftTradingService();
