/**
 * TIME JUMP CONTROLLER - ISOLATED SYSTEM
 * 
 * This is a completely separate system that does NOT interfere with existing algorithms.
 * It works by filtering JSON data BEFORE it reaches the main chart algorithm.
 * 
 * Core Principle: Change the input, not the engine.
 */

class TimeJumpController {
    constructor() {
        this.originalData = null;
        this.filteredData = null;
        this.isActive = false;
        this.jumpTime = null;
        this.dataTimeRange = { start: null, end: null };
        this.currentUsername = null;
        
        this.initializeElements();
        this.bindEvents();
        this.validateTimeFormat = this.validateTimeFormat.bind(this);
        this.parseTimeToMinutes = this.parseTimeToMinutes.bind(this);
        this.formatMinutesToTime = this.formatMinutesToTime.bind(this);
        this.initializeUserSession();
    }

    /**
     * Initialize user session
     */
    async initializeUserSession() {
        try {
            const response = await fetch('./php/session_manager.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'getCurrentUser' })
            });
            const sessionData = await response.json();
            this.currentUsername = sessionData.username;
        } catch (error) {
        }
    }

    /**
     * Initialize DOM elements
     */
    initializeElements() {
        this.elements = {
            input: document.getElementById('time-jump-input'),
            button: document.getElementById('time-jump-button'),
            status: document.getElementById('time-jump-status'),
            rangeDisplay: document.getElementById('time-range-display')
        };

        // Validate all elements exist
        Object.keys(this.elements).forEach(key => {
            if (!this.elements[key]) {
            }
        });
    }

    /**
     * Bind event listeners
     */
    bindEvents() {
        if (!this.elements.input || !this.elements.button) return;

        // Input validation and formatting
        this.elements.input.addEventListener('input', (e) => {
            this.handleTimeInput(e.target.value);
        });

        // Jump button click
        this.elements.button.addEventListener('click', () => {
            this.executeTimeJump();
        });

        // Enter key support
        this.elements.input.addEventListener('keypress', (e) => {
            if (e.key === 'Enter' && !this.elements.button.disabled) {
                this.executeTimeJump();
            }
        });
    }

    /**
     * Handle time input formatting and validation
     */
    handleTimeInput(value) {
        // Auto-format time input (add colon)
        let formatted = value.replace(/[^\d]/g, '');
        if (formatted.length >= 3) {
            formatted = formatted.substring(0, 2) + ':' + formatted.substring(2, 4);
        }
        
        if (formatted !== value) {
            this.elements.input.value = formatted;
        }

        this.validateTimeInput(formatted);
    }

    /**
     * Validate time input and update UI state
     */
    validateTimeInput(timeStr) {
        const isValid = this.validateTimeFormat(timeStr);
        const isInRange = isValid && this.isTimeInDataRange(timeStr);
        
        // Update input styling
        this.elements.input.classList.remove('error', 'success');
        if (timeStr.length > 0) {
            this.elements.input.classList.add(isValid && isInRange ? 'success' : 'error');
        }

        // Update button state
        this.elements.button.disabled = !(isValid && isInRange);

        // Update status
        this.updateStatus(timeStr, isValid, isInRange);
    }

    /**
     * Update status message
     */
    updateStatus(timeStr, isValid, isInRange) {
        if (!this.elements.status) return;

        this.elements.status.className = 'time-jump-status';
        
        if (timeStr.length === 0) {
            this.elements.status.style.display = 'none';
            return;
        }

        if (!isValid) {
            this.elements.status.className += ' error';
            this.elements.status.textContent = 'Invalid time format. Use HH:MM (24-hour format)';
            this.elements.status.style.display = 'block';
        } else if (!isInRange) {
            this.elements.status.className += ' warning';
            this.elements.status.textContent = 'Time is outside available data range';
            this.elements.status.style.display = 'block';
        } else {
            this.elements.status.className += ' success';
            this.elements.status.textContent = 'Ready to jump to ' + timeStr;
            this.elements.status.style.display = 'block';
        }
    }

    /**
     * Validate time format (HH:MM)
     */
    validateTimeFormat(timeStr) {
        const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/;
        return timeRegex.test(timeStr);
    }

    /**
     * Convert time string to minutes since midnight
     */
    parseTimeToMinutes(timeStr) {
        const [hours, minutes] = timeStr.split(':').map(Number);
        return hours * 60 + minutes;
    }

    /**
     * Convert minutes since midnight to time string
     */
    formatMinutesToTime(minutes) {
        const hours = Math.floor(minutes / 60);
        const mins = minutes % 60;
        return `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}`;
    }

    /**
     * Check if time is within data range
     */
    isTimeInDataRange(timeStr) {
        if (!this.dataTimeRange.start || !this.dataTimeRange.end) return false;
        
        const targetMinutes = this.parseTimeToMinutes(timeStr);
        const startMinutes = this.parseTimeToMinutes(this.dataTimeRange.start);
        const endMinutes = this.parseTimeToMinutes(this.dataTimeRange.end);
        
        // Handle midnight crossing (e.g., 21:58 to 00:07)
        if (endMinutes < startMinutes) {
            // Range crosses midnight: accept times >= start OR <= end
            return targetMinutes >= startMinutes || targetMinutes <= endMinutes;
        }
        
        // Normal range (same day)
        return targetMinutes >= startMinutes && targetMinutes <= endMinutes;
    }
    
    /**
     * Normalize Combined_data.json wrapper format to flat {time, price} array
     * Detects {header, data} wrapper and converts array rows to objects for backward compatibility
     */
    _normalizeCombinedData(jsonData) {
        if (!jsonData) return jsonData;
        
        // Already a flat array? Return as-is
        if (Array.isArray(jsonData)) return jsonData;
        
        // Detect Combined_data.json wrapper format: { header: [...], data: [[ts, price, depth, ...], ...] }
        if (jsonData.header && Array.isArray(jsonData.data)) {
            return jsonData.data.map(row => ({
                time: row[0],
                price: row[1],
                depth: row[2],
                subMs: row[3],
                init: row[4]
            }));
        }
        
        return jsonData;
    }

    /**
     * Convert HH:MM time back to timestamp for filtering
     */
    timeToTimestamp(timeStr) {
        if (!this.originalData || this.originalData.length === 0) return null;
        
        const targetMinutes = this.parseTimeToMinutes(timeStr);
        const firstTick = this.originalData[0];
        // Support both array rows and object rows
        const firstTickTime = Array.isArray(firstTick) ? firstTick[0] : firstTick.time;
        const isMs = firstTickTime > 10000000000;
        
        // Use 60000ms for high-precision or 60s for legacy
        const minuteFactor = isMs ? 60000 : 60;
        
        return firstTickTime + (targetMinutes * minuteFactor);
    }

    /**
     * Set original data and analyze time range
     * This is called when new JSON data is loaded
     */
    setOriginalData(jsonData, datasetPath = null) {
        try {
            this.originalData = jsonData;
            
            // Store dataset path if provided
            if (datasetPath && window.chart) {
                window.chart.currentDatasetPath = datasetPath;
            }
            
            this.analyzeDataTimeRange();
            this.updateRangeDisplay();
            this.resetController();
            
        } catch (error) {
            this.showError('Failed to analyze data time range');
        }
    }

    /**
     * Analyze time range from JSON data
     */
    analyzeDataTimeRange() {
        if (!this.originalData || this.originalData.length === 0) {
            this.dataTimeRange = { start: null, end: null };
            return;
        }

        // Normalize if originalData is a Combined_data.json wrapper
        const data = this._normalizeCombinedData(this.originalData);
        this.originalData = data;

        // Extract time from first and last candle
        const firstCandle = data[0];
        const lastCandle = data[data.length - 1];
        
        const startTime = this.extractTimeFromCandle(firstCandle);
        const endTime = this.extractTimeFromCandle(lastCandle);
        
        this.dataTimeRange = {
            start: startTime,
            end: endTime
        };
    }

    /**
     * Extract time string from candle data
     */
    extractTimeFromCandle(candle) {
        // Support array-format rows from Combined_data.json: [timestamp, price, depth, subMs, init]
        if (Array.isArray(candle)) {
            if (candle[0]) return this.parseTimeFromValue(candle[0]);
            return null;
        }
        
        // Try different possible time field names for object-format rows
        const timeFields = ['time', 'timestamp', 'datetime', 't'];
        
        for (const field of timeFields) {
            if (candle[field]) {
                return this.parseTimeFromValue(candle[field]);
            }
        }
        

        return null;
    }

    /**
     * Parse time from various formats
     */
    parseTimeFromValue(timeValue) {
        if (typeof timeValue === 'string') {
            // Already in HH:MM format
            if (/^\d{1,2}:\d{2}$/.test(timeValue)) return timeValue;
            
            // Extract HH:MM from datetime string
            const timeMatch = timeValue.match(/(\d{1,2}):(\d{2})/);
            if (timeMatch) return `${timeMatch[1].padStart(2, '0')}:${timeMatch[2]}`;
        }
        
        if (typeof timeValue === 'number') {
            // 🚀 SMART TIMESTAMP DETECTION
            // If > 10,000,000,000 it is Milliseconds (Nexus Engine)
            const date = timeValue > 10000000000 ? new Date(timeValue) : new Date(timeValue * 1000);
            return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
        }
        
        return null;
    }

    /**
     * Update range display
     */
    updateRangeDisplay() {
        if (!this.elements.rangeDisplay) return;
        
        if (this.dataTimeRange && this.dataTimeRange.start && this.dataTimeRange.end) {
            this.elements.rangeDisplay.textContent = `Available: ${this.dataTimeRange.start} to ${this.dataTimeRange.end}`;
        } else {
            this.elements.rangeDisplay.textContent = 'No data loaded';
        }
    }

    /**
     * Execute time jump
     */
    async executeTimeJump() {
        const timeStr = this.elements.input.value;
        
        if (!this.validateTimeFormat(timeStr)) {
            this.showError('Invalid time format. Use HH:MM');
            return;
        }





        
        // Use direct chart approach (your system uses single chart)
        if (window.chart && window.chart.candleData && window.chart.candleData.length > 0) {
            try {
                const success = await this.executeDirectTimeJump(timeStr);
                
                if (success) {
                    this.jumpTime = timeStr;
                    this.isActive = true;
                    this.showSuccess(`Jumped to ${timeStr}. Chart will build from this time.`);
                } else {
                    this.showError('Time jump failed. Check if time is within data range.');
                }
                
            } catch (error) {
                this.showError('Failed to execute time jump');
            }
        } else {
            this.showError('Chart data not available');
        }
    }

    /**
     * Filter data from specified time
     */
    filterDataFromTime(timeStr) {
        if (!this.originalData) {
            throw new Error('No original data available');
        }

        const targetTimestamp = this.timeToTimestamp(timeStr);
        if (!targetTimestamp) {
            throw new Error('Invalid time conversion');
        }
        
        this.filteredData = this.originalData.filter(candle => {
            return candle.time >= targetTimestamp;
        });

        if (this.filteredData.length === 0) {
            throw new Error('No data found from specified time');
        }
    }

    /**
     * Get data for chart (filtered or original)
     */
    getDataForChart() {
        return this.isActive && this.filteredData ? this.filteredData : this.originalData;
    }

    /**
     * Reset controller to use original data
     */
    resetController() {
        this.isActive = false;
        this.jumpTime = null;
        this.filteredData = null;
        this.elements.input.value = '';
        this.elements.input.classList.remove('error', 'success');
        this.elements.button.disabled = true;
        this.elements.status.style.display = 'none';
    }

    /**
     * Trigger chart rebuild with current data
     */
    triggerChartRebuild() {
        // This method should be called by the main chart system
        // to rebuild the chart with the filtered data
        
        // If chart exists, load the filtered data directly
        if (window.chart && this.filteredData) {
            window.chart.loadDataset(this.filteredData, []);
            if (window.sentimentManager && window.chart.sentimentData && window.chart.sentimentData.length > 0) {
                window.sentimentManager.loadDatasetSentiment(window.chart.sentimentData);
            }
        }
        
        // Dispatch custom event that main chart system can listen to
        const event = new CustomEvent('timeJumpExecuted', {
            detail: {
                jumpTime: this.jumpTime,
                filteredData: this.filteredData,
                isActive: this.isActive
            }
        });
        
        document.dispatchEvent(event);
    }

    /**
     * Show success message
     */
    showSuccess(message) {
        if (!this.elements.status) return;
        
        this.elements.status.className = 'time-jump-status success';
        this.elements.status.textContent = message;
        this.elements.status.style.display = 'block';
    }

    /**
     * Show error message
     */
    showError(message) {
        if (!this.elements.status) return;
        
        this.elements.status.className = 'time-jump-status error';
        this.elements.status.textContent = message;
        this.elements.status.style.display = 'block';
    }

    /**
     * Check if controller is active
     */
    isControllerActive() {
        return this.isActive;
    }

    /**
     * Get current jump time
     */
    getCurrentJumpTime() {
        return this.jumpTime;
    }

    /**
     * Get active dataset path from chart instance
     */
    getActiveDatasetPath(activeAssetName) {
        // Method 1: Get from active chart instance (most reliable)
        if (window.chart && window.chart.currentDatasetPath) {
            return window.chart.currentDatasetPath;
        }
        
        // Method 2: Get from multi-chart manager
        if (window.multiChartManager && window.multiChartManager.getChart && window.multiChartManager.getChart(activeAssetName)) {
            const chart = window.multiChartManager.getChart(activeAssetName);
            if (chart && chart.currentDatasetPath) {
                return chart.currentDatasetPath;
            }
        }
        
        return null;
    }

    /**
     * Detect dataset path from active chart data (emergency fallback)
     */
    detectDatasetFromChart(activeAssetName) {
        const chart = window.chart || (window.multiChartManager && window.multiChartManager.getChart(activeAssetName));
        if (!chart || !chart.candleData || chart.candleData.length === 0) return null;
        
        // Try to reconstruct path from chart data timestamps
        const firstCandle = chart.candleData[0];
        if (firstCandle && firstCandle.time && this.currentUsername) {
            const simplifiedAssetName = activeAssetName.toLowerCase().replace(/[^a-zA-Z0-9]/g, '');
            return `./data/${this.currentUsername}/${simplifiedAssetName}/data_*/Combined_data.json`;
        }
        
        return null;
    }

    /**
     * Update time range from active asset's full dataset
     */
    async updateTimeRange() {
        try {
            const activeAssetName = document.querySelector('.asset-name')?.textContent;
            if (!activeAssetName) return;
            
            // Method 1: Try to get dataset path and fetch full data
            let datasetPath = this.getActiveDatasetPath(activeAssetName);
            if (datasetPath) {
                const response = await fetch(datasetPath);
                const rawData = await response.json();
                const fullData = this._normalizeCombinedData(rawData);
                
                if (fullData && fullData.length > 0) {
                    this.updateTimeRangeFromData(fullData);
                    return;
                }
            }
            
            // Method 2: Extract time range directly from active chart data
            const chart = window.chart || (window.multiChartManager && window.multiChartManager.getChart(activeAssetName));
            if (chart && chart.candleData && chart.candleData.length > 0) {
                
                // Get raw data from chart if available
                if (chart.rawData && chart.rawData.length > 0) {
                    this.updateTimeRangeFromData(chart.rawData);
                    return;
                }
                
                // Fallback: use processed candle data
                const firstCandle = chart.candleData[0];
                const lastCandle = chart.candleData[chart.candleData.length - 1];
                
                if (firstCandle.timestamp && lastCandle.timestamp) {
                    const timeRange = {
                        start: new Date(firstCandle.timestamp).toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', hour12: false}),
                        end: new Date(lastCandle.timestamp).toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', hour12: false})
                    };
                    
                    this.dataTimeRange = timeRange;
                    this.updateRangeDisplay();
                    return;
                }
            }
            
            // Method 3: Try auto-detection as last resort
            datasetPath = await this.autoDetectAssetPath(activeAssetName);
            if (datasetPath) {
                const response = await fetch(datasetPath);
                const rawData = await response.json();
                const fullData = this._normalizeCombinedData(rawData);
                
                if (fullData && fullData.length > 0) {
                    this.updateTimeRangeFromData(fullData);
                    return;
                }
            }
            
        } catch (error) {
        }
    }
    
    /**
     * Update time range from data array
     */
    updateTimeRangeFromData(data) {
        const firstCandle = data[0];
        const lastCandle = data[data.length - 1];
        
        // Support both array rows [ts, price, ...] and object rows {time, price, ...}
        const firstTime = Array.isArray(firstCandle) ? firstCandle[0] : firstCandle.time;
        const lastTime = Array.isArray(lastCandle) ? lastCandle[0] : lastCandle.time;
        
        const timeRange = {
            start: this.parseTimeFromValue(firstTime),
            end: this.parseTimeFromValue(lastTime)
        };
        
        // Only update if range actually changed
        const currentRange = this.dataTimeRange;
        if (!currentRange || currentRange.start !== timeRange.start || currentRange.end !== timeRange.end) {
            this.dataTimeRange = timeRange;
            this.updateRangeDisplay();
        }
    }



    /**
     * Convert HH:MM to Unix timestamp within dataset's time range
     */
    convertTimeToTimestamp(timeStr, dataArray) {
        const [inputHours, inputMinutes] = timeStr.split(':').map(Number);
        // Support both array rows [ts, ...] and object rows {time, ...}
        const firstTick = dataArray[0];
        const firstTickTime = Array.isArray(firstTick) ? firstTick[0] : firstTick.time;
        const isMs = firstTickTime > 10000000000;
        
        // Use 1000ms if input was in ms
        const dataDate = isMs ? new Date(firstTickTime) : new Date(firstTickTime * 1000);
        
        const targetDate = new Date(dataDate.getFullYear(), dataDate.getMonth(), dataDate.getDate(), inputHours, inputMinutes, 0, 0);
        
        return isMs ? targetDate.getTime() : Math.floor(targetDate.getTime() / 1000);
    }

    /**
     * Find closest candle to target timestamp
     */
    findClosestCandle(targetTimestamp, dataArray) {
        // Support both array rows [ts, ...] and object rows {time, ...}
        const getTime = (row) => Array.isArray(row) ? row[0] : row.time;
        
        // Binary search for efficiency with large datasets
        let left = 0;
        let right = dataArray.length - 1;
        let closest = dataArray[0];
        let minDiff = Math.abs(getTime(dataArray[0]) - targetTimestamp);
        
        while (left <= right) {
            const mid = Math.floor((left + right) / 2);
            const diff = Math.abs(getTime(dataArray[mid]) - targetTimestamp);
            
            if (diff < minDiff) {
                minDiff = diff;
                closest = dataArray[mid];
            }
            
            if (getTime(dataArray[mid]) < targetTimestamp) {
                left = mid + 1;
            } else if (getTime(dataArray[mid]) > targetTimestamp) {
                right = mid - 1;
            } else {
                // Exact match found
                return dataArray[mid];
            }
        }
        
        return closest;
    }

    /**
     * Execute time jump directly on the chart
     */
    async executeDirectTimeJump(timeStr) {
        const activeAssetName = document.querySelector('.asset-name')?.textContent;
        if (!activeAssetName) return false;

        let targetChart = (window.multiChartManager?.getChart(activeAssetName)) || window.chart;
        if (!targetChart || !targetChart.candleData) return false;

        try {
            let datasetPath = this.getActiveDatasetPath(activeAssetName) || await this.autoDetectAssetPath(activeAssetName);
            if (!datasetPath) return false;

            const response = await fetch(datasetPath);
            const rawData = await response.json();
            const fullData = this._normalizeCombinedData(rawData);
            
            // Helper for consistent time field access (supports both array and object rows)
            const getTime = (row) => Array.isArray(row) ? row[0] : row.time;
            
            // Generate target timestamp for jump
            const targetTimestamp = this.convertTimeToTimestamp(timeStr, fullData);
            
            // 🚀 EXACT TICK SEARCH (Replaces 'Index / 60' math)
            // Finds the exact index of the tick closest to the requested time.
            let targetRawIndex = -1;
            let minDiff = Infinity;
            for (let i = 0; i < fullData.length; i++) {
                const diff = Math.abs(getTime(fullData[i]) - targetTimestamp);
                if (diff < minDiff) {
                    minDiff = diff;
                    targetRawIndex = i;
                } else if (diff > minDiff) {
                    break; // Data is sorted by time
                }
            }

            if (targetRawIndex === -1) return false;

            if (targetChart.isPlaying) targetChart.stopAnimation();
            
            // Load dataset with RAW wrapper format so chart applies 3-branch ms/sub-ms expansion
            // Passing normalized flat array would bypass the Combined_data.json detection in loadDataset()
            targetChart.loadDataset(rawData, []);
            if (window.sentimentManager && targetChart.sentimentData && targetChart.sentimentData.length > 0) {
                window.sentimentManager.loadDatasetSentiment(targetChart.sentimentData);
            }
            
            // Wait for chart to process and calculate accurate positioning
            setTimeout(() => {
                if (targetChart.isPlaying) targetChart.stopAnimation();

                // Read current time format to determine ms vs second mode
                // Combined_data.json parent timestamps are always ~10-digit seconds,
                // so we cannot detect ms mode from the timestamp alone
                const timeFormat = window.currentTimeFormat || 'millisecond';
                const isMs = timeFormat === 'millisecond';
                const windowSize = isMs ? 60000 : 60;
                
                // Calculate correct candle index based on timestamps, NOT static index
                const jumpTick = fullData[targetRawIndex];
                const jumpTickTime = getTime(jumpTick); // Parent-second timestamp
                
                // In ms mode, window boundaries are ms-based; in second mode, second-based
                // Chart candles always use ms timestamps internally
                const jumpWindowStart = isMs
                    ? Math.floor(jumpTickTime / 60) * 60000
                    : Math.floor(jumpTickTime / 60) * 60;
                
                // Find candle that contains this window (candle timestamps are always ms)
                let targetCandleIndex = targetChart.candleData.findIndex(
                    c => c.timestamp === (isMs ? jumpWindowStart : jumpWindowStart * 1000)
                );
                
                if (targetCandleIndex === -1) targetCandleIndex = 0;
                
                // Calculate elapsed ticks within that specific candle
                const targetCandle = targetChart.candleData[targetCandleIndex];
                let targetCandleElapsed = 0;
                if (targetCandle && targetCandle.secondData && targetCandle.secondData.length > 0) {
                    if (isMs) {
                        // In ms mode, secondData entries have full ms timestamps (parentTs*1000 + subMsOffset)
                        // Find the first tick >= our target parent-second * 1000
                        const targetMsBase = jumpTickTime * 1000;
                        targetCandleElapsed = targetCandle.secondData.findIndex(d => d.time >= targetMsBase);
                    } else {
                        // In second mode, secondData entries have parent-second timestamps
                        targetCandleElapsed = targetCandle.secondData.findIndex(d => d.time >= jumpTickTime);
                    }
                    if (targetCandleElapsed === -1) targetCandleElapsed = 0;
                }

                targetChart.currentCandleIndex = targetCandleIndex;
                targetChart.currentCandleElapsed = targetCandleElapsed;
                
                // Reset animation state to prevent frame sweeps across the jump gap
                targetChart.isAnimating = false;
                
                targetChart.candleData.forEach((c, idx) => {
                    c.isComplete = idx < targetCandleIndex;
                });
                
                if (targetCandle && targetCandle.secondData && targetCandle.secondData[targetCandleElapsed]) {
                    targetChart.currentPrice = targetCandle.secondData[targetCandleElapsed].price;
                    targetChart.targetPrice = targetChart.currentPrice;
                    targetChart.currentTickTime = targetCandle.secondData[targetCandleElapsed].time; // Initialize tick time for sentiment
                }

                if (targetChart._initRunningExtremes) targetChart._initRunningExtremes();

                // Reposition Camera
                const area = targetChart.getChartArea();
                const candleSpacing = (targetChart.config.candleWidth + targetChart.config.candleGap) || 89;
                const chartCenter = area.width / 2;
                targetChart.panOffset = chartCenter - (targetCandleIndex * candleSpacing);
                
                targetChart.updateDisplays();
                targetChart.startAnimation();
            }, 500); // 500ms cooling period for dataset initialization

            return true;
        } catch (error) {
            return false;
        }
    }

    /**
     * Auto-detect dataset path for new assets
     */
    async autoDetectAssetPath(assetName) {
        // Use the existing getUserSpecificDatasetPath function from app.js
        if (window.getUserSpecificDatasetPath) {
            return await window.getUserSpecificDatasetPath(assetName);
        }
        
        // Fallback implementation
        let simplifiedAssetName = assetName.toLowerCase().replace(/[^a-zA-Z0-9]/g, '');
        
        // Only add 'otc' suffix if asset name contains '(OTC)'
        if (assetName.includes('(OTC)') && !simplifiedAssetName.endsWith('otc')) {
            simplifiedAssetName += 'otc';
        }
        
        try {
            const response = await fetch(`./php/list_datasets.php?asset=${encodeURIComponent(simplifiedAssetName)}`);
            const datasets = await response.json();
            
            if (datasets.length > 0) {
                const latestDataset = datasets[0];
                
                if (!this.currentUsername) {
                    await this.initializeUserSession();
                }
                
                if (this.currentUsername) {
                    const path = `./data/${this.currentUsername}/${simplifiedAssetName}/${latestDataset}/Combined_data.json`;
                    return path;
                }
            }
        } catch (error) {
        }
        
        return null;
    }

    /**
     * Get data statistics
     */
    getDataStats() {
        return {
            originalLength: this.originalData ? this.originalData.length : 0,
            filteredLength: this.filteredData ? this.filteredData.length : 0,
            isActive: this.isActive,
            jumpTime: this.jumpTime,
            timeRange: this.dataTimeRange
        };
    }
}

