import type { VisualConfiguration } from "../visual/createVisual.js";

type BlockerCheckerConsentTransport = {
    /**
     * Setting this to explicitly `null` means that this item will not be respected when checking for consent
     * to unblock the content.
     */
    consent: boolean | null;
};

type BlockerCheckerCallback<ExtendedBlockerDefinition extends VisualConfiguration = VisualConfiguration> = (
    by: string,
    /**
     * A mutable transport object for the consent checker. Please fulfill the object with the consent information
     * with the `consent` boolean and return the corresponding blocker which should be used for e.g. visual creation.
     *
     * The key represents the ID of the required item (e.g. service ID, vendor ID or purpose ID).
     */
    consentTransport: Record<string, BlockerCheckerConsentTransport>,
    blockerId: number,
) => { blocker?: ExtendedBlockerDefinition };

/**
 * Given by criteria, IDs and content blocker ID decide if the consent is given.
 */
function decideToUnblock<ExtendedBlockerDefinition extends VisualConfiguration = VisualConfiguration>(
    by: string,
    requiredIds: string | string[],
    blockerId: number,
    checker: BlockerCheckerCallback<ExtendedBlockerDefinition>,
    /**
     * The condition of the consent. Can be `and` or `or`.
     *
     * - `and` = All required IDs need to be accepted
     * - `or` = At least one required ID needs to be accepted
     */
    condition: "and" | "or" = "and",
) {
    const required = typeof requiredIds === "string" ? requiredIds.split(",") : requiredIds;

    const consentTransport: Record<string, BlockerCheckerConsentTransport> = {};
    for (const requiredId of required) {
        consentTransport[requiredId] = {
            consent: false,
        };
    }

    const { blocker } = checker(by, consentTransport, blockerId);
    const consentsToCheck = Object.values(consentTransport).filter(({ consent }) => consent !== null);

    if (consentsToCheck.length === 0) {
        return { consent: true, blocker };
    }

    const consent =
        condition === "and"
            ? consentsToCheck.every(({ consent }) => consent)
            : consentsToCheck.some(({ consent }) => consent);

    return { consent, blocker };
}

export type { BlockerCheckerConsentTransport, BlockerCheckerCallback };
export { decideToUnblock };
