import { EServiceTemplateDataProcessingInCountriesSpecialTreatment } from "@devowl-wp/api-real-cookie-banner";

import type { CommonContextProps } from "../types/commonContext.js";
import type { VisualService } from "../types/service.js";

function calculateSafetyMechanismsFromSpecialTreatments({
    predefinedDataProcessingInSafeCountriesLists,
    isDataProcessingInUnsafeCountries,
    territorialLegalBasis,
    service,
}: Pick<CommonContextProps, "predefinedDataProcessingInSafeCountriesLists" | "territorialLegalBasis"> &
    Partial<Pick<CommonContextProps, "isDataProcessingInUnsafeCountries">> & {
        service?: Required<
            Pick<VisualService, "dataProcessingInCountries" | "dataProcessingInCountriesSpecialTreatments">
        >;
    }) {
    let safeCountries: string[] = [];
    const isGdpr = territorialLegalBasis.indexOf("gdpr-eprivacy") > -1;
    const isDsg = territorialLegalBasis.indexOf("dsg-switzerland") > -1;

    const {
        GDPR: listGdpr,
        DSG: listDsg,
        "GDPR+DSG": listGdprDsg,
        ADEQUACY_CH: listAdequacyCh,
        ADEQUACY_EU: listAdequacyEu,
    } = predefinedDataProcessingInSafeCountriesLists;

    if (isDsg && isGdpr) {
        safeCountries = listGdprDsg;
    } else if (isGdpr) {
        safeCountries = listGdpr;
    } else if (isDsg) {
        safeCountries = listDsg;
    }

    let unsafeCountries: string[] = [];
    const allowedSpecialTreatments: EServiceTemplateDataProcessingInCountriesSpecialTreatment[] = [];
    const result: Record<string, Array<"A" | `${"A" | "D"}-${"EU" | "CH"}` | "B" | "C" | "E" | "D">> = {};

    if (service) {
        const { dataProcessingInCountries, dataProcessingInCountriesSpecialTreatments } = service;
        unsafeCountries = dataProcessingInCountries.filter((dc) => safeCountries.indexOf(dc) === -1);
        const allowTdpf = unsafeCountries.indexOf("US") > -1;

        if (allowTdpf) {
            allowedSpecialTreatments.push(
                EServiceTemplateDataProcessingInCountriesSpecialTreatment.ProviderIsSelfCertifiedTransAtlanticDataPrivacyFramework,
            );
        }

        if (unsafeCountries.length > 0) {
            // Only allow standard contractual clauses for unsafe countries which are not part of the adequacy decision
            const intersectAdequacyDecisionCountries = [
                ...(isGdpr ? listAdequacyEu : []),
                ...(isDsg ? listAdequacyCh : []),
            ];
            const realUnsafeCountries = unsafeCountries.filter(
                (c) => intersectAdequacyDecisionCountries.indexOf(c) === -1,
            );

            if (
                realUnsafeCountries.length > 0 ||
                // When TDPF is allowed, we also need to activate standard contractual clauses as not every service is
                // signed to the transatlantic data privacy framework.
                allowTdpf
            ) {
                allowedSpecialTreatments.push(
                    EServiceTemplateDataProcessingInCountriesSpecialTreatment.StandardContractualClauses,
                );

                if (
                    dataProcessingInCountriesSpecialTreatments.indexOf(
                        EServiceTemplateDataProcessingInCountriesSpecialTreatment.StandardContractualClauses,
                    ) === -1
                ) {
                    allowedSpecialTreatments.push(
                        EServiceTemplateDataProcessingInCountriesSpecialTreatment.ContractualAssurancesWithSubProcessors,
                    );
                }
            }

            // Calculate third countries with their respective security mechanisms
            const isStandardContractualClauses =
                dataProcessingInCountriesSpecialTreatments.indexOf(
                    EServiceTemplateDataProcessingInCountriesSpecialTreatment.StandardContractualClauses,
                ) > -1;
            const isContractualAssurancesWithSubProcessors =
                !isStandardContractualClauses &&
                dataProcessingInCountriesSpecialTreatments.indexOf(
                    EServiceTemplateDataProcessingInCountriesSpecialTreatment.ContractualAssurancesWithSubProcessors,
                ) > -1;
            const isProviderIsSelfCertifiedTransAtlanticDataPrivacyFramework =
                allowTdpf &&
                dataProcessingInCountriesSpecialTreatments.indexOf(
                    EServiceTemplateDataProcessingInCountriesSpecialTreatment.ProviderIsSelfCertifiedTransAtlanticDataPrivacyFramework,
                ) > -1;
            const isBindingCorporateRules =
                dataProcessingInCountriesSpecialTreatments.indexOf(
                    EServiceTemplateDataProcessingInCountriesSpecialTreatment.BindingCorporateRules,
                ) > -1;

            // Special case: For the USA we do only allow adequacy when the service is signed to the TDPF
            const filterAdequacyLists = (country: string) =>
                (isGdpr || isDsg) && country === "US"
                    ? isProviderIsSelfCertifiedTransAtlanticDataPrivacyFramework
                    : true;

            // Exclusive for non-adequecy treatments
            const defaultSecurityMechanism: (typeof result)[""][0] = isStandardContractualClauses
                ? "B"
                : isContractualAssurancesWithSubProcessors
                  ? "C"
                  : isBindingCorporateRules
                    ? "E"
                    : isDataProcessingInUnsafeCountries
                      ? "D"
                      : undefined;

            for (const unsafeCountry of unsafeCountries) {
                const thisResult: (typeof result)[""] = [];

                const isInListAdequacyEu = listAdequacyEu.filter(filterAdequacyLists).indexOf(unsafeCountry) > -1;
                const isInListAdequacyCh = listAdequacyCh.filter(filterAdequacyLists).indexOf(unsafeCountry) > -1;

                if (isDsg && isGdpr) {
                    if (listGdpr.indexOf(unsafeCountry) === -1) {
                        thisResult.push(
                            isInListAdequacyEu
                                ? "A-EU"
                                : defaultSecurityMechanism === "D"
                                  ? "D-EU"
                                  : defaultSecurityMechanism,
                        );
                    }
                    if (listDsg.indexOf(unsafeCountry) === -1) {
                        thisResult.push(
                            isInListAdequacyCh
                                ? "A-CH"
                                : defaultSecurityMechanism === "D"
                                  ? "D-CH"
                                  : defaultSecurityMechanism,
                        );
                    }
                } else if (isGdpr) {
                    thisResult.push(isInListAdequacyEu ? "A" : defaultSecurityMechanism);
                } else if (isDsg) {
                    thisResult.push(isInListAdequacyCh ? "A" : defaultSecurityMechanism);
                }

                result[unsafeCountry] = [...new Set(thisResult.filter(Boolean))];
            }
        }
    }

    return {
        isGdpr,
        isDsg,
        safeCountries,
        unsafeCountries,
        allowedSpecialTreatments,
        result,
        filter: (callback: (mechanism: (typeof result)[""][0]) => boolean) =>
            Object.entries(result)
                .map(([country, mechanisms]) => (mechanisms.some(callback) ? country : undefined))
                .filter(Boolean),
    };
}

