/**
 * Creates and manages all indicator-related logic for the chart.
 * @param {Object} chart - The Lightweight Charts instance.
 * @param {Array<Object>} baseCandleDataRef - A reference to the array holding the chart's BASE 1m candle data.
 * @param {Array<Object>} displayedCandleDataRef - A reference to the array with currently visible candles.
 * @returns {Object} A manager object with public methods to control indicators.
 */
function createIndicatorManager(chart, baseCandleDataRef, displayedCandleDataRef) {
    // --- FIX: --- Added `debounceTimerId` to each slot object to track pending updates.
    const indicatorSlots = [
        { id: 1, cellId: 'indicator-cell-1', series: [], definition: null, params: {}, calculator: null, debounceTimerId: null },
        { id: 2, cellId: 'indicator-cell-2', series: [], definition: null, params: {}, calculator: null, debounceTimerId: null },
        { id: 3, cellId: 'indicator-cell-3', series: [], definition: null, params: {}, calculator: null, debounceTimerId: null },
        { id: 4, cellId: 'indicator-cell-4', series: [], definition: null, params: {}, calculator: null, debounceTimerId: null },
    ];

    const colors = {
        bb: {
            bb1_upper: 'rgba(128, 25, 34, 0.5)',
            bb2_upper: 'rgba(128, 25, 34, 0.75)',
            bb3_upper: 'rgba(128, 25, 34, 1)',
            bb1_lower: 'rgba(6, 95, 6, 0.5)',
            bb2_lower: 'rgba(6, 95, 6, 0.75)',
            bb3_lower: 'rgba(6, 95, 6, 1.0)',
        },
        hurst: { topBand: '#787b86', bottomBand: '#787b86', topBand_h: '#673ab7', bottomBand_h: '#673ab7' },
        default: ['#00BCD4', '#FFEB3B', '#4CAF50', '#E91E63']
    };

    function populateDropdowns() {
        indicatorSlots.forEach(slot => {
            const cell = document.getElementById(slot.cellId);
            if (!cell) return;

            const select = document.createElement('select');
            select.innerHTML = `<option value="">-- Select Indicator --</option>`;
            AVAILABLE_INDICATORS.forEach(ind => {
                select.innerHTML += `<option value="${ind.name}">${ind.label}</option>`;
            });

            const controlsContainer = document.createElement('div');
            controlsContainer.className = 'indicator-controls';

            cell.innerHTML = '';
            cell.appendChild(select);
            cell.appendChild(controlsContainer);

            select.addEventListener('change', (e) => loadIndicator(slot.id, e.target.value));
        });
    }

    function loadIndicator(slotId, indicatorName) {
        const slot = indicatorSlots.find(s => s.id === slotId);
        if (!slot) return;

        // --- FIX: --- Cancel any pending debounced update from the previous indicator's controls.
        // This is the core of the fix, preventing the race condition.
        if (slot.debounceTimerId) {
            clearTimeout(slot.debounceTimerId);
            slot.debounceTimerId = null;
        }

        slot.series.forEach(s => chart.removeSeries(s));
        slot.series = [];
        slot.definition = null;
        slot.params = {};
        slot.calculator = null;

        const controlsContainer = document.querySelector(`#${slot.cellId} .indicator-controls`);
        controlsContainer.innerHTML = '';

        if (!indicatorName) return;

        const definition = AVAILABLE_INDICATORS.find(ind => ind.name === indicatorName);
        if (!definition) return;

        slot.definition = definition;

        definition.params.forEach(param => {
            const label = document.createElement('label');
            label.textContent = param.label || param.name;
            label.style.fontSize = '12px';

            const input = document.createElement('input');
            input.type = param.type;
            input.value = param.defaultValue;
            if (param.min !== undefined) input.min = param.min;
            if (param.step !== undefined) input.step = param.step;
            input.className = 'input-field';
            slot.params[param.name] = input.type === 'number' ? parseFloat(input.value) : input.value;

            input.addEventListener('input', () => {
                // --- FIX: --- Use the slot's `debounceTimerId` property to manage the timeout.
                clearTimeout(slot.debounceTimerId);
                slot.debounceTimerId = setTimeout(() => {
                    slot.params[param.name] = input.type === 'number' ? parseFloat(input.value) : input.value;
                    updateIndicator(slot.id, true);
                    slot.debounceTimerId = null; // Clear the ID after the function has run.
                }, 500);
            });
            const controlGroup = document.createElement('div');
            controlGroup.style.display = 'flex';
            controlGroup.style.flexDirection = 'column';
            controlGroup.appendChild(label);
            controlGroup.appendChild(input);
            controlsContainer.appendChild(controlGroup);
        });

        updateIndicator(slot.id, true);
    }

    function updateIndicator(slotId, isFullRecalculation = false) {
        const slot = indicatorSlots.find(s => s.id === slotId);
        if (!slot || !slot.definition) return;

        const candleDataForCalc = (slot.definition.usesBaseData) ? baseCandleDataRef : displayedCandleDataRef;
        if (candleDataForCalc.length === 0) return;


        if (isFullRecalculation) {
            slot.series.forEach(s => chart.removeSeries(s));
            slot.series = [];

            const indicatorResult = slot.definition.calculateFull(candleDataForCalc, slot.params);

            if (typeof indicatorResult === 'object' && !Array.isArray(indicatorResult)) {
                Object.keys(indicatorResult).forEach(key => {
                    const seriesData = indicatorResult[key];
                    const indicatorNameLower = slot.definition.name.toLowerCase();
                    const series = chart.addLineSeries({
                        color: (colors[indicatorNameLower] && colors[indicatorNameLower][key]) ? colors[indicatorNameLower][key] : colors.default[slot.id - 1],
                        lineWidth: 1,
                        title: '',
                        lastValueVisible: false,
                        priceLineVisible: false,
                    });
                    series.setData(seriesData);
                    slot.series.push(series);
                });
            } else {
                const series = chart.addLineSeries({
                    color: colors.default[slot.id - 1],
                    lineWidth: 1,
                    title: '',
                    lastValueVisible: false,
                    priceLineVisible: false,
                });
                series.setData(indicatorResult);
                slot.series.push(series);
            }

            if (slot.definition.createRealtime) {
                slot.calculator = slot.definition.createRealtime(slot.params);
                slot.calculator.prime(candleDataForCalc);
            }
        } else if (slot.calculator) {
            const lastCandle = candleDataForCalc[candleDataForCalc.length - 1];
            if (!lastCandle) return;

            const newPoint = slot.calculator.update(lastCandle);

            if (newPoint && typeof newPoint === 'object') {
                if (slot.series.length > 1) { // Multi-line indicator
                    Object.keys(newPoint).forEach((key, index) => {
                        if (slot.series[index] && newPoint[key]) {
                            slot.series[index].update(newPoint[key]);
                        }
                    });
                } else if (slot.series.length === 1) { // Single-line indicator
                    slot.series[0].update(newPoint);
                }
            }
        }
    }

    function recalculateAllAfterHistory(baseData, displayedData) {
        baseCandleDataRef = baseData;
        displayedCandleDataRef = displayedData;

        // --- FIX: --- Clear any pending debounced updates from parameter changes.
        // This prevents a stale update from a parameter input from running after 
        // the chart has already been reset for a new timeframe.
        indicatorSlots.forEach(slot => {
            if (slot.debounceTimerId) {
                clearTimeout(slot.debounceTimerId);
                slot.debounceTimerId = null;
            }
        });

        // --- FIX: --- Defer the full recalculation to the next frame.
        // This prevents a race condition where indicators are removed/added while the chart
        // is still processing the main series' `setData` operation from a timeframe change.
        setTimeout(() => {
            indicatorSlots.forEach(slot => {
                if (slot.definition) {
                    updateIndicator(slot.id, true);
                }
            });
        }, 0);
    }

    function updateAllOnNewCandle() {
        indicatorSlots.forEach(slot => {
            if (slot.definition) {
                updateIndicator(slot.id, false);
            }
        });
    }

    return {
        populateDropdowns,
        recalculateAllAfterHistory,
        updateAllOnNewCandle,
    };
}
