/**
 * Entrypoint for plain website. This file is only loaded if the visitor needs to accept cookies.
 */

import { options } from "preact";
import { createRoot } from "react-dom/client";

import type { OptOutAllEvent } from "@devowl-wp/cookie-consent-web-client";
import {
    OPT_OUT_ALL_EVENT,
    createApi,
    gcmDispatcher,
    printConsentUuidsToHTMLElement,
} from "@devowl-wp/cookie-consent-web-client";
import {
    HTML_ATTRIBUTE_JQUERY_HIJACK_EACH,
    hijackCreateElement,
    hijackWebComponents,
    hijackWebRequests,
} from "@devowl-wp/headless-content-unblocker";
import { getSsrPoweredByLink } from "@devowl-wp/react-cookie-banner";
import { idx, ready, yieldLazyLoad } from "@devowl-wp/react-utils";
import { simpleHash } from "@devowl-wp/utils";

import { listenTemplateOptIn } from "./others/comp/listenTemplateOptIn.js";
import { deleteCookiesServer } from "./others/deleteCookiesServer.js";
import { getCookieConsentManager } from "./others/getCookieConsentManager.js";
import { tcfCmpApi } from "./tcf/cmpApi.js";
import { ensureBodyElement } from "./utils/ensureBodyElement.js";
import { getOptionsFromWindow } from "./utils/getOptionsFromWindow.js";
import { getOtherOptionsFromWindow } from "./utils/getOtherOptionsFromWindow.js";

// Needed to be used together with `fastdom`
options.requestAnimationFrame = requestAnimationFrame;

const {
    others: {
        frontend: { blocker },
        anonymousContentUrl,
        anonymousHash,
        pageRequestUuid4,
    },
    publicUrl,
    chunkFolder,
} = getOptionsFromWindow();

const oldFn = __webpack_get_script_filename__;
__webpack_public_path__ = anonymousHash ? anonymousContentUrl : `${publicUrl}${chunkFolder}/`;
__webpack_get_script_filename__ = (chunkId) => {
    const filename = oldFn(chunkId);
    const [basename, query] = filename.split("?");
    return anonymousHash ? `${simpleHash(anonymousHash + basename)}.js?${query}` : filename;
};

listenTemplateOptIn();

ready(() => {
    const {
        frontend: { isGcm },
    } = getOtherOptionsFromWindow();

    tcfCmpApi();

    /* onlypro:start */
    if (process.env.PLUGIN_CTX === "pro" && isGcm) {
        gcmDispatcher(getCookieConsentManager().getOptions());
    }
    /* onlypro:end */
}, "interactive");

ready(undefined, "interactive").then(() => {
    const poweredLink = getSsrPoweredByLink(`${pageRequestUuid4}-powered-by`);
    const element = ensureBodyElement(document.getElementById(pageRequestUuid4));

    printConsentUuidsToHTMLElement(".rcb-consent-history-uuids", getCookieConsentManager());

    document.addEventListener(OPT_OUT_ALL_EVENT, (async ({
        detail: { deleteHttpCookies },
    }: CustomEvent<OptOutAllEvent>) => {
        // Handle cookie deletion which needs to be done server-side (e. g. HTTP cookies)
        deleteHttpCookies.length && setTimeout(() => deleteCookiesServer(deleteHttpCookies), 0);
    }) as any);

    if (element) {
        const WebsiteBanner = yieldLazyLoad(
            import(/* webpackChunkName: "banner-ui", webpackMode: "lazy-once" */ "./components/websiteBanner.js").then(
                ({ WebsiteBanner }) => WebsiteBanner,
            ),
        );

        createRoot(element).render(<WebsiteBanner poweredLink={poweredLink} />);
    }

    document.querySelectorAll<HTMLTableElement>(".devowl-wp-react-cookie-banner-cookie-policy").forEach((element) => {
        import(
            /* webpackChunkName: "cookie-policy", webpackMode: "lazy-once" */ "@devowl-wp/react-cookie-banner/cookie-policy"
        ).then(({ createCookiePolicyTable }) => createCookiePolicyTable(element));
    });
});

// Expose public API
const { wrapFn, unblock, consent, unblockSync } = createApi(getCookieConsentManager(), blocker);

const clientSideRule = "client-side:";
const mapRule = (rule: string) => (rule.startsWith(clientSideRule) ? rule.slice(clientSideRule.length) : undefined);
hijackWebComponents((element, callback) => unblock(element, { callback }));
hijackCreateElement((url) => {
    const blocked = unblockSync(url, { mapRule });
    if (blocked) {
        const { id, services: requiredIds } = blocked;
        return { id, by: "services", requiredIds };
    }
    return undefined;
});
hijackWebRequests((url) => {
    const blockedSync = unblockSync(url, { mapRule });
    return blockedSync ? unblock(url, { mapRule }) : undefined;
});

// Wrap some functions
const fnGetWindow = () => window as any;

wrapFn(
    [
        // [Plugin Comp] https://wordpress.org/plugins/bold-page-builder/
        {
            object: fnGetWindow,
            key: "bt_bb_gmap_init_new",
        },
        {
            object: fnGetWindow,
            key: "bt_bb_gmap_init_static_new",
        },
        {
            object: () => idx(window as any, (window) => window.mkdf.modules.destinationMaps.mkdfGoogleMaps),
            key: "getDirectoryItemsAddresses",
        },
        // [Plugin Comp] https://themeforest.net/item/brikk-directory-listing-wordpress-theme/29105129
        {
            object: () =>
                idx(window as any, (window) =>
                    window.rz_vars.sdk.map_provider === "google" ? window.Routiz.explore : undefined,
                ),
            key: "init_map",
        },
    ],
    ["unblock", "google.com/maps"],
);

wrapFn(
    {
        object: () =>
            idx(window as any, (window) => Object.values(window.acf.models).map((model: any) => model.prototype)),
        key: "initialize",
    },
    ({ that: { $el } }) => unblock($el?.get(0)),
);

// [Plugin Comp] PixelYourSite
const getPysUtils = () => idx(window as any, (window) => window.pys.Utils);
wrapFn(
    [
        { object: getPysUtils, key: "manageCookies" },
        { object: getPysUtils, key: "setupGDPRData" },
    ],
    ["consent", "http", "pys_first_visit", "*"],
);

// [Plugin Comp] WPForms
wrapFn({ object: () => idx(window as any, (window) => window.wpforms), key: "createCookie" }, ({ args: [name] }) => {
    if (name) {
        return consent("http", name, "*");
    }
    return undefined;
});

// [Plugin Comp] https://wsform.com/knowledgebase/google-map/
wrapFn(
    {
        object: () => idx(window as any, (window) => window.jQuery.WS_Form.prototype),
        key: "form_google_map",
    },
    () => {
        const consent = "google.com/maps";
        jQuery(`[data-google-map]:not([data-init-google-map],[${HTML_ATTRIBUTE_JQUERY_HIJACK_EACH}])`).each(
            function () {
                unblock(consent, {
                    ref: this,
                    attributes: {
                        [HTML_ATTRIBUTE_JQUERY_HIJACK_EACH]: true,
                    },
                });
            },
        );

        return unblock(consent);
    },
);

// [Plugin Comp] WP Bakery
wrapFn(
    {
        object: fnGetWindow,
        key: "vc_pinterest",
    },
    ["unblock", "assets.pinterest.com"],
);
