import { getUserDecision } from "./getUserDecision.js";
import { getManagerDependingVariables } from "../apply/getManagerDependingVariables.js";

import type { DecisionConsentGroups } from "./getUserDecision.js";
import type { CookieConsentManagerOptions } from "../apply/manager.js";
import type { Service, ServiceGroup } from "../types/service.js";

type GetServiceSelectionOptions = {
    /**
     * If `consent` it will be read from the current cookie and if this fails, it falls back to `essentials`.
     */
    type: "all" | "essentials" | "consent";
} & Pick<CookieConsentManagerOptions, "decisionCookieName" | "setCookiesViaManager" | "groups" | "isGcm">;

/**
 * Read the selected groups + services depending on the passed type.
 */
function getServiceSelection({
    decisionCookieName,
    setCookiesViaManager,
    isGcm,
    groups,
    type,
}: GetServiceSelectionOptions) {
    let selectedGroups: DecisionConsentGroups;
    const { useManager } = getManagerDependingVariables(setCookiesViaManager, {
        isGcm,
        presetId: "",
    });

    const essentialGroupObj = groups.find(({ isEssential }) => isEssential);
    const consentEssentials = {
        [essentialGroupObj.id]: essentialGroupObj.items.map(({ id }) => id),
    };

    // Read current consent
    if (type === "consent") {
        const decision = getUserDecision(decisionCookieName);
        if (decision !== false) {
            selectedGroups = decision.consent;
        } else {
            console.warn("Something went wrong while reading the cookie, fallback to essentials only...");
            selectedGroups = consentEssentials;
        }
    }

    if (type === "essentials") {
        selectedGroups = consentEssentials;
    }

    return {
        isManagerActive: useManager !== "none",
        selectedGroups,
        iterateServices: async function (
            callback: (
                group: ServiceGroup,
                service: Service,
                isOptIn: boolean,
                setCookiesViaManager: ReturnType<typeof getManagerDependingVariables>,
            ) => Promise<void> | void,
        ) {
            const items = groups.map((group) => group.items.map((service) => [group, service] as const)).flat();
            items.sort((a, b) => a[1].executePriority - b[1].executePriority);

            for (const [group, service] of items) {
                const isOptIn = type === "all" || selectedGroups[group.id]?.indexOf(service.id) > -1;
                const useTagManager = getManagerDependingVariables(setCookiesViaManager, {
                    presetId: service.presetId,
                    isGcm,
                });
                await callback(group, service, isOptIn, useTagManager);
            }
        },
    };
}

export { type GetServiceSelectionOptions, getServiceSelection };
