/**
 * utility.js
 * Part of the p11 UI Library.
 * Contains general helper functions and global state management.
 */

/* ========================================================================
   INTERNAL STATE
   ======================================================================== */
let lastClickClientX = 0;
let lastClickClientY = 0;
let lastClickScrollX = 0;
let lastClickScrollY = 0;

/* ========================================================================
   INTERNAL HELPER FUNCTIONS
   ======================================================================== */

function getFocusableElements(element) {
    if (!element) return [];
    return Array.from(
        element.querySelectorAll(
            'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"]'
        )
    ).filter(el => el.offsetWidth > 0 || el.offsetHeight > 0);
}

function isFocusableAndVisible(element) {
    return element && element.tabIndex >= 0 && !element.disabled &&
        element.offsetWidth > 0 && element.offsetHeight > 0 &&
        element.style.visibility !== 'hidden' && element.style.display !== 'none';
}

/* ========================================================================
   PUBLIC EXPORTED FUNCTIONS
   ======================================================================== */

export const UtilityFunctions = {
    /**
     * Setzt den globalen Debug-Status
     */
    setDebugMode: function (enabled) {
        if (window.p11Js) {
            window.p11Js.isDebug = enabled;
            this.log("Debug Mode " + (enabled ? "ENABLED" : "DISABLED"));
        }
    },

    /**
     * Central logging bridge to window.p11Js.
     */
    log: function (message, ...args) {
        if (window.p11Js && typeof window.p11Js.log === 'function') {
            window.p11Js.log("Utility", message, args.length > 0 ? args : null);
        }
    },

    error: function (message, ...args) {
        console.error("[p11][Utility] ERROR:", message, ...args);
    },

    isFocusableAndVisible: (element) => isFocusableAndVisible(element),
    getFocusableElements: (element) => getFocusableElements(element),

    // --- CLICK COORDINATES ---

    getLastClickCoords: function () {
        return {
            clientX: lastClickClientX,
            clientY: lastClickClientY,
            scrollX: lastClickScrollX,
            scrollY: lastClickScrollY
        };
    },

    setupGlobalClickTracker: function () {
        document.addEventListener('click', (e) => {
            lastClickClientX = e.clientX;
            lastClickClientY = e.clientY;

            // Nutze scrollX/scrollY (Fallback auf pageXOffset für ganz alte Browser, falls nötig)
            //lastClickScrollX = window.scrollX !== undefined ? window.scrollX : window.pageXOffset;
            //lastClickScrollY = window.scrollY !== undefined ? window.scrollY : window.pageYOffset;
            lastClickScrollX = window.scrollX ?? 0;
            lastClickScrollY = window.scrollY ?? 0;

            if (window.p11Js?.isDebug) {
                this.log(`Global click captured: X=${lastClickClientX}, Y=${lastClickClientY}, ScrollX=${lastClickScrollX}, ScrollY=${lastClickScrollY}`);
            }
        });
    },

    // --- LEGACY INITIALIZATION ---

    initializeLegacySupport: function () {
        window.TpcModalJs = window.TpcModalJs || {};

        // Linking debug flag to central system
        if (!Object.getOwnPropertyDescriptor(window.TpcModalJs, 'debugMode')) {
            Object.defineProperty(window.TpcModalJs, 'debugMode', {
                get: () => window.p11Js?.isDebug || false,
                set: (val) => { if (window.p11Js) window.p11Js.isDebug = val; },
                configurable: true
            });
        }

        // Legacy API mappings for general helpers
        window.TpcModalJs.log = (msg, ...args) => this.log(msg, ...args);
        window.TpcModalJs.error = (msg, ...args) => this.error(msg, ...args);
        window.TpcModalJs.getLastClickCoords = () => this.getLastClickCoords();
        window.TpcModalJs.isFocusableAndVisible = (el) => this.isFocusableAndVisible(el);

        this.log("Legacy Utility support initialized.");
    },

    // --- CLASS MANIPULATION ---

    /**
     * Fügt eine Klasse zum Body hinzu oder entfernt sie.
     * @param {string} className - Name der CSS Klasse (z.B. 'p11-no-scroll')
     * @param {boolean} force - true zum Hinzufügen, false zum Entfernen
     */
    toggleBodyClass: function (className, force) {
        if (force) {
            document.body.classList.add(className);
        } else {
            document.body.classList.remove(className);
        }
    },

    // --- SHARED UI MANAGEMENT ---

    _uiState: {
        activeScrollLocks: new Set(),
        activeModals: [], // NEU: Stack für Modale zur Z-Index Berechnung
        baseZIndex: 1000,
        layers: {
            P11PageNative: -1000,
            P11DrawerNative: 0,
            P11ModalNative: 1050,
            P11Modal: 1100,
            P11MessageBox: 2000,
            P11Toast: 3000,
            P11FloatingPanel: 5000
        }
    },

    /**
     * Receives configuration updates from IEventStateService.
     * @param {object} config - The configuration model from C#.
     */
    configureUi: function (config) {
        if (!config) return;

        if (config.baseZIndex !== undefined) {
            this._uiState.baseZIndex = config.baseZIndex;
        }

        // Merge layer offsets if provided
        if (config.layers) {
            this._uiState.layers = { ...this._uiState.layers, ...config.layers };
        }

        this.log("UI Configuration synchronized from C# Service", this._uiState);
    },

    /**
     * @param {number} stackDepth - Current depth of the component.
     * @param {string} layerName - The key from _uiState.layers (e.g. 'modal').
     */
    getNextZIndex: function (stackDepth, layerName) {
        const offset = this._uiState.layers[layerName] || 0;
        // Each layer gets its base + stack offset (10 per instance)
        return this._uiState.baseZIndex + offset + (stackDepth * 10);
    },

    // --- SCROLL LOCK ---

    requestScrollLock: function (componentId) {
        if (!componentId) return;
        this._uiState.activeScrollLocks.add(componentId);

        // LOG zur Kontrolle - wenn dieser nicht kommt, wird die Funktion nicht aufgerufen!
        console.warn(`[p11][Utility] APPLYING HAMMER-LOCK for ${componentId}. Count: ${this._uiState.activeScrollLocks.size}`);

        // DEINE METHODE VON GESTERN
        const body = document.body;
        body.style.setProperty('overflow', 'hidden', 'important');

        // Scrollbar-Gap Ausgleich
        const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
        if (scrollbarWidth > 0) {
            body.style.setProperty('padding-right', `${scrollbarWidth}px`, 'important');
        }
        body.classList.add('modal-open');
    },

    releaseScrollLock: function (componentId) {
        if (!componentId) return;
        this._uiState.activeScrollLocks.delete(componentId);

        console.warn(`[p11][Utility] RELEASE requested for ${componentId}. Remaining: ${this._uiState.activeScrollLocks.size}`);

        if (this._uiState.activeScrollLocks.size === 0) {
            // Hier nutzen wir jetzt die neue zentrale Funktion
            this.clearBodyStyles();

            // Optional: Der kleine Timeout-Sicherheitscheck von vorher kann bleiben
            setTimeout(() => {
                this.clearBodyStyles();
                console.log("[p11][Utility] FINAL CLEANUP: Scroll restored.");
            }, 25);
        }
    },

    /**
     * Cleans all p11-related styles from the body. 
     * Essential for hard-resets or when the last layer closes.
     */
    clearBodyStyles: function () {
        document.body.style.removeProperty('overflow');
        document.body.style.removeProperty('padding-right');
        document.body.classList.remove('modal-open');
        this.log("Body styles cleared.");
    },

    /**
     * Calculates movement metrics for any touch gesture.
     * Returns diffs, absolute values and the dominant axis.
     */
    getSwipeMetrics: function (e, startX, startY) {
        const touch = e.touches ? e.touches[0] : (e.changedTouches ? e.changedTouches[0] : null);
        if (!touch) return null;

        const diffX = touch.clientX - startX;
        const diffY = touch.clientY - startY;
        const absX = Math.abs(diffX);
        const absY = Math.abs(diffY);

        return {
            diffX,
            diffY,
            absX,
            absY,
            isHorizontal: absX > absY
        };
    },

    /**
     * Helper to get the current platform via Capacitor if available.
     */
    getPlatform: function () {
        return window.Capacitor?.getPlatform ? window.Capacitor.getPlatform() : 'web';
    },

    // --- LIGHTWEIGHT FOCUS MANAGEMENT ---

    /**
     * Sets focus to the element or its first focusable child without using the modal stack.
     */
    focusElement: function (element) {
        if (!element) return;
        if (isFocusableAndVisible(element)) {
            element.focus();
        } else {
            const focusables = getFocusableElements(element);
            if (focusables.length > 0) focusables[0].focus();
        }
    },

    /**
     * Simple tab-trap helper for light components like Dropdowns.
     */
    handleTabTrap: function (e, element) {
        if (!e || e.key !== 'Tab' || !element) return;
        const focusables = getFocusableElements(element);
        if (focusables.length === 0) {
            e.preventDefault();
            return;
        }
        const first = focusables[0];
        const last = focusables[focusables.length - 1];

        if (e.shiftKey && document.activeElement === first) {
            last.focus();
            e.preventDefault();
        } else if (!e.shiftKey && document.activeElement === last) {
            first.focus();
            e.preventDefault();
        }
    },

    // --- SIMPLE OVERLAY MANAGEMENT (Lightweight but with Scroll-Lock) ---

    /**
     * Shows a simple overlay, sets focus, and requests a scroll lock.
     * Does not register in the global modal stack.
     */
    showSimpleOverlay: function (element, preventScroll) {
        if (!element) return;

        if (preventScroll) {
            this.requestScrollLock(element.id || 'simple-overlay');
        }

        this.focusElement(element);
    },

    /**
     * Hides a simple overlay and releases the scroll lock.
     */
    hideSimpleOverlay: function (elementId) {
        if (elementId) {
            this.releaseScrollLock(elementId);
        }
    },

};

