class User_Interface {
    constructor() {
        // Initialize all components needed by the user interface
        this.strats = new Strategies();
        this.exchanges = new Exchanges();
        this.data = new Data();
        this.controls = new Controls();
        this.alerts = new Alerts("alert_list");
        this.trade = new Trade();
        this.users = new Users();
        this.indicators = new Indicators(this.data.comms);
        this.signals = new Signals(this);
        this.formations = new Formations(this);
        this.chartAnalysis = new ChartAnalysis();
        this.backtesting = new Backtesting(this);
        this.statistics = new Statistics(this.data.comms);
        this.account = new Account();

        // Register a callback function for when indicator updates are received from the data object
        this.data.registerCallback_i_updates(this.indicators.update.bind(this.indicators));

        // Initialize all components after the page has loaded and Blockly is ready
        this.initializeAll();
    }

    async initializeAll() {
        window.addEventListener('load', async () => {
            try {
                await this.data.initialize(); // Wait for initialization
                this.initializeChartsAndIndicators();

                // Initialize other UI components here
                this.initializeResizablePopup("new_strat_form", this.strats.resizeWorkspace.bind(this.strats), "draggable_header", "resize-strategy");
                this.initializeResizablePopup("backtest_form", null, "backtest_draggable_header", "resize-backtest");
                this.initializeResizablePopup("exchanges_config_form", null, "exchange_draggable_header", "resize-exchange");
                this.initializeResizablePopup("new_ind_form", null, "indicator_draggable_header", "resize-indicator");
                this.initializeResizablePopup("new_sig_form", null, "signal_draggable_header", "resize-signal");
                this.initializeResizablePopup("new_signal_type_form", null, "signal_type_draggable_header", "resize-signal-type");
                this.initializeResizablePopup("external_indicator_form", null, "external_indicator_header", "resize-external-indicator");
                this.initializeResizablePopup("edit_indicator_form", null, "edit_indicator_header", null);
                this.initializeResizablePopup("new_trade_form", null, "trade_draggable_header", "resize-trade");
                this.initializeResizablePopup("ai_strategy_form", null, "ai_strategy_header", "resize-ai-strategy");

                // Account settings popups
                this.initializeResizablePopup("account_settings_form", null, "account_settings_header", "resize-account");
                this.initializeResizablePopup("wallet_setup_modal", null, "wallet_setup_header", "resize-wallet-setup");
                this.initializeResizablePopup("wallet_keys_modal", null, "wallet_keys_header", "resize-wallet-keys");
                this.initializeResizablePopup("view_keys_modal", null, "view_keys_header", "resize-view-keys");
                this.initializeResizablePopup("withdraw_modal", null, "withdraw_header", "resize-withdraw");
                this.initializeResizablePopup("credit_modal", null, "credit_header", "resize-credit");

                // Trade details and login popups
                this.initializeResizablePopup("trade_details_form", null, "trade_details_header", "resize-trade-details");
                this.initializeResizablePopup("login_popup", null, "login_draggable_header", null);

                // Initialize Backtesting's DOM elements
                this.backtesting.initialize();
            } catch (error) {
                console.error('Initialization failed:', error);
            }
        });
    }

    initializeChartsAndIndicators() {
        let chart_init_data = {
            chart1_id: this.data.chart1_id,
            chart2_id: this.data.chart2_id,
            chart3_id: this.data.chart3_id,
            chart4_id: this.data.chart4_id,
            chart5_id: this.data.chart5_id,
            trading_pair: this.data.trading_pair,
            price_history: this.data.price_history
        };
        this.charts = new Charts(chart_init_data);

        let ind_init_data = {
            indicators: this.data.indicators,
            indicator_data: this.data.indicator_data
        };
        this.indicators.addToCharts(this.charts, ind_init_data);

        this.signals.initialize('signal_list', 'new_sig_form');
        this.formations.initialize('formations_list');
        this.formations.initOverlay(this.data.chart1_id, this.charts.chart_1, this.charts.candleSeries);
        this.chartAnalysis.initialize(this.data.chart1_id, this.charts.chart_1, this.charts.candleSeries);
        this.alerts.set_target();
        this.alerts.initialize(this.data.comms);
        this.controls.init_TP_selector();
        this.trade.initialize();
        this.exchanges.initialize();
        this.strats.initialize('strats_display', 'new_strat_form', this.data);
        this.backtesting.fetchSavedTests();
        this.account.initialize();
    }

    /**
     * Make a popup resizable, and optionally pass a resize callback (like for Blockly workspaces).
     * @param {string} popupId - The ID of the popup to make resizable.
     * @param {function|null} resizeCallback - Optional callback to run when resizing (for Blockly or other elements).
     * @param {string|null} headerId - The ID of the header to use for dragging, or null to drag the entire element.
     * @param {string} resizerId - The ID of the resizer handle element.
     */
    initializeResizablePopup(popupId, resizeCallback = null, headerId = null, resizerId) {
        const popupElement = document.getElementById(popupId);
        if (!popupElement) {
            console.warn(`initializeResizablePopup: Element '${popupId}' not found`);
            return;
        }
        this.dragElement(popupElement, headerId);
        this.makeResizable(popupElement, resizeCallback, resizerId);
    }

    /**
     * Make an element draggable by dragging its header.
     * @param {HTMLElement} elm - The element to make draggable.
     * @param {string|null} headerId - The ID of the header to use for dragging, or null to drag the entire element.
     */
    dragElement(elm, headerId = null) {
        const header = headerId ? document.getElementById(headerId) : elm;
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;

        if (header) {
            header.onmousedown = dragMouseDown;
        } else {
            elm.onmousedown = dragMouseDown;
        }

        function dragMouseDown(e) {
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            elm.style.top = (elm.offsetTop - pos2) + "px";
            elm.style.left = (elm.offsetLeft - pos1) + "px";
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

    /**
     * Make an element resizable and optionally call a resize callback (like for Blockly workspace).
     * @param {HTMLElement} elm - The element to make resizable.
     * @param {function|null} resizeCallback - Optional callback to resize specific content.
     * @param {string|null} resizerId - The ID of the resizer handle element, or null to skip resizing.
     */
    makeResizable(elm, resizeCallback = null, resizerId) {
        if (!resizerId) return; // Skip if no resizer specified

        const resizer = document.getElementById(resizerId);
        if (!resizer) return; // Skip if resizer element not found

        let originalWidth = 0;
        let originalHeight = 0;
        let originalMouseX = 0;
        let originalMouseY = 0;

        resizer.addEventListener('mousedown', function(e) {
            e.preventDefault();
            originalWidth = parseFloat(getComputedStyle(elm, null).getPropertyValue('width').replace('px', ''));
            originalHeight = parseFloat(getComputedStyle(elm, null).getPropertyValue('height').replace('px', ''));
            originalMouseX = e.pageX;
            originalMouseY = e.pageY;

            window.addEventListener('mousemove', resize);
            window.addEventListener('mouseup', stopResize);
        });

        const resize = (e) => {
            elm.style.width = originalWidth + (e.pageX - originalMouseX) + 'px';
            elm.style.height = originalHeight + (e.pageY - originalMouseY) + 'px';

            // Optionally call the resize callback (for Blockly or other resizable components)
            if (resizeCallback) {
                resizeCallback();
            }
        };

        const stopResize = () => {
            window.removeEventListener('mousemove', resize);
            window.removeEventListener('mouseup', stopResize);
        };
    }
}

// Instantiate the User_Interface class and assign it to a global variable for access in other parts of the app
window.UI = new User_Interface();
