import type {
    ClickableButtonsNamed,
    CookieConsentManagerOptions,
    Tcf,
    TcfMetadata,
} from "@devowl-wp/cookie-consent-web-client";
import {
    applyRestrictivePurposes,
    applyTcfModelMetadata,
    createTcfModel,
    createTcfModelFromCookie,
    prepareTcfString,
} from "@devowl-wp/cookie-consent-web-client";
import { useAsyncMemo, yieldMainThread } from "@devowl-wp/react-utils";

import type { GVL, TCModel } from "@iabtechlabtcf/core";

/**
 * Merges the localized `tcf` and `tcfMetadata` together so it can be used inside our `BannerContextProps`.
 *
 * It returns a Promise which you could use to yield the main thread (by e.g. using React's `use`
 * or use `<YieldLazyLoad`) as creating the `GVL` for the first time can take a very long
 * time - especially when there are a lot of vendors selected.
 */
function useTcf(
    active: boolean,
    tcf: Tcf,
    tcfMetadata: TcfMetadata,
    options: Pick<CookieConsentManagerOptions, "tcfCookieName" | "cmpId" | "cmpVersion">,
    /**
     * Depending on an implicit consent we need to fill the decision (e.g. when implicitely all services are
     * accepted, we also need to accept all GCM consent types)
     */
    buttonClicked?: ClickableButtonsNamed,
) {
    return useAsyncMemo(async () => {
        if (process.env.IS_TCF === "1" && active && Object.values(tcf.vendors).length > 0) {
            let gvl: GVL;
            let model: TCModel;
            const restored = createTcfModelFromCookie(tcf, tcfMetadata, options.tcfCookieName);

            // First, try to resolve from user consent (cookie value)
            if (restored) {
                ({ gvl, model } = restored);
            } else {
                // No consent given, let's create an empty model
                const newTcf = createTcfModel({ tcf, tcfMetadata, tcfString: "" });
                ({ gvl, model } = newTcf);
            }

            applyTcfModelMetadata(model, tcfMetadata, options);
            applyRestrictivePurposes(model, tcf.vendorConfigurations);

            if (buttonClicked?.startsWith("implicit")) {
                await yieldMainThread();
                prepareTcfString(model, buttonClicked);
            } else if (!restored) {
                await yieldMainThread();
                prepareTcfString(model, "initial");
            }

            return { gvl, model, original: tcf, metadata: tcfMetadata };
        } else {
            return undefined;
        }
    }, [active, tcf, tcfMetadata, buttonClicked]);
}

export { useTcf };
