// Signal Calculator - orchestrates signal calculation using indicator-specific functions
// Signal calculation logic is now in each indicator file

import { IndicatorRegistry, getSignalFunction } from '../indicators/index.js';

/**
 * Calculate signal for an indicator
 * @param {Object} indicator - Indicator configuration
 * @param {Array} candles - Candle data array
 * @param {Object} indicatorValues - Computed indicator values for last candle
 * @param {Object} prevIndicatorValues - Computed indicator values for previous candle
 * @returns {Object} Signal object with type, strength, value, reasoning
 */
function calculateIndicatorSignal(indicator, candles, indicatorValues, prevIndicatorValues) {
    const signalFunction = getSignalFunction(indicator.type);
    
    if (!signalFunction) {
        console.warn('[Signals] No signal function for indicator type:', indicator.type);
        return null;
    }
    
    const lastCandle = candles[candles.length - 1];
    const prevCandle = candles[candles.length - 2];
    
    return signalFunction(indicator, lastCandle, prevCandle, indicatorValues, prevIndicatorValues);
}

/**
 * Calculate aggregate summary signal from all indicators
 */
export function calculateSummarySignal(signals) {
    console.log('[calculateSummarySignal] Input signals:', signals?.length);
    
    if (!signals || signals.length === 0) {
        return {
            signal: 'hold',
            strength: 0,
            reasoning: 'No active indicators',
            buyCount: 0,
            sellCount: 0,
            holdCount: 0
        };
    }
    
    const buySignals = signals.filter(s => s.signal === 'buy');
    const sellSignals = signals.filter(s => s.signal === 'sell');
    const holdSignals = signals.filter(s => s.signal === 'hold');
    
    const buyCount = buySignals.length;
    const sellCount = sellSignals.length;
    const holdCount = holdSignals.length;
    const total = signals.length;
    
    console.log('[calculateSummarySignal] BUY:', buyCount, 'SELL:', sellCount, 'HOLD:', holdCount);
    
    const buyWeight = buySignals.reduce((sum, s) => sum + (s.strength || 0), 0);
    const sellWeight = sellSignals.reduce((sum, s) => sum + (s.strength || 0), 0);
    
    let summarySignal, strength, reasoning;
    
    if (buyCount > sellCount && buyCount > holdCount) {
        summarySignal = 'buy';
        const avgBuyStrength = buyWeight / buyCount;
        strength = Math.round(avgBuyStrength * (buyCount / total));
        reasoning = `${buyCount} buy signals, ${sellCount} sell, ${holdCount} hold`;
    } else if (sellCount > buyCount && sellCount > holdCount) {
        summarySignal = 'sell';
        const avgSellStrength = sellWeight / sellCount;
        strength = Math.round(avgSellStrength * (sellCount / total));
        reasoning = `${sellCount} sell signals, ${buyCount} buy, ${holdCount} hold`;
    } else {
        summarySignal = 'hold';
        strength = 30;
        reasoning = `Mixed signals: ${buyCount} buy, ${sellCount} sell, ${holdCount} hold`;
    }
    
    const result = {
        signal: summarySignal,
        strength: Math.min(Math.max(strength, 0), 100),
        reasoning,
        buyCount,
        sellCount,
        holdCount,
        color: summarySignal === 'buy' ? '#26a69a' : summarySignal === 'sell' ? '#ef5350' : '#787b86'
    };
    
    console.log('[calculateSummarySignal] Result:', result);
    return result;
}

/**
 * Calculate historical crossovers for all indicators based on full candle history
 * Finds the last time each indicator crossed from BUY to SELL or SELL to BUY
 */
function calculateHistoricalCrossovers(activeIndicators, candles) {
    activeIndicators.forEach(indicator => {
        const indicatorType = indicator.type || indicator.indicatorType;
        
        // Recalculate indicator values for all candles (use cache if valid)
        let results = indicator.cachedResults;
        if (!results || !Array.isArray(results) || results.length !== candles.length) {
            const IndicatorClass = IndicatorRegistry[indicatorType];
            if (!IndicatorClass) return;
            const instance = new IndicatorClass(indicator);
            results = instance.calculate(candles);
            // Don't save back to cache here, let drawIndicatorsOnChart be the source of truth for cache
        }
        
        if (!results || !Array.isArray(results) || results.length === 0) return;
        
        // Find the most recent crossover by going backwards from the newest candle
        // candles are sorted oldest first, newest last
        let lastCrossoverTimestamp = null;
        let lastSignalType = null;
        
        // Get indicator-specific parameters
        const overbought = indicator.params?.overbought || 70;
        const oversold = indicator.params?.oversold || 30;
        
        for (let i = candles.length - 1; i > 0; i--) {
            const candle = candles[i];       // newer candle
            const prevCandle = candles[i-1]; // older candle
            
            const result = results[i];
            const prevResult = results[i-1];
            
            if (!result || !prevResult) continue;
            
            // Handle different indicator types
            if (indicatorType === 'rsi' || indicatorType === 'stoch') {
                // RSI/Stochastic: check crossing overbought/oversold levels
                const rsi = result.rsi !== undefined ? result.rsi : result;
                const prevRsi = prevResult.rsi !== undefined ? prevResult.rsi : prevResult;
                
                if (rsi === undefined || prevRsi === undefined) continue;
                
                // SELL: crossed down through overbought (was above, now below)
                if (prevRsi > overbought && rsi <= overbought) {
                    lastCrossoverTimestamp = candle.time;
                    lastSignalType = 'sell';
                    break;
                }
                // BUY: crossed up through oversold (was below, now above)
                if (prevRsi < oversold && rsi >= oversold) {
                    lastCrossoverTimestamp = candle.time;
                    lastSignalType = 'buy';
                    break;
                }
            } else if (indicatorType === 'hurst') {
                // Hurst Bands: check price crossing bands
                const upper = result.upper;
                const lower = result.lower;
                const prevUpper = prevResult.upper;
                const prevLower = prevResult.lower;
                
                if (upper === undefined || lower === undefined || 
                    prevUpper === undefined || prevLower === undefined) continue;
                
                // BUY: price crossed down below lower band
                if (prevCandle.close > prevLower && candle.close < lower) {
                    lastCrossoverTimestamp = candle.time;
                    lastSignalType = 'buy';
                    break;
                }
                // SELL: price crossed down below upper band
                if (prevCandle.close > prevUpper && candle.close < upper) {
                    lastCrossoverTimestamp = candle.time;
                    lastSignalType = 'sell';
                    break;
                }
            } else {
                // MA-style: check price crossing MA
                const ma = result.ma !== undefined ? result.ma : result;
                const prevMa = prevResult.ma !== undefined ? prevResult.ma : prevResult;
                
                if (ma === undefined || prevMa === undefined) continue;
                
                // Check crossover: price was on one side of MA, now on the other side
                const priceAbovePrev = prevCandle.close > prevMa;
                const priceAboveNow = candle.close > ma;
                
                // SELL signal: price crossed from above to below MA
                if (priceAbovePrev && !priceAboveNow) {
                    lastCrossoverTimestamp = candle.time;
                    lastSignalType = 'sell';
                    break;
                }
                // BUY signal: price crossed from below to above MA
                if (!priceAbovePrev && priceAboveNow) {
                    lastCrossoverTimestamp = candle.time;
                    lastSignalType = 'buy';
                    break;
                }
            }
        }
        
        // Always update the timestamp based on current data
        // If crossover found use that time, otherwise use last candle time
        if (lastCrossoverTimestamp) {
            console.log(`[HistoricalCross] ${indicatorType}: Found ${lastSignalType} crossover at ${new Date(lastCrossoverTimestamp * 1000).toLocaleString()}`);
            indicator.lastSignalTimestamp = lastCrossoverTimestamp;
            indicator.lastSignalType = lastSignalType;
        } else {
            // No crossover found - use last candle time
            const lastCandleTime = candles[candles.length - 1]?.time;
            if (lastCandleTime) {
                const lastResult = results[results.length - 1];
                
                if (indicatorType === 'rsi' || indicatorType === 'stoch') {
                    // RSI/Stochastic: use RSI level to determine signal
                    const rsi = lastResult?.rsi !== undefined ? lastResult.rsi : lastResult;
                    if (rsi !== undefined) {
                        indicator.lastSignalType = rsi > overbought ? 'sell' : (rsi < oversold ? 'buy' : null);
                        indicator.lastSignalTimestamp = lastCandleTime;
                    }
                } else if (indicatorType === 'hurst') {
                    // Hurst Bands: use price vs bands
                    const upper = lastResult?.upper;
                    const lower = lastResult?.lower;
                    const currentPrice = candles[candles.length - 1]?.close;
                    if (upper !== undefined && lower !== undefined && currentPrice !== undefined) {
                        if (currentPrice < lower) {
                            indicator.lastSignalType = 'buy';
                        } else if (currentPrice > upper) {
                            indicator.lastSignalType = 'sell';
                        } else {
                            indicator.lastSignalType = null;
                        }
                        indicator.lastSignalTimestamp = lastCandleTime;
                    }
                } else {
                    // MA-style: use price vs MA
                    const ma = lastResult?.ma !== undefined ? lastResult.ma : lastResult;
                    if (ma !== undefined) {
                        const isAbove = candles[candles.length - 1].close > ma;
                        indicator.lastSignalType = isAbove ? 'buy' : 'sell';
                        indicator.lastSignalTimestamp = lastCandleTime;
                    }
                }
            }
        }
    });
}

