import { yieldMainThread } from "@devowl-wp/react-utils";

import { createTcfModelFromCookie } from "./createModelFromCookie.js";
import { transformTcfAdTags } from "./transformAdTags.js";
import { BANNER_PRE_DECISION_SHOW_EVENT } from "../events/bannerPredecisionShow.js";
import { OPT_IN_ALL_EVENT } from "../events/optInAll.js";

import type { CookieConsentManagerOptions } from "../apply/manager.js";
import type { Tcf, TcfMetadata } from "../types/tcf.js";
import type { CmpApi } from "@iabtechlabtcf/cmpapi";

/**
 * Dispatch events to the CMP API so vendors can listen to it.
 *
 * @see https://www.npmjs.com/package/@iabtechlabtcf/cmpapi#user-content-trigger-change-event
 */
function tcfCmpApiDispatcher(
    tcf: Tcf,
    tcfMetadata: TcfMetadata,
    api: CmpApi,
    tcfCookieName: CookieConsentManagerOptions["tcfCookieName"],
) {
    const fnUpdateFromCurrentCookie = async (uiVisible: boolean) => {
        const current = createTcfModelFromCookie(tcf, tcfMetadata, tcfCookieName);

        if (current) {
            // Creating the GVL object can be expensive, so generating the TC string for vendors should be generated in an own task
            await yieldMainThread();
        }

        const tcfStringForVendors = current?.tcfStringForVendors();

        if (uiVisible) {
            // If the UI is visible, we can have an encoded TCF string
            api.update(tcfStringForVendors || "", true);
        } else if (!uiVisible) {
            if (tcfStringForVendors) {
                api.update(tcfStringForVendors, false);
            } else {
                // If the UI is not visible, and we do not have a TCF string, the GDPR does not apply for this request
                api.update(null);
            }
        }

        transformTcfAdTags(tcfStringForVendors, current?.gvl);
    };

    // The UI got shown to the user
    document.addEventListener(BANNER_PRE_DECISION_SHOW_EVENT, () => {
        fnUpdateFromCurrentCookie(true);
    });

    // The user has changed its privacy preferences
    document.addEventListener(OPT_IN_ALL_EVENT, () => {
        fnUpdateFromCurrentCookie(false);
    });
}

export { tcfCmpApiDispatcher };