/**
 * @deprecated Only for backwards-compatibility rendering (designVersion < 10), use `calculateSafetyMechanismsFromSpecialTreatments` instead
 */
function calculateUnsafeCountries({
    dataProcessingInCountries,
    safeCountries = [],
    specialTreatments = [],
    isDisplay,
}: {
    dataProcessingInCountries: string[];
    safeCountries: string[];
    specialTreatments?: EServiceTemplateDataProcessingInCountriesSpecialTreatment[];
    /**
     * When we want to display unsafe countries in the cookie banner, we need to exclude some special treatments
     * for the calculation as we want to still show unsafe countries for when using e.g. a standard contractual
     * clauses for information purposes.
     */
    isDisplay?: boolean;
}) {
    let useSpecialTreatments = specialTreatments;

    if (isDisplay) {
        useSpecialTreatments = useSpecialTreatments.filter(
            (e) => EServiceTemplateDataProcessingInCountriesSpecialTreatment.StandardContractualClauses !== e,
        );
    }

    return dataProcessingInCountries.filter((c) =>
        useSpecialTreatments.indexOf(
            EServiceTemplateDataProcessingInCountriesSpecialTreatment.StandardContractualClauses,
        ) > -1
            ? false
            : safeCountries.indexOf(c) === -1 ||
              (c === "US" &&
                  useSpecialTreatments.indexOf(
                      EServiceTemplateDataProcessingInCountriesSpecialTreatment.ProviderIsSelfCertifiedTransAtlanticDataPrivacyFramework,
                  ) === -1),
    );
}

export { calculateUnsafeCountries, calculateSafetyMechanismsFromSpecialTreatments };