/**
 * Calculate signals for all active indicators
 * @returns {Array} Array of indicator signals
 */
export function calculateAllIndicatorSignals() {
    const activeIndicators = window.getActiveIndicators?.() || [];
    const candles = window.dashboard?.allData?.get(window.dashboard?.currentInterval);
    
    //console.log('[Signals] ========== calculateAllIndicatorSignals START ==========');
    console.log('[Signals] Active indicators:', activeIndicators.length, 'Candles:', candles?.length || 0);
    
    if (!candles || candles.length < 2) {
        //console.log('[Signals] Insufficient candles available:', candles?.length || 0);
        return [];
    }
    
    if (!activeIndicators || activeIndicators.length === 0) {
        //console.log('[Signals] No active indicators');
        return [];
    }
    
    const signals = [];
    
    // Calculate crossovers for all indicators based on historical data
    calculateHistoricalCrossovers(activeIndicators, candles);
    
    for (const indicator of activeIndicators) {
        const IndicatorClass = IndicatorRegistry[indicator.type];
        if (!IndicatorClass) {
            console.log('[Signals] No class for indicator type:', indicator.type);
            continue;
        }
        
        // Use cached results if available, otherwise calculate
        let results = indicator.cachedResults;
        let meta = indicator.cachedMeta;
        
        if (!results || !meta || !Array.isArray(results) || results.length !== candles.length) {
            const instance = new IndicatorClass(indicator);
            meta = instance.getMetadata();
            results = instance.calculate(candles);
            indicator.cachedResults = results;
            indicator.cachedMeta = meta;
        }
        
        if (!results || !Array.isArray(results) || results.length === 0) {
            console.log('[Signals] No valid results for indicator:', indicator.type);
            continue;
        }
        
        const lastResult = results[results.length - 1];
        const prevResult = results[results.length - 2];
        if (lastResult === null || lastResult === undefined) {
            console.log('[Signals] No valid last result for indicator:', indicator.type);
            continue;
        }
        
        let values;
        let prevValues;
        if (typeof lastResult === 'object' && lastResult !== null && !Array.isArray(lastResult)) {
            values = lastResult;
            prevValues = prevResult;
        } else if (typeof lastResult === 'number') {
            values = { ma: lastResult };
            prevValues = prevResult ? { ma: prevResult } : undefined;
        } else {
            console.log('[Signals] Unexpected result type for', indicator.type, ':', typeof lastResult);
            continue;
        }
        
        const signal = calculateIndicatorSignal(indicator, candles, values, prevValues);
        
        let currentSignal = signal;
        let lastSignalDate = indicator.lastSignalTimestamp || null;
        let lastSignalType = indicator.lastSignalType || null;
        
        if (!currentSignal || !currentSignal.type) {
            console.log('[Signals] No valid signal for', indicator.type, '- Using last signal if available');
            
            if (lastSignalType && lastSignalDate) {
                currentSignal = {
                    type: lastSignalType,
                    strength: 50,
                    value: candles[candles.length - 1]?.close,
                    reasoning: `No crossover (price equals MA)`
                };
            } else {
                console.log('[Signals] No previous signal available - Skipping');
                continue;
            }
        } else {
            const currentCandleTimestamp = candles[candles.length - 1].time;
            
            if (currentSignal.type !== lastSignalType || !lastSignalType) {
                console.log('[Signals] Signal changed for', indicator.type, ':', lastSignalType, '->', currentSignal.type);
                lastSignalDate = indicator.lastSignalTimestamp || currentCandleTimestamp;
                lastSignalType = currentSignal.type;
                indicator.lastSignalTimestamp = lastSignalDate;
                indicator.lastSignalType = lastSignalType;
            }
        }
        
        signals.push({
            id: indicator.id,
            name: meta?.name || indicator.type,
            label: indicator.type?.toUpperCase(),
            params: meta?.inputs && meta.inputs.length > 0
                ? indicator.params[meta.inputs[0].name]
                : null,
            type: indicator.type,
            signal: currentSignal.type,
            strength: Math.round(currentSignal.strength),
            value: currentSignal.value,
            reasoning: currentSignal.reasoning,
            color: currentSignal.type === 'buy' ? '#26a69a' : currentSignal.type === 'sell' ? '#ef5350' : '#787b86',
            lastSignalDate: lastSignalDate
        });
    }
    
    //console.log('[Signals] ========== calculateAllIndicatorSignals END ==========');
    console.log('[Signals] Total signals calculated:', signals.length);
    return signals;
}