/**
 * Range-Only Visible Zone - Keep Intervals, Change Range
 */

class RangeOnlyVisibleZone {
    constructor(chart) {
        this.chart = chart;
        this.originalGetPriceRange = null;
        this.stableRange = null;
        this.lastUpdateTime = 0;
        this.animationRange = null;
        this.animationStart = 0;
        this.animationDuration = 400; // 400ms smooth transition
    }

    activate() {
        if (!this.chart.getPriceRange) return;
        
        this.originalGetPriceRange = this.chart.getPriceRange.bind(this.chart);
        
        // OVERRIDE WITH STRICT 6-10 LINE ENFORCEMENT
        this.chart.getPriceRange = () => {
            const original = this.originalGetPriceRange();
            const enforced = this.enforceGridLines(original);
            
            return enforced;
        };
        

    }

    enforceGridLines(original) {
        const now = Date.now();
        
        // ALLOW FASTER UPDATES DURING ANIMATION
        const updateThreshold = this.animationRange ? 50 : 800;
        if (this.stableRange && (now - this.lastUpdateTime) < updateThreshold) {
            return this.stableRange;
        }
        
        // GET ASSET-SPECIFIC INTERVALS
        const assetName = this.chart.assetName || document.querySelector('.asset-name')?.textContent;
        const assetConfig = this.getAssetConfig(assetName);
        const baseInterval = assetConfig.baseInterval;
        const availableIntervals = assetConfig.priceInterval;
        
        // REVERSAL BOX TARGETING
        const reversalBoxes = this.chart.reversalBoxes || [];
        const topReversals = reversalBoxes.filter(box => box.type === 'top');
        const bottomReversals = reversalBoxes.filter(box => box.type === 'bottom');
        
        let targetHigh, targetLow;
        
        if (topReversals.length > 0 && bottomReversals.length > 0) {
            targetHigh = Math.max(...topReversals.map(box => box.price));
            targetLow = Math.min(...bottomReversals.map(box => box.price));
        } else {
            const candles = this.chart.getVisibleCandles();
            if (!candles?.length) return original;
            
            const prices = [];
            candles.forEach(c => {
                if (c.isComplete) {
                    prices.push(c.high, c.low);
                } else {
                    if (this.chart.runningHigh) prices.push(this.chart.runningHigh);
                    if (this.chart.runningLow) prices.push(this.chart.runningLow);
                }
            });
            
            if (this.chart.currentPrice) prices.push(this.chart.currentPrice);
            targetHigh = Math.max(...prices);
            targetLow = Math.min(...prices);
        }
        
        // SMOOTH ANIMATION IN PROGRESS
        if (this.animationRange && (now - this.animationStart) < this.animationDuration) {
            const progress = (now - this.animationStart) / this.animationDuration;
            const eased = this.easeInOut(progress);
            
            return {
                ...original,
                min: this.lerp(this.animationRange.fromMin, this.animationRange.toMin, eased),
                max: this.lerp(this.animationRange.fromMax, this.animationRange.toMax, eased),
                interval: this.animationRange.interval
            };
        }
        
        // FORCE BASELINE PREFERENCE - Always try baseInterval first
        let optimalInterval = baseInterval;
        let finalMin, finalMax;
        
        // Try baseline interval first
        const baseTopLine = Math.ceil(targetHigh / baseInterval) * baseInterval + baseInterval;
        const baseBottomLine = Math.floor(targetLow / baseInterval) * baseInterval - baseInterval;
        const baseLines = Math.floor((baseTopLine - baseBottomLine) / baseInterval) + 1;
        
        if (baseLines <= 6) {
            // Baseline works perfectly - use 6 lines
            const additionalLines = 6 - baseLines;
            const expandTop = Math.ceil(additionalLines / 2);
            const expandBottom = Math.floor(additionalLines / 2);
            
            finalMax = baseTopLine + (expandTop * baseInterval);
            finalMin = baseBottomLine - (expandBottom * baseInterval);

        } else if (baseLines <= 10) {
            // Baseline fits within limits - use it
            finalMax = baseTopLine;
            finalMin = baseBottomLine;

        } else {
            // Baseline creates too many lines - try larger intervals
            let intervalFound = false;
            
            for (const testInterval of availableIntervals.slice().reverse()) {
                if (testInterval <= baseInterval) continue;
                
                const testTopLine = Math.ceil(targetHigh / testInterval) * testInterval + testInterval;
                const testBottomLine = Math.floor(targetLow / testInterval) * testInterval - testInterval;
                const testLines = Math.floor((testTopLine - testBottomLine) / testInterval) + 1;
                
                if (testLines <= 10) {
                    optimalInterval = testInterval;
                    finalMax = testTopLine;
                    finalMin = testBottomLine;
                    intervalFound = true;

                    break;
                }
            }
            
            if (!intervalFound) {
                // Use largest available interval and contract to 10 lines
                const largestInterval = Math.max(...availableIntervals);
                optimalInterval = largestInterval;
                const largeTopLine = Math.ceil(targetHigh / largestInterval) * largestInterval + largestInterval;
                const largeBottomLine = Math.floor(targetLow / largestInterval) * largestInterval - largestInterval;
                const largeLines = Math.floor((largeTopLine - largeBottomLine) / largestInterval) + 1;
                
                if (largeLines > 10) {
                    const excessLines = largeLines - 10;
                    const contractTop = Math.ceil(excessLines / 2);
                    const contractBottom = Math.floor(excessLines / 2);
                    
                    finalMax = largeTopLine - (contractTop * largestInterval);
                    finalMin = largeBottomLine + (contractBottom * largestInterval);
                } else {
                    finalMax = largeTopLine;
                    finalMin = largeBottomLine;
                }

            }
        }
        
        // CHECK IF CURRENT RANGE IS STABLE
        if (this.stableRange && this.stableRange.interval === optimalInterval) {
            const buffer = optimalInterval * 0.5;
            if (targetLow >= (this.stableRange.min + buffer) && 
                targetHigh <= (this.stableRange.max - buffer)) {
                return this.stableRange;
            }
        }
        
        const newRange = {
            ...original,
            min: finalMin,
            max: finalMax,
            interval: optimalInterval
        };
        
        // START ANIMATION IF RANGE OR INTERVAL CHANGED
        if (this.stableRange && 
            (Math.abs(finalMin - this.stableRange.min) > optimalInterval * 0.01 || 
             Math.abs(finalMax - this.stableRange.max) > optimalInterval * 0.01 ||
             this.stableRange.interval !== optimalInterval)) {
            
            this.animationRange = {
                fromMin: this.stableRange.min,
                fromMax: this.stableRange.max,
                toMin: finalMin,
                toMax: finalMax,
                interval: optimalInterval
            };
            this.animationStart = now;
            
            this.triggerAnimation();

        }
        
        this.stableRange = newRange;
        this.lastUpdateTime = now;
        return newRange;
    }
    