// Auto-Init
UtilityFunctions.initializeLegacySupport();
UtilityFunctions.setupGlobalClickTracker();



///**
// * utility.js
// * Part of the p11 UI Library.
// * Contains general helper functions and global state management.
// */

///* ========================================================================
//   INTERNAL STATE
//   ======================================================================== */
//let lastClickClientX = 0;
//let lastClickClientY = 0;
//let lastClickScrollX = 0;
//let lastClickScrollY = 0;

///* ========================================================================
//   INTERNAL HELPER FUNCTIONS
//   ======================================================================== */

//function getFocusableElements(element) {
//    if (!element) return [];
//    return Array.from(
//        element.querySelectorAll(
//            'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"]'
//        )
//    ).filter(el => el.offsetWidth > 0 || el.offsetHeight > 0);
//}

//function isFocusableAndVisible(element) {
//    return element && element.tabIndex >= 0 && !element.disabled &&
//        element.offsetWidth > 0 && element.offsetHeight > 0 &&
//        element.style.visibility !== 'hidden' && element.style.display !== 'none';
//}

///* ========================================================================
//   PUBLIC EXPORTED FUNCTIONS
//   ======================================================================== */

//export const UtilityFunctions = {
//    /**
//     * Setzt den globalen Debug-Status
//     */
//    setDebugMode: function (enabled) {
//        if (window.p11Js) {
//            window.p11Js.isDebug = enabled;
//            this.log("Debug Mode " + (enabled ? "ENABLED" : "DISABLED"));
//        }
//    },

