/**
 * Copyright (c) 2025 Broadcom. All Rights Reserved.
 * Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
 * and/or its subsidiaries.
 */ 
(function () {
    function logger() {
        const isDebugEnabled = JSON.parse(localStorage.getItem("debugVirtualWindow"));

        if (!isDebugEnabled) {
            return;
        }

        console.log(...arguments);
    }

    function isClass(propName) {
        return propName[0].toUpperCase() === propName[0];
    }

    const ANGULAR_APP_PRIMARY_NAVIGATION = "urn:vmware:vcd:angular-app:hyper-plugin:19.0";
    window[`createdElements_${ANGULAR_APP_PRIMARY_NAVIGATION}`] = [];

    // List of window default properties and methods
    const windowProps = window["windowProps"];
    // CustomElementsRegistry class is located here. Gives ability to have custom components scoped for given UI Plugin
    const vcdCustomPolyfills = window["vcdCustomPolyfills"];
    let timeout;
    const createElement = function () {
        if (timeout) {
            clearTimeout(timeout);
        }

        window[`createdElements_${ANGULAR_APP_PRIMARY_NAVIGATION}`].push(arguments[0]);

        timeout = setTimeout(() => {
            logger("[Virtual Window HP19][Document] Clean up created elements!");
            window[`createdElements_${ANGULAR_APP_PRIMARY_NAVIGATION}`] = [];
            clearTimeout(timeout);
        }, 10000);

        return originalCreateElement(...arguments);
    };

    let documentValidator = {
        set: (obj, prop, value) => {
            logger("[Virtual Window HP19][Document][SET]", prop, value);

            if (typeof document[prop] === "function") {
                document[prop] = value;
                return true;
            }

            document[prop] = value;
            return true;
        },
        get: (obj, prop) => {
            logger("[Virtual Window HP19][Document][GET]", prop);

            /**
             * Keeps track of created elements, used by the scoped custom elements polyfill to deduce from
             * which custom elements registry to get the appropriate class for given custom element's html tag.
             */
            if (prop === "createElement") {
                return createElement;
            }

            if (typeof document[prop] === "function") {
                if (isClass(prop)) {
                    return document[prop];
                }

                return document[prop].bind(document);
            }

            return document[prop];
        },
    };
    let documentProxy = new Proxy(window.document, documentValidator);

    const originalTreeWalker = document.createTreeWalker.bind(document);
    document.createTreeWalker = function () {

        if (arguments[0] === documentProxy) {
    
            arguments[0] = document;
        }


        return originalTreeWalker(...arguments);
    };

    const originalCreateElement = document.createElement.bind(document);

    let validator = {
        set: (obj, prop, value) => {
            logger("[Virtual Window HP19][SET]", prop, value);

            const propInWindow = windowProps.includes(prop);
            if (propInWindow) {
                if (typeof value == "function") {
                    window[prop] = value;
                    logger("[Virtual Window HP19][SET] window function to", prop, value);
                    return true;
                }

                window[prop] = value;
                logger("[Virtual Window HP19][SET] window property to", prop, value);

                return true;
            }

            if (typeof value == "function") {
                logger("[Virtual Window HP19][SET] function in customWindow", prop, value);

                obj[prop] = value;
                return true;
            }

            obj[prop] = value;
            logger("[Virtual Window HP19][SET] prop in customWindow", prop);

            return true;
        },
        get: (obj, prop) => {
            logger("[Virtual Window HP19][GET]", prop);

            if (prop === "document") {
                return documentProxy;
            }

            const propInCustomWindow = prop in obj;

            if (propInCustomWindow) {
                const value = obj[prop];

                if (typeof value == "function") {
                    logger("[Virtual Window HP19][GET] give function from custom window", prop);

                    if (isClass(prop)) {
                        return value;
                    }

                    return value.bind(obj);
                }

                logger("[Virtual Window HP19][GET] give prop from custom window", prop);
                return value;
            }

            const propInWindow = windowProps.includes(prop);
            if (!propInWindow) {
                logger("[Virtual Window HP19][GET] prop doesn't exist in window returning null", prop);
                return null;
            }

            const value = window[prop];
            if (typeof value == "function") {
                logger("[Virtual Window HP19][GET] window function! Allow window access for prop", prop);

                if (isClass(prop)) {
                    return value;
                }

                return value.bind(window);
            }

            logger("[Virtual Window HP19][GET] Original window prop! Give access to the plugin", prop);
            return value;
        },
    };
    /**
     * customWindow property name here is not coincidence. The same property name is used in angular.json -> replaceGlobalVarUsage.
     * 
     * All calls from this UI Plugin to the window object will be proxied through to this object, except they are browser built-ins.
     * */ 
    const customWindow = (window["hp19"] = {
        customElements: new vcdCustomPolyfills.CustomElementRegistry(),
    });
    window["hp19Proxy"] = new Proxy(customWindow, validator);

    /**
     * Fox for
     * Issue #1 `Failed to set the 'currentNode' property on 'TreeWalker': Failed to convert value to 'Node'.`
     * https://gitlab.eng.vmware.com/cloud-director-solutions/hyper-plugin/-/merge_requests/12
     * 
     * This is happening because of @cds/core, they use Lit, a library for WebComponents.
     * The error means that we are passing a Proxy to the Document instead of passing the Real Document
     * to a TreeWalker.currentNode, and that causes the error.
     * 
     * !!! IMPORTANT !!!
     * THIS FIX CHANGES THE GLOBAL IMPLEMENTATION IN THE BROWSER OF `TreeWalker.currentNode`.
     * see https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
     * 
     * THE FIX IS SMALL AND DOESN'T AFFECT THE OVERALL FUNCTION OF THE `TreeWalker` class.
     */
    const descriptor = Object.getOwnPropertyDescriptors(window.TreeWalker.prototype);
    Object.defineProperty(window.TreeWalker.prototype, "hp19_original__currentNode", descriptor.currentNode);
    Object.defineProperty(window.TreeWalker.prototype, "currentNode", {
        get: function currentNode() {
            logger("[Virtual Window HP19][TreeWalker][GET] Allow window access for prop", "currentNode");
            return this.hp19_original__currentNode;
        },
        set: function currentNode() {
            if (arguments[0] === documentProxy) {
                arguments[0] = document;
            }
            
            logger("[Virtual Window HP19][TreeWalker][SET]", "currentNode", arguments[0]);
            this.hp19_original__currentNode = arguments[0];
        }
    });
})();
;