import { consent } from "./consent.js";
import { consentAll } from "./consentAll.js";
import { consentSync } from "./consentSync.js";
import { unblock } from "./unblock.js";
import { unblockSync } from "./unblockSync.js";
import { wrapFn } from "./wrapFn.js";

import type { CookieConsentManager } from "../apply/manager.js";
import type { OmitFirst } from "../types/types.js";

/**
 * Create the API functions and make them available through `window.consentApi`.
 *
 * There is also a [stub](https://shorturl.at/bcgyz) implementation:
 *
 * ```js
 * ((a,b)=>{a[b]||(a[b]={unblockSync:()=>undefined},["consentSync"].forEach(c=>a[b][c]=()=>({cookie:null,consentGiven:!1,cookieOptIn:!0})),["consent","consentAll","unblock"].forEach(c=>a[b][c]=(...d)=>new Promise(e=>a.addEventListener(b,()=>{a[b][c](...d).then(e)},{once:!0}))))})(window,"consentApi");
 * ```
 */
function createApi(manager: CookieConsentManager, blocker: Parameters<typeof unblock>[0]) {
    const apiConsent = (...args: OmitFirst<Parameters<typeof consent>>) => consent(manager, ...args);
    const apiConsentAll = (...args: OmitFirst<Parameters<typeof consentAll>>) => consentAll(manager, ...args);
    const apiConsentSync = (...args: OmitFirst<Parameters<typeof consentSync>>) => consentSync(manager, ...args);
    const apiConsentUnblockSync = (...args: OmitFirst<Parameters<typeof unblockSync>>) => unblockSync(blocker, ...args);
    const apiConsentUnblock = (...args: OmitFirst<Parameters<typeof unblock>>) => unblock(blocker, ...args);

    const wrapApis = {
        consent: apiConsent,
        consentAll: apiConsentAll,
        consentSync: apiConsentSync,
        unblock: apiConsentUnblock,
        unblockSync: apiConsentUnblockSync,
    };

    const apiWrapFn = (...args: OmitFirst<OmitFirst<OmitFirst<Parameters<typeof wrapFn>>>>) =>
        wrapFn(wrapApis, blocker, manager, ...args);
    const api = {
        ...wrapApis,
        wrapFn: apiWrapFn,
    };

    window.consentApi = api;

    // Dispatch event so e.g. stubs can react to it and forward functions
    window.dispatchEvent(new CustomEvent("consentApi"));
    return api;
}

declare global {
    interface Window {
        consentApi?: ReturnType<typeof createApi>;
    }
}

export { createApi };