//    /**
//     * Central logging bridge to window.p11Js.
//     */
//    log: function (message, ...args) {
//        if (window.p11Js && typeof window.p11Js.log === 'function') {
//            window.p11Js.log("Utility", message, args.length > 0 ? args : null);
//        }
//    },

//    error: function (message, ...args) {
//        console.error("[p11][Utility] ERROR:", message, ...args);
//    },

//    isFocusableAndVisible: (element) => isFocusableAndVisible(element),
//    getFocusableElements: (element) => getFocusableElements(element),

//    // --- CLICK COORDINATES ---

//    getLastClickCoords: function () {
//        return {
//            clientX: lastClickClientX,
//            clientY: lastClickClientY,
//            scrollX: lastClickScrollX,
//            scrollY: lastClickScrollY
//        };
//    },

//    setupGlobalClickTracker: function () {
//        document.addEventListener('click', (e) => {
//            lastClickClientX = e.clientX;
//            lastClickClientY = e.clientY;

//            // Nutze scrollX/scrollY (Fallback auf pageXOffset für ganz alte Browser, falls nötig)
//            //lastClickScrollX = window.scrollX !== undefined ? window.scrollX : window.pageXOffset;
//            //lastClickScrollY = window.scrollY !== undefined ? window.scrollY : window.pageYOffset;
//            lastClickScrollX = window.scrollX ?? 0;
//            lastClickScrollY = window.scrollY ?? 0;

//            if (window.p11Js?.isDebug) {
//                this.log(`Global click captured: X=${lastClickClientX}, Y=${lastClickClientY}, ScrollX=${lastClickScrollX}, ScrollY=${lastClickScrollY}`);
//            }
//        });
//    },

