#!/usr/bin/env node

/**
 * Complete Risk/Reward Learning System
 * 
 * This enhanced system learns from BOTH stop losses AND take profits to optimize
 * the AI's risk/reward settings and position management decisions.
 */

const { getDB } = require('./db');

class RiskRewardLearner {
  constructor() {
    this.setupHistory = [];
    this.patterns = {
      optimal_rr_ratios: {},
      market_condition_adjustments: {},
      symbol_specific_patterns: {}
    };
  }

  async getPrisma() {
    return await getDB();
  }

  async log(message) {
    const timestamp = new Date().toISOString();
    console.log(`[${timestamp}] 🎯 RR Learner: ${message}`);
  }

  /**
   * Record a complete risk/reward setup for learning
   */
  async recordRiskRewardSetup(setupData) {
    try {
      const setup = {
        id: `rr_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        tradeId: setupData.tradeId,
        symbol: setupData.symbol,
        entryPrice: setupData.entryPrice,
        stopLoss: setupData.stopLoss,
        takeProfit: setupData.takeProfit,
        leverage: setupData.leverage,
        side: setupData.side,
        
        // Calculate initial risk/reward metrics
        stopLossDistance: this.calculateDistance(setupData.entryPrice, setupData.stopLoss, setupData.side),
        takeProfitDistance: this.calculateDistance(setupData.entryPrice, setupData.takeProfit, setupData.side),
        riskRewardRatio: this.calculateRiskRewardRatio(setupData),
        
        // Market context when setup was made
        marketConditions: {
          volatility: await this.calculateVolatility(setupData.symbol),
          trend: await this.analyzeMarketTrend(setupData.symbol),
          timeOfDay: new Date().getHours(),
          dayOfWeek: new Date().getDay(),
          aiConfidence: setupData.aiConfidence || 0.7
        },
        
        // AI reasoning for the setup
        aiReasoning: setupData.aiReasoning || 'Standard risk/reward setup',
        expectedOutcome: setupData.expectedOutcome || 'REACH_TAKE_PROFIT',
        
        setupTimestamp: new Date(),
        status: 'ACTIVE'
      };

      // Store in database
      const prisma = await this.getPrisma();
      await prisma.riskRewardSetup.create({
        data: {
          id: setup.id,
          tradeId: setup.tradeId,
          symbol: setup.symbol,
          entryPrice: setup.entryPrice,
          stopLoss: setup.stopLoss,
          takeProfit: setup.takeProfit,
          leverage: setup.leverage,
          side: setup.side,
          stopLossDistance: setup.stopLossDistance,
          takeProfitDistance: setup.takeProfitDistance,
          riskRewardRatio: setup.riskRewardRatio,
          marketConditions: JSON.stringify(setup.marketConditions),
          aiReasoning: setup.aiReasoning,
          expectedOutcome: setup.expectedOutcome,
          setupTimestamp: setup.setupTimestamp,
          status: setup.status
        }
      });

      this.learningHistory.push(setup);

      await this.log(`📝 Recorded R/R setup: ${setup.symbol} SL=${setup.stopLossDistance.toFixed(2)}% TP=${setup.takeProfitDistance.toFixed(2)}% Ratio=1:${setup.riskRewardRatio.toFixed(2)}`);
      
      return setup.id;
    } catch (error) {
      await this.log(`❌ Error recording R/R setup: ${error.message}`);
      return null;
    }
  }

  /**
   * Record the final outcome when position closes
   */
  async recordTradeOutcome(outcomeData) {
    try {
      const { setupId, exitPrice, exitReason, actualPnL, timeToExit } = outcomeData;

      // Determine outcome quality
      const outcomeAnalysis = this.analyzeOutcomeQuality(outcomeData);

      // Update setup record with outcome
      // Update setup in database
      const prisma = await this.getPrisma();
      await prisma.riskRewardSetup.update({
        where: { id: setupId },
        data: {
          exitPrice,
          exitReason, // 'STOP_LOSS', 'TAKE_PROFIT', 'MANUAL_EXIT', 'LIQUIDATION'
          actualPnL,
          timeToExit,
          outcomeQuality: outcomeAnalysis.quality,
          learningScore: outcomeAnalysis.score,
          actualRiskReward: outcomeAnalysis.actualRR,
          exitTimestamp: new Date(),
          status: 'COMPLETED',
          learningData: JSON.stringify({
            wasOptimal: outcomeAnalysis.wasOptimal,
            improvements: outcomeAnalysis.suggestedImprovements,
            marketBehavior: outcomeAnalysis.marketBehavior
          })
        }
      });

      await this.log(`✅ Recorded outcome: ${exitReason} - Quality: ${outcomeAnalysis.quality} (Score: ${outcomeAnalysis.score.toFixed(2)})`);

      // Trigger learning update
      await this.updateRiskRewardLearning();

      return outcomeAnalysis;
    } catch (error) {
      await this.log(`❌ Error recording trade outcome: ${error.message}`);
      return null;
    }
  }

  /**
   * Analyze the quality of a risk/reward setup outcome
   */
  analyzeOutcomeQuality(outcomeData) {
    const { exitReason, actualPnL, setupData } = outcomeData;
    let quality = 'UNKNOWN';
    let score = 0.5;
    let wasOptimal = false;
    let suggestedImprovements = [];
    let actualRR = 0;

    if (setupData) {
      actualRR = Math.abs(actualPnL) / Math.abs(setupData.stopLossDistance * setupData.entryPrice / 100);
    }

    switch (exitReason) {
      case 'TAKE_PROFIT':
        // Excellent - AI's take profit was hit
        quality = 'EXCELLENT';
        score = 0.9;
        wasOptimal = true;
        
        if (actualRR > setupData?.riskRewardRatio * 1.2) {
          suggestedImprovements.push('Consider setting take profit even higher in similar conditions');
        }
        break;

      case 'STOP_LOSS':
        // Stop loss hit - analyze if it was appropriate
        if (actualPnL > -(setupData?.stopLossDistance * setupData?.entryPrice / 100) * 0.8) {
          quality = 'GOOD'; // Stop loss worked as intended
          score = 0.6;
          wasOptimal = true;
        } else {
          quality = 'POOR'; // Stop loss was too tight or poorly placed
          score = 0.3;
          suggestedImprovements.push('Consider wider stop loss in similar market conditions');
        }
        break;

      case 'MANUAL_EXIT':
        // Manual exit - analyze timing and P&L
        if (actualPnL > 0) {
          if (actualPnL >= setupData?.takeProfitDistance * setupData?.entryPrice / 100 * 0.8) {
            quality = 'GOOD'; // Took profit manually near target
            score = 0.7;
          } else {
            quality = 'FAIR'; // Took profit early
            score = 0.5;
            suggestedImprovements.push('Consider holding longer to reach full take profit');
          }
        } else {
          quality = 'POOR'; // Manual exit at loss
          score = 0.2;
          suggestedImprovements.push('Consider trusting stop loss instead of manual exit');
        }
        break;

      case 'LIQUIDATION':
        // Liquidation - very poor outcome
        quality = 'TERRIBLE';
        score = 0.1;
        suggestedImprovements.push('Reduce leverage significantly', 'Use wider stop loss', 'Better position sizing');
        break;

      default:
        quality = 'UNKNOWN';
        score = 0.3;
    }

    return {
      quality,
      score,
      wasOptimal,
      suggestedImprovements,
      actualRR,
      marketBehavior: this.analyzeMarketBehaviorDuringTrade(outcomeData)
    };
  }

  /**
   * Learn from risk/reward patterns and optimize future setups
   */
  async updateRiskRewardLearning() {
    try {
      const prisma = await this.getPrisma();
      const recentSetups = await prisma.riskRewardSetup.findMany({
        where: { status: 'COMPLETED' },
        orderBy: { setupTimestamp: 'desc' },
        take: 100
      });

      if (recentSetups.length < 5) {
        await this.log('📊 Insufficient data for learning (need at least 5 completed trades)');
        return;
      }

      // Analyze patterns
      const patterns = {
        stopLossPatterns: this.analyzeStopLossPatterns(recentSetups),
        takeProfitPatterns: this.analyzeTakeProfitPatterns(recentSetups),
        optimalRatios: this.findOptimalRiskRewardRatios(recentSetups),
        timeBasedPatterns: this.analyzeTimeBasedPatterns(recentSetups),
        volatilityPatterns: this.analyzeVolatilityPatterns(recentSetups)
      };

      // Update learning patterns
      this.riskRewardPatterns = patterns;

      await this.log(`🧠 Updated R/R learning: ${patterns.stopLossPatterns.length} SL patterns, ${patterns.takeProfitPatterns.length} TP patterns`);

      return patterns;
    } catch (error) {
      await this.log(`❌ Error updating R/R learning: ${error.message}`);
      return null;
    }
  }

  /**
   * Analyze stop loss effectiveness patterns
   */
  analyzeStopLossPatterns(setups) {
    const patterns = [];
    
    // Group by stop loss distance ranges
    const slRanges = [
      { min: 0, max: 1, label: 'Tight (0-1%)' },
      { min: 1, max: 3, label: 'Normal (1-3%)' },
      { min: 3, max: 5, label: 'Wide (3-5%)' },
      { min: 5, max: 100, label: 'Very Wide (>5%)' }
    ];

    for (const range of slRanges) {
      const rangeSetups = setups.filter(s => 
        s.stopLossDistance >= range.min && s.stopLossDistance < range.max
      );

      if (rangeSetups.length >= 3) {
        const stopLossHits = rangeSetups.filter(s => s.exitReason === 'STOP_LOSS');
        const takeProfitHits = rangeSetups.filter(s => s.exitReason === 'TAKE_PROFIT');
        const avgScore = rangeSetups.reduce((sum, s) => sum + (s.learningScore || 0), 0) / rangeSetups.length;

        patterns.push({
          range: range.label,
          distanceRange: [range.min, range.max],
          totalSetups: rangeSetups.length,
          stopLossHitRate: (stopLossHits.length / rangeSetups.length) * 100,
          takeProfitHitRate: (takeProfitHits.length / rangeSetups.length) * 100,
          avgLearningScore: avgScore,
          effectiveness: avgScore > 0.6 ? 'HIGH' : avgScore > 0.4 ? 'MEDIUM' : 'LOW',
          recommendation: this.generateStopLossRecommendation(rangeSetups, avgScore)
        });
      }
    }

    return patterns.sort((a, b) => b.avgLearningScore - a.avgLearningScore);
  }

  /**
   * Analyze take profit effectiveness patterns  
   */
  analyzeTakeProfitPatterns(setups) {
    const patterns = [];
    
    // Group by risk/reward ratios
    const rrRanges = [
      { min: 0, max: 1, label: 'Conservative (1:0-1)' },
      { min: 1, max: 2, label: 'Balanced (1:1-2)' },
      { min: 2, max: 3, label: 'Aggressive (1:2-3)' },
      { min: 3, max: 100, label: 'Very Aggressive (1:3+)' }
    ];

    for (const range of rrRanges) {
      const rangeSetups = setups.filter(s => 
        s.riskRewardRatio >= range.min && s.riskRewardRatio < range.max
      );

      if (rangeSetups.length >= 3) {
        const takeProfitHits = rangeSetups.filter(s => s.exitReason === 'TAKE_PROFIT');
        const avgPnL = rangeSetups.reduce((sum, s) => sum + (s.actualPnL || 0), 0) / rangeSetups.length;
        const avgScore = rangeSetups.reduce((sum, s) => sum + (s.learningScore || 0), 0) / rangeSetups.length;

        patterns.push({
          range: range.label,
          rrRange: [range.min, range.max],
          totalSetups: rangeSetups.length,
          takeProfitHitRate: (takeProfitHits.length / rangeSetups.length) * 100,
          avgPnL,
          avgLearningScore: avgScore,
          profitability: avgPnL > 0 ? 'PROFITABLE' : 'UNPROFITABLE',
          recommendation: this.generateTakeProfitRecommendation(rangeSetups, avgScore, avgPnL)
        });
      }
    }

    return patterns.sort((a, b) => b.avgLearningScore - a.avgLearningScore);
  }

  /**
   * Find optimal risk/reward ratios for different market conditions
   */
  findOptimalRiskRewardRatios(setups) {
    const optimalRatios = [];

    // Group by market conditions
    const conditionGroups = {
      'High Volatility': setups.filter(s => this.getVolatility(s) > 0.08),
      'Medium Volatility': setups.filter(s => this.getVolatility(s) >= 0.04 && this.getVolatility(s) <= 0.08),
      'Low Volatility': setups.filter(s => this.getVolatility(s) < 0.04),
      'Bullish Trend': setups.filter(s => this.getTrend(s) === 'BULLISH'),
      'Bearish Trend': setups.filter(s => this.getTrend(s) === 'BEARISH'),
      'Sideways Market': setups.filter(s => this.getTrend(s) === 'SIDEWAYS')
    };

    for (const [condition, conditionSetups] of Object.entries(conditionGroups)) {
      if (conditionSetups.length >= 5) {
        const excellentSetups = conditionSetups.filter(s => s.outcomeQuality === 'EXCELLENT');
        
        if (excellentSetups.length >= 2) {
          const avgOptimalRR = excellentSetups.reduce((sum, s) => sum + s.riskRewardRatio, 0) / excellentSetups.length;
          const avgOptimalSL = excellentSetups.reduce((sum, s) => sum + s.stopLossDistance, 0) / excellentSetups.length;
          
          optimalRatios.push({
            condition,
            sampleSize: conditionSetups.length,
            excellentSamples: excellentSetups.length,
            optimalRiskReward: avgOptimalRR,
            optimalStopLoss: avgOptimalSL,
            successRate: (excellentSetups.length / conditionSetups.length) * 100,
            confidence: Math.min(0.95, excellentSetups.length / 10) // Max 95% confidence
          });
        }
      }
    }

    return optimalRatios.sort((a, b) => b.confidence - a.confidence);
  }

  /**
   * Get smart risk/reward recommendation for current setup
   */
  async getSmartRiskRewardRecommendation(requestData) {
    try {
      const { symbol, entryPrice, side, marketConditions } = requestData;
      
      // Get current market context
      const currentVolatility = marketConditions?.volatility || await this.calculateVolatility(symbol);
      const currentTrend = marketConditions?.trend || await this.analyzeMarketTrend(symbol);
      
      // Find best matching patterns
      const matchingPatterns = this.riskRewardPatterns.optimalRatios.filter(pattern => {
        if (currentVolatility > 0.08 && pattern.condition.includes('High Volatility')) return true;
        if (currentVolatility < 0.04 && pattern.condition.includes('Low Volatility')) return true;
        if (currentTrend === 'BULLISH' && pattern.condition.includes('Bullish')) return true;
        if (currentTrend === 'BEARISH' && pattern.condition.includes('Bearish')) return true;
        return false;
      });

      let recommendation = {
        stopLossDistance: 2.5, // Default 2.5%
        riskRewardRatio: 2.0,  // Default 1:2
        confidence: 0.3,
        reasoning: 'Using default values - insufficient learning data',
        learningBased: false
      };

      if (matchingPatterns.length > 0) {
        const bestPattern = matchingPatterns.reduce((best, current) => 
          current.confidence > best.confidence ? current : best
        );

        const stopLoss = side === 'LONG' ? 
          entryPrice * (1 - bestPattern.optimalStopLoss / 100) :
          entryPrice * (1 + bestPattern.optimalStopLoss / 100);

        const takeProfitDistance = bestPattern.optimalStopLoss * bestPattern.optimalRiskReward;
        const takeProfit = side === 'LONG' ?
          entryPrice * (1 + takeProfitDistance / 100) :
          entryPrice * (1 - takeProfitDistance / 100);

        recommendation = {
          stopLoss,
          takeProfit,
          stopLossDistance: bestPattern.optimalStopLoss,
          takeProfitDistance,
          riskRewardRatio: bestPattern.optimalRiskReward,
          confidence: bestPattern.confidence,
          reasoning: `Based on ${bestPattern.excellentSamples} excellent outcomes in ${bestPattern.condition}`,
          learningBased: true,
          patternMatch: bestPattern.condition,
          historicalSuccessRate: bestPattern.successRate
        };
      }

      await this.log(`🎯 R/R Recommendation: SL=${recommendation.stopLossDistance?.toFixed(2)}% RR=1:${recommendation.riskRewardRatio.toFixed(2)} (${(recommendation.confidence * 100).toFixed(1)}% confidence)`);

      return recommendation;
    } catch (error) {
      await this.log(`❌ Error generating R/R recommendation: ${error.message}`);
      return {
        stopLossDistance: 2.5,
        riskRewardRatio: 2.0,
        confidence: 0.1,
        reasoning: `Error in recommendation system: ${error.message}`,
        learningBased: false
      };
    }
  }

  // Helper methods
  calculateDistance(entryPrice, targetPrice, side) {
    if (side === 'LONG') {
      return Math.abs((entryPrice - targetPrice) / entryPrice) * 100;
    } else {
      return Math.abs((targetPrice - entryPrice) / entryPrice) * 100;
    }
  }

  calculateRiskRewardRatio(setupData) {
    if (!setupData.stopLoss || !setupData.takeProfit) return 1.0;
    
    const riskDistance = this.calculateDistance(setupData.entryPrice, setupData.stopLoss, setupData.side);
    const rewardDistance = this.calculateDistance(setupData.entryPrice, setupData.takeProfit, setupData.side);
    
    return rewardDistance / riskDistance;
  }

  getVolatility(setup) {
    try {
      const conditions = JSON.parse(setup.marketConditions || '{}');
      return conditions.volatility || 0.05;
    } catch {
      return 0.05;
    }
  }

  getTrend(setup) {
    try {
      const conditions = JSON.parse(setup.marketConditions || '{}');
      return conditions.trend || 'SIDEWAYS';
    } catch {
      return 'SIDEWAYS';
    }
  }

  generateStopLossRecommendation(setups, avgScore) {
    if (avgScore > 0.7) return 'Optimal range - continue using';
    if (avgScore > 0.5) return 'Good range with room for improvement';
    return 'Consider adjusting - poor performance';
  }

  generateTakeProfitRecommendation(setups, avgScore, avgPnL) {
    if (avgScore > 0.7 && avgPnL > 0) return 'Excellent - optimal risk/reward ratio';
    if (avgPnL > 0) return 'Profitable but could be optimized';
    return 'Needs adjustment - consider different ratio';
  }

  analyzeMarketBehaviorDuringTrade(outcomeData) {
    // Simplified market behavior analysis
    if (outcomeData.exitReason === 'TAKE_PROFIT') return 'FAVORABLE';
    if (outcomeData.exitReason === 'STOP_LOSS') return 'UNFAVORABLE';
    return 'MIXED';
  }

  async calculateVolatility(symbol) {
    // Mock volatility calculation - implement with real price data
    return Math.random() * 0.1;
  }

  async analyzeMarketTrend(symbol) {
    // Mock trend analysis - implement with real market data
    const trends = ['BULLISH', 'BEARISH', 'SIDEWAYS'];
    return trends[Math.floor(Math.random() * trends.length)];
  }

  analyzeTimeBasedPatterns(setups) {
    // Analyze performance by time of day, day of week
    const timePatterns = {};
    // Implementation for time-based analysis
    return timePatterns;
  }

  analyzeVolatilityPatterns(setups) {
    // Analyze performance in different volatility conditions
    const volPatterns = {};
    // Implementation for volatility-based analysis
    return volPatterns;
  }
}

// Export for use in other modules
module.exports = RiskRewardLearner;

// Direct execution for testing
if (require.main === module) {
  const learner = new RiskRewardLearner();
  
  console.log('🎯 Risk/Reward Learning System');
  console.log('📊 Learning from BOTH stop losses AND take profits!');
  console.log('🧠 Optimizing risk/reward ratios based on real outcomes');
}
