import { VENDOR_IDS, CATEGORY_PURPOSES } from "../../utils/enums";
import { getUniqueValues } from "../../utils";
import makeTimedCallback from "../../core/makeTimedCallback";
import getCmp from "./getCmp";
import makeCallbackRegistry from "@adobe/callback-registry-factory";

export default function IAB() {
    const self = this;
    self.name = "iabPlugin";
    self.version = "0.0.1";

    const FETCH_CONSENT_KEY = "FETCH_CONSENT_DATA";
    const registry = makeCallbackRegistry();

    const state = {
        allConsentData: null // `gdprApplies`-`purposesConsent`-`vendorConsents`-`consentString`.
    };

    const setState = (key, value = {}) => ( state[key] = value );

    self.fetchConsentData = ({ callback, timeout }) => {
        const callbackWithTimer = makeTimedCallback(callback, timeout);
        fetchConsentData({ callback: callbackWithTimer });
    };

    self.isApproved = ({ callback, category, timeout }) => {
        if (state.allConsentData) {
            return callback(null, isApproved(
                category,
                state.allConsentData.vendorConsents,
                state.allConsentData.purposeConsents)
            );
        }

        const callbackWithTimer = makeTimedCallback((error, { vendorConsents, purposeConsents } = {}) => {
            callback(error, isApproved(category, vendorConsents, purposeConsents));
        }, timeout);
        fetchConsentData({ category, callback: callbackWithTimer });
    };

    self.onRegister = optIn => {
        // On register, retrieve IAB vendor consents for all current vendors with IDs.
        // If consent was found, set that approval status for those vendors in OptIn.
        const allVendors = Object.keys(VENDOR_IDS);
        const callback = (error, { purposeConsents, gdprApplies, vendorConsents } = {}) => {
            if (!error && gdprApplies && vendorConsents && purposeConsents) {
                allVendors.forEach(vendor => {
                    const isVendorApproved = isApproved(vendor, vendorConsents, purposeConsents);
                    const action = isVendorApproved ? "approve" : "deny";
                    optIn[action](vendor, true);
                });
                optIn.complete();
            }
        };
        self.fetchConsentData({ callback });
    };

    // This function should fetch the following:
    // - `gdprApplies`, `purposesConsent`, `vendorConsents`, `consentString` and `allConsentData`.
    // - It should call __cmp.getConsentData & __cmp.getVendorConsents, and aggregate the responses.
    const fetchConsentData = ({ callback }) => {
        if (state.allConsentData) {
            return callback(null, state.allConsentData);
        }

        registry.add(FETCH_CONSENT_KEY, callback);
        let allConsentData = {};
        getVendorConsents(({ purposeConsents, gdprApplies, vendorConsents } = {}, success) => {
            if (success) {
                allConsentData = { purposeConsents, gdprApplies, vendorConsents };
                setState("allConsentData", allConsentData);
            }
            getConsentData((data = {}, success) => {
                if (success) {
                    allConsentData["consentString"] = data.consentData;
                    setState("allConsentData", allConsentData);
                }
                registry.execute(FETCH_CONSENT_KEY, [null, state.allConsentData]);
            });
        });
    };

    const getConsentData = callback => {
        // 'null' means get the latest version of the consent string.
        let cmp = getCmp();
        cmp && cmp("getConsentData", null, callback);
    };

    const getVendorConsents = callback => {
        // NOTE: vendorID should be an array. For now, we are supporting one vendorId at a time.
        // FOR NOW, we are passing ALL the Adobe Vendor IDs.
        // TODO: Rethink filtering that by a category param.
        const vendorIds = getUniqueValues(VENDOR_IDS);
        let cmp = getCmp();
        cmp && cmp("getVendorConsents", vendorIds, callback);
    };

    const isApproved = (category, vendorConsents = {}, purposeConsents = {}) => {
        const isVendorApproved = !!vendorConsents[VENDOR_IDS[category]];
        const arePurposesApproved = () => CATEGORY_PURPOSES[category].every(purpose => purposeConsents[purpose]);
        return isVendorApproved && arePurposesApproved();
    };
}