//    // --- LEGACY INITIALIZATION ---

//    initializeLegacySupport: function () {
//        window.TpcModalJs = window.TpcModalJs || {};

//        // Linking debug flag to central system
//        if (!Object.getOwnPropertyDescriptor(window.TpcModalJs, 'debugMode')) {
//            Object.defineProperty(window.TpcModalJs, 'debugMode', {
//                get: () => window.p11Js?.isDebug || false,
//                set: (val) => { if (window.p11Js) window.p11Js.isDebug = val; },
//                configurable: true
//            });
//        }

//        // Legacy API mappings for general helpers
//        window.TpcModalJs.log = (msg, ...args) => this.log(msg, ...args);
//        window.TpcModalJs.error = (msg, ...args) => this.error(msg, ...args);
//        window.TpcModalJs.getLastClickCoords = () => this.getLastClickCoords();
//        window.TpcModalJs.isFocusableAndVisible = (el) => this.isFocusableAndVisible(el);

//        this.log("Legacy Utility support initialized.");
//    },

//    // --- CLASS MANIPULATION ---

//    /**
//     * Fügt eine Klasse zum Body hinzu oder entfernt sie.
//     * @param {string} className - Name der CSS Klasse (z.B. 'p11-no-scroll')
//     * @param {boolean} force - true zum Hinzufügen, false zum Entfernen
//     */
//    toggleBodyClass: function (className, force) {
//        if (force) {
//            document.body.classList.add(className);
//        } else {
//            document.body.classList.remove(className);
//        }
//    },

//    // --- SHARED UI MANAGEMENT ---

//    //_uiState: {
//    //    activeScrollLocks: new Set(),
//    //    activeModals: [], // NEU: Stack für Modale zur Z-Index Berechnung
//    //    baseZIndex: 1000,
//    //    layers: {
//    //        drawer: 0,
//    //        floating: 500,
//    //        modal: 1000,
//    //        messagebox: 2000
//    //    }
//    //},
//    _uiState: {
//        baseZIndex: 1000,
//        layers: {
//            "P11PageNative": -1000,
//            "P11DrawerNative": 0,
//            "P11ModalNative": 1050,
//            "P11Modal": 1100,
//            "P11MessageBox": 2000,
//            "P11FloatingPanel": 5000
//        }
//    },

//    getLayerConfiguration: function () {
//        return {
//            baseZIndex: this._uiState.baseZIndex,
//            layers: this._uiState.layers
//        };
//    },

//    /**
//     * Setzt die Layer-Konfiguration direkt aus C#.
//     * @param {object} layers - Ein Dictionary/Objekt mit Layer-Offsets.
//     */
//    setLayerConfiguration: function (layers) {
//        if (!layers) return;

//        // Wir mergen die neuen Offsets in den bestehenden State
//        this._uiState.layers = {
//            ...this._uiState.layers,
//            ...layers
//        };

//        this.log("Layer configuration updated from C#", this._uiState.layers);
//    },

//    /**
//     * Receives configuration updates from IEventStateService.
//     * @param {object} config - The configuration model from C#.
//     */
//    configureUi: function (config) {
//        if (!config) return;

//        if (config.baseZIndex !== undefined) {
//            this._uiState.baseZIndex = config.baseZIndex;
//        }

//        // Merge layer offsets if provided
//        if (config.layers) {
//            this._uiState.layers = { ...this._uiState.layers, ...config.layers };
//        }

//        this.log("UI Configuration synchronized from C# Service", this._uiState);
//    },

//    /**
//     * @param {number} stackDepth - Current depth of the component.
//     * @param {string} layerName - The key from _uiState.layers (e.g. 'modal').
//     */
//    getNextZIndex: function (stackDepth, layerName) {
//        const offset = this._uiState.layers[layerName] || 0;
//        // Each layer gets its base + stack offset (10 per instance)
//        return this._uiState.baseZIndex + offset + (stackDepth * 10);
//    },

//    // --- SCROLL LOCK ---

//    requestScrollLock: function (componentId) {
//        if (!componentId) return;
//        this._uiState.activeScrollLocks.add(componentId);

//        // LOG zur Kontrolle - wenn dieser nicht kommt, wird die Funktion nicht aufgerufen!
//        console.warn(`[p11][Utility] APPLYING HAMMER-LOCK for ${componentId}. Count: ${this._uiState.activeScrollLocks.size}`);