    getAssetConfig(assetName) {
        if (typeof getAssetConfig === 'function') {
            return getAssetConfig(assetName);
        }
        return {
            decimalPoints: 4,
            pipValue: 0.0001,
            baseInterval: 0.020,
            priceInterval: [0.020, 0.050, 0.100]
        };
    }
    
    // ANIMATION HELPER FUNCTIONS
    lerp(start, end, progress) {
        return start + (end - start) * progress;
    }
    
    easeInOut(t) {
        return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
    }
    
    triggerAnimation() {
        // Multiple methods to force chart updates
        const animationLoop = () => {
            if (!this.animationRange || (Date.now() - this.animationStart) >= this.animationDuration) {
                return;
            }
            
            // Try multiple ways to trigger chart redraw
            if (this.chart.draw) this.chart.draw();
            if (this.chart.render) this.chart.render();
            if (this.chart.update) this.chart.update();
            
            // Force canvas redraw by triggering resize event
            if (this.chart.setupCanvas) {
                setTimeout(() => this.chart.setupCanvas(), 0);
            }
            
            // Continue animation
            requestAnimationFrame(animationLoop);
        };
        
        // Start animation loop
        requestAnimationFrame(animationLoop);
        
        // Also use interval as backup
        const backupInterval = setInterval(() => {
            if (!this.animationRange || (Date.now() - this.animationStart) >= this.animationDuration) {
                clearInterval(backupInterval);
                return;
            }
            
            // Force window resize event to trigger chart redraw
            window.dispatchEvent(new Event('resize'));
        }, 16);
    }
}

// ACTIVATE
setTimeout(() => {
    if (window.chart) {
        window.chart.rangeZone = new RangeOnlyVisibleZone(window.chart);
        window.chart.rangeZone.activate();
    }
}, 500);