// Initialize Time Jump Controller when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
    
    // Only initialize if we're in the signals panel
    if (document.getElementById('time-jump-input')) {
        window.timeJumpController = new TimeJumpController();
        
        // Periodic checks for chart readiness
        let checkCount = 0;
        const maxChecks = 15;
        const checkInterval = setInterval(() => {
            checkCount++;
            
            if (window.chart && window.chart.candleData && window.chart.candleData.length > 0) {
                window.timeJumpController.updateTimeRange();
                clearInterval(checkInterval);
            } else if (checkCount >= maxChecks) {
                clearInterval(checkInterval);
            }
        }, 2000);
        
        // Monitor for asset name changes with debouncing
        let lastAssetName = null;
        let updateTimeout = null;
        setInterval(() => {
            const currentAssetName = document.querySelector('.asset-name')?.textContent;
            if (currentAssetName && currentAssetName !== lastAssetName) {
                lastAssetName = currentAssetName;
                // Clear previous timeout to prevent multiple updates
                if (updateTimeout) clearTimeout(updateTimeout);
                updateTimeout = setTimeout(() => {
                    window.timeJumpController.updateTimeRange();
                    updateTimeout = null;
                }, 2000);
            }
        }, 1000);
    } else {
    }
});

// Listen for asset changes to update time range
let assetClickTimeout = null;
document.addEventListener('click', (e) => {
    const assetCard = e.target.closest('.asset-card-tab');
    if (assetCard && window.timeJumpController) {
        // Clear previous timeout to prevent multiple updates
        if (assetClickTimeout) clearTimeout(assetClickTimeout);
        assetClickTimeout = setTimeout(() => {
            window.timeJumpController.updateTimeRange();
            assetClickTimeout = null;
        }, 3000);
    }
});

// Listen for chart control button clicks
document.addEventListener('click', (e) => {
    if (e.target.id === 'chart-play-btn' || e.target.closest('#chart-play-btn')) {
        setTimeout(() => {
            if (window.timeJumpController) {
                window.timeJumpController.updateTimeRange();
            }
        }, 2000);
    }
});

// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
    module.exports = TimeJumpController;
}