//        // DEINE METHODE VON GESTERN
//        const body = document.body;
//        body.style.setProperty('overflow', 'hidden', 'important');

//        // Scrollbar-Gap Ausgleich
//        const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
//        if (scrollbarWidth > 0) {
//            body.style.setProperty('padding-right', `${scrollbarWidth}px`, 'important');
//        }
//        body.classList.add('modal-open');
//    },

//    releaseScrollLock: function (componentId) {
//        if (!componentId) return;
//        this._uiState.activeScrollLocks.delete(componentId);

//        console.warn(`[p11][Utility] RELEASE requested for ${componentId}. Remaining: ${this._uiState.activeScrollLocks.size}`);

//        if (this._uiState.activeScrollLocks.size === 0) {
//            // Hier nutzen wir jetzt die neue zentrale Funktion
//            this.clearBodyStyles();

//            // Optional: Der kleine Timeout-Sicherheitscheck von vorher kann bleiben
//            setTimeout(() => {
//                this.clearBodyStyles();
//                console.log("[p11][Utility] FINAL CLEANUP: Scroll restored.");
//            }, 25);
//        }
//    },

//    /**
//     * Cleans all p11-related styles from the body. 
//     * Essential for hard-resets or when the last layer closes.
//     */
//    clearBodyStyles: function () {
//        document.body.style.removeProperty('overflow');
//        document.body.style.removeProperty('padding-right');
//        document.body.classList.remove('modal-open');
//        this.log("Body styles cleared.");
//    },

//    /**
//     * Calculates movement metrics for any touch gesture.
//     * Returns diffs, absolute values and the dominant axis.
//     */
//    getSwipeMetrics: function (e, startX, startY) {
//        const touch = e.touches ? e.touches[0] : (e.changedTouches ? e.changedTouches[0] : null);
//        if (!touch) return null;

//        const diffX = touch.clientX - startX;
//        const diffY = touch.clientY - startY;
//        const absX = Math.abs(diffX);
//        const absY = Math.abs(diffY);

//        return {
//            diffX,
//            diffY,
//            absX,
//            absY,
//            isHorizontal: absX > absY
//        };
//    },

//    /**
//     * Helper to get the current platform via Capacitor if available.
//     */
//    getPlatform: function () {
//        return window.Capacitor?.getPlatform ? window.Capacitor.getPlatform() : 'web';
//    },

//    // --- LIGHTWEIGHT FOCUS MANAGEMENT ---

//    /**
//     * Sets focus to the element or its first focusable child without using the modal stack.
//     */
//    focusElement: function (element) {
//        if (!element) return;
//        if (isFocusableAndVisible(element)) {
//            element.focus();
//        } else {
//            const focusables = getFocusableElements(element);
//            if (focusables.length > 0) focusables[0].focus();
//        }
//    },

//    /**
//     * Simple tab-trap helper for light components like Dropdowns.
//     */
//    handleTabTrap: function (e, element) {
//        if (!e || e.key !== 'Tab' || !element) return;
//        const focusables = getFocusableElements(element);
//        if (focusables.length === 0) {
//            e.preventDefault();
//            return;
//        }
//        const first = focusables[0];
//        const last = focusables[focusables.length - 1];

//        if (e.shiftKey && document.activeElement === first) {
//            last.focus();
//            e.preventDefault();
//        } else if (!e.shiftKey && document.activeElement === last) {
//            first.focus();
//            e.preventDefault();
//        }
//    },

//    // --- SIMPLE OVERLAY MANAGEMENT (Lightweight but with Scroll-Lock) ---

//    /**
//     * Shows a simple overlay, sets focus, and requests a scroll lock.
//     * Does not register in the global modal stack.
//     */
//    showSimpleOverlay: function (element, preventScroll) {
//        if (!element) return;

//        if (preventScroll) {
//            this.requestScrollLock(element.id || 'simple-overlay');
//        }

//        this.focusElement(element);
//    },

//    /**
//     * Hides a simple overlay and releases the scroll lock.
//     */
//    hideSimpleOverlay: function (elementId) {
//        if (elementId) {
//            this.releaseScrollLock(elementId);
//        }
//    },

//};

//// Auto-Init
//UtilityFunctions.initializeLegacySupport();
//UtilityFunctions.setupGlobalClickTracker();