import CookieHandler from "./CookieHandler"

export default class GDPRHandler {
    constructor(config) {
        let defaultCb = () => {
        };
        this.defaults = {
            sections: {
                default: {
                    enable: defaultCb,
                    disable: defaultCb,
                }
            }
        };

        this.config = {};
        this.config = mergeDeep(this.config, this.defaults);
        this.config = mergeDeep(this.config, config);

        this.interfaceQuickAccessBtn = document.querySelector('.gdpr-quick-access');
        this.interfaceModal = document.querySelector('.gdpr-modal');
        this.interfaceBanner = document.querySelector('.gdpr-banner');

        // setup default section callback if none provided
        Object.keys(this.config.sections).forEach((section) => {
            if (typeof this.config.sections[section].enable === 'undefined') {
                this.config.sections[section].enable = defaultCb;
            }
            if (typeof this.config.sections[section].disable === 'undefined') {
                this.config.sections[section].disable = defaultCb;
            }
        });
    }


    init() {
        // add event listeners
        this._getSectionControls().forEach((control) => {
            control.addEventListener('change', (e) => {
                this.onControlChange(control, control.checked === true);
            })
        });
        [...document.querySelectorAll('.gdpr-save, .gdpr-close')].forEach((control) => {
            control.addEventListener('click', (e) => {
                this.onSave();
            });
        });
        document.querySelector('.gdpr-accept-all').addEventListener('click', (e) => {
            this.onGrantAll();
        });
        document.querySelector('.gdpr-deny-all').addEventListener('click', (e) => {
            this.onDenyAll();
        });

        let preInitialized = CookieHandler.hasCookie('default');
        if (preInitialized) {
            this._showEl(this.interfaceQuickAccessBtn);
        } else {
            this._showEl(this.interfaceBanner);
        }

        // retrieve state
        this.syncStates();
        // call callbacks after sync on initialization
        this._getSectionControls().forEach((control) => {
            let section = control.getAttribute('data-gdpr-section');
            this.config.sections[section][control.checked ? 'enable' : 'disable']();
        });
    }

    onGrantAll() {
        this._setControlsState(true);
        this._getSectionControls().forEach((el) => {
            let section = el.getAttribute('data-gdpr-section');
            this.config.sections[section].enable();
        });
        this.config.sections.default.enable();
        this.persistStates();
        this._closeInterfaces();
    }

    onDenyAll() {
        this._setControlsState(false);
        this._getSectionControls().forEach((el) => {
            let section = el.getAttribute('data-gdpr-section');
            this.config.sections[section].disable();
        });
        this.config.sections.default.disable();
        this.persistStates();
        this._closeInterfaces();
    }

    onSave() {
        this.persistStates();
        this._closeInterfaces();
    }

    onControlChange(control, state) {
        let section = control.getAttribute('data-gdpr-section');
        if (typeof this.config.sections[section] === 'undefined') {
            console.warn('gdpr section "' + section + '" is not declared');
        }
        this.config.sections[section][state ? 'enable' : 'disable']();
        this.persistStates();
    }

    /**
     * check cookie values and init controls
     */
    syncStates() {
        Object.keys(this.config.sections).forEach((section) => {
            let cookieVal = CookieHandler.getCookie(section);
            if (section !== 'default' && cookieVal) {
                this._getSectionControl(section).checked = true;
            }
        });
    }

    /**
     * check controls values and set cookie values
     */
    persistStates() {
        this._getSectionControls().forEach((control) => {
            let section = control.getAttribute('data-gdpr-section');
            if (section !== 'default') {
                CookieHandler.setCookie(section, control.checked === true);
            }
        });
        CookieHandler.setCookie('default', true);
    }

    _getSectionControls() {
        return [...document.querySelectorAll('.gdpr-control:not([data-gdpr-section="default"])')]
    }

    _getSectionControl(section) {
        return document.querySelector('.gdpr-control[data-gdpr-section="' + section + '"]')
    }

    _setControlsState(state) {
        this._getSectionControls().forEach((control) => {
            let section = control.getAttribute('data-gdpr-section');
            if (section !== 'default') {
                control.checked = state;
            } else {
                control.checked = true;
            }
        });
    }

    _closeInterfaces() {
        let modal = document.querySelector('#gdpr-modal');
        modal.classList.remove('show');
        modal.removeAttribute('aria-modal');
        modal.removeAttribute('role');
        modal.setAttribute('aria-hidden', 'true');
        modal.setAttribute('style', 'display: none');

        this._hideEl(this.interfaceBanner);
        this._showEl(this.interfaceQuickAccessBtn);
    }

    _showEl(el) {
        el.classList.add('shown');
    }

    _hideEl(el) {
        el.classList.remove('shown');
    }
};

function isObject(item) {
    return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
 * Deep merge two objects.
 * @param target
 * @param sources
 */
function mergeDeep(target, ...sources) {
    if (!sources.length) return target;
    const source = sources.shift();

    if (isObject(target) && isObject(source)) {
        for (const key in source) {
            if (isObject(source[key])) {
                if (!target[key]) Object.assign(target, {[key]: {}});
                mergeDeep(target[key], source[key]);
            } else {
                Object.assign(target, {[key]: source[key]});
            }
        }
    }

    return mergeDeep(target, ...sources);
}
