import { regExpPatternFromWildcardName } from "../utils/regExpPatternFromWildcardName.js";

import type { CookieConsentManager } from "../apply/manager.js";
import type { Service, ServiceTechnicalDefinition } from "../types/service.js";

/**
 * Synchronously check if a consent is given. See `window.consentApi.consent` for more documentation.
 */
function consentSync(
    manager: CookieConsentManager,
    typeOrIdOrUniqueName: ServiceTechnicalDefinition["type"] | number | string,
    name?: ServiceTechnicalDefinition["name"],
    /**
     * This can also be `*` to allow all hosts.
     */
    host?: ServiceTechnicalDefinition["host"],
): {
    /**
     * If the website operator has defined a cookie or service with the information you requested,
     * it will be returned here.
     */
    cookie: Service | null;
    /**
     * This variable defines whether a valid consent has generally been given. This does not refer to the technical information
     * that you have passed as arguments. For example: If the user clicks "Continue without Consent", this variable is set to `true`.
     * The variable is `false` if the user has not yet given consent and the cookie banner is displayed.
     */
    consentGiven: boolean;
    /**
     * This variable defines whether the technical information has been accepted.
     *
     * **Attention:** This variable is also `true` if no service (see `cookie`) is found.
     */
    cookieOptIn: boolean;
} {
    // Find matching cookie
    const found: Array<{ cookie: Service; relevance: number }> = [];
    const { groups, revisionHash } = manager.getOptions();
    const allCookies = groups.map(({ items }) => items).flat();

    for (const row of allCookies) {
        if (typeof typeOrIdOrUniqueName === "number") {
            if (row.id === typeOrIdOrUniqueName) {
                found.push({
                    cookie: row,
                    relevance: 10,
                });
            }
        } else if (
            typeof typeOrIdOrUniqueName === "string" &&
            typeof name === "undefined" &&
            typeof host === "undefined"
        ) {
            if (row.uniqueName === typeOrIdOrUniqueName) {
                found.push({
                    cookie: row,
                    relevance: 10,
                });
            }
        } else {
            const { technicalDefinitions } = row;

            if (technicalDefinitions?.length) {
                // Check if technical information matches
                for (const td of technicalDefinitions) {
                    if (
                        td.name !== "*" &&
                        td.type === typeOrIdOrUniqueName &&
                        (td.name === name || name.match(regExpPatternFromWildcardName(td.name))) &&
                        (td.host === host || host === "*")
                    ) {
                        found.push({
                            cookie: row,
                            // Create a priority by "relevance" inside the technical definitions
                            // This is the case if e.g. another Cookie consumes the same technical cookie
                            // Example: Vimeo uses Facebook Pixel, too
                            relevance: technicalDefinitions.length + technicalDefinitions.indexOf(td) + 1,
                        });
                        break;
                    }
                }
            }
        }
    }

    const already = manager.getUserDecision();
    if (found.length) {
        const relevantCookie = found.sort(({ relevance: a }, { relevance: b }) => a - b)[0].cookie;

        // Check if consent is already given
        if (already && revisionHash === already.revision) {
            const consentCookieIds = Object.values(already.consent).flat();
            if (consentCookieIds.indexOf(relevantCookie.id) > -1) {
                return {
                    cookie: relevantCookie,
                    consentGiven: true,
                    cookieOptIn: true,
                };
            } else {
                return {
                    cookie: relevantCookie,
                    consentGiven: true,
                    cookieOptIn: false,
                };
            }
        } else {
            return {
                cookie: relevantCookie,
                consentGiven: false,
                cookieOptIn: false,
            };
        }
    } else {
        return {
            cookie: null,
            consentGiven: !!already,
            cookieOptIn: true,
        };
    }
}

export { consentSync };
