/**
 * Elementor frontend handler for the Age Gate widget.
 *
 * Shows an age-verification overlay until the visitor passes one of three checks
 * (confirm buttons, date of birth, or a checkbox). A passed check is remembered in
 * localStorage for a configurable number of days. Declining either shows a message
 * screen or redirects. Inside the Elementor editor the gate renders inline for
 * styling and never locks the canvas or reads/writes storage. One controller per
 * instance with editor-safe teardown.
 *
 * @package captain-widgets-kit
 * @since   1.6.0
 */

(function ($) {
    'use strict';

    /**
     * Per-instance handler — called by Elementor for every widget instance.
     *
     * @param {jQuery} $scope - The widget wrapper element.
     */
    var CaptwikiAgeGateHandler = function ($scope) {

        var root = $scope[0].querySelector('.captwiki-age-gate');
        if (!root) return;

        if (root._cwkTeardown) {
            root._cwkTeardown();
        }

        var isEditMode = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();

        var overlay = root.querySelector('.captwiki-age-gate__overlay');
        var verify = root.querySelector('.captwiki-age-gate__verify');
        var failScreen = root.querySelector('.captwiki-age-gate__fail');
        var errorEl = root.querySelector('.captwiki-age-gate__error');
        if (!overlay) return;

        var config = {
            minAge: parseInt(root.getAttribute('data-min-age'), 10) || 18,
            rememberDays: parseInt(root.getAttribute('data-remember-days'), 10) || 0,
            storageKey: root.getAttribute('data-storage-key') || 'captwiki_age_gate',
            declineAction: root.getAttribute('data-decline-action') || 'message',
            redirectUrl: root.getAttribute('data-redirect-url') || '',
            method: root.getAttribute('data-verify-method') || 'buttons'
        };

        var handlers = [];

        /**
         * Add an event listener and remember it for later teardown.
         *
         * @param {Element} el   - Target element.
         * @param {string}  type - Event name.
         * @param {Function} fn  - Listener.
         */
        function on(el, type, fn) {
            if (!el) return;
            el.addEventListener(type, fn);
            handlers.push(function () { el.removeEventListener(type, fn); });
        }

        /* ── Storage helpers (guarded — private mode can throw) ── */

        /**
         * Has the visitor already passed within the remembered window?
         *
         * @return {boolean} True if a valid pass is stored.
         */
        function hasPassed() {
            try {
                var raw = window.localStorage.getItem(config.storageKey);
                if (!raw) return false;
                var data = JSON.parse(raw);
                if (!data || data.passed !== true) return false;
                if (data.expires && data.expires < Date.now()) {
                    window.localStorage.removeItem(config.storageKey);
                    return false;
                }
                return true;
            } catch (e) {
                return false;
            }
        }

        /**
         * Persist a passed check for the configured duration.
         */
        function storePass() {
            try {
                var data = { passed: true };
                if (config.rememberDays > 0) {
                    data.expires = Date.now() + config.rememberDays * 86400000;
                }
                window.localStorage.setItem(config.storageKey, JSON.stringify(data));
            } catch (e) { /* storage unavailable — fall back to session only */ }
        }

        /* ── Show / hide ───────────────────────────────────── */

        /**
         * Lock or unlock page scrolling.
         *
         * @param {boolean} lock - Whether to lock.
         */
        function lockScroll(lock) {
            if (isEditMode) return;
            document.body.classList.toggle('captwiki-age-gate-open', lock);
        }

        /**
         * Reveal the gate and trap initial focus.
         */
        function openGate() {
            root.classList.add('is-open');
            lockScroll(true);
            var focusable = overlay.querySelector('button, input');
            if (focusable && !isEditMode) {
                focusable.focus();
            }
        }

        /**
         * Pass the gate — remember the choice and remove the overlay.
         */
        function passGate() {
            if (!isEditMode) {
                storePass();
            }
            root.classList.remove('is-open');
            root.classList.add('is-passed');
            lockScroll(false);
        }

        /**
         * Handle a declined check.
         */
        function declineGate() {
            if (config.declineAction === 'redirect' && config.redirectUrl && !isEditMode) {
                window.location.href = config.redirectUrl;
                return;
            }
            if (verify) verify.hidden = true;
            if (failScreen) failScreen.hidden = false;
        }

        /**
         * Reset back to the verification view from the decline screen.
         */
        function retryGate() {
            if (failScreen) failScreen.hidden = true;
            if (verify) verify.hidden = false;
            hideError();
        }

        /* ── Error helpers ─────────────────────────────────── */

        function showError() {
            if (errorEl) errorEl.hidden = false;
        }

        function hideError() {
            if (errorEl) errorEl.hidden = true;
        }

        /* ── Verification ──────────────────────────────────── */

        /**
         * Compute a whole-number age from a day / month / year.
         *
         * @param {number} d - Day.
         * @param {number} m - Month (1-12).
         * @param {number} y - Year.
         * @return {number|null} Age in years, or null if the date is invalid.
         */
        function computeAge(d, m, y) {
            if (!d || !m || !y || m < 1 || m > 12 || d < 1 || d > 31 || y < 1900) {
                return null;
            }
            var dob = new Date(y, m - 1, d);
            if (dob.getFullYear() !== y || dob.getMonth() !== m - 1 || dob.getDate() !== d) {
                return null;
            }
            if (dob.getTime() > Date.now()) {
                return null;
            }
            var now = new Date();
            var age = now.getFullYear() - y;
            var beforeBirthday = (now.getMonth() < m - 1) || (now.getMonth() === m - 1 && now.getDate() < d);
            if (beforeBirthday) age--;
            return age;
        }

        /**
         * Validate the date-of-birth fields.
         */
        function verifyDob() {
            var day = parseInt((root.querySelector('.captwiki-age-gate__dob-day') || {}).value, 10);
            var month = parseInt((root.querySelector('.captwiki-age-gate__dob-month') || {}).value, 10);
            var year = parseInt((root.querySelector('.captwiki-age-gate__dob-year') || {}).value, 10);

            var age = computeAge(day, month, year);
            if (age === null) {
                showError();
                return;
            }
            hideError();
            if (age >= config.minAge) {
                passGate();
            } else {
                declineGate();
            }
        }

        /**
         * Validate the checkbox confirmation.
         */
        function verifyCheckbox() {
            var box = root.querySelector('.captwiki-age-gate__checkbox');
            if (box && box.checked) {
                hideError();
                passGate();
            } else {
                showError();
            }
        }

        /* ── Wire actions ──────────────────────────────────── */
        var actionButtons = Array.prototype.slice.call(root.querySelectorAll('[data-action]'));

        actionButtons.forEach(function (btn) {
            on(btn, 'click', function () {
                switch (btn.getAttribute('data-action')) {
                    case 'confirm':
                        passGate();
                        break;
                    case 'decline':
                        declineGate();
                        break;
                    case 'verify-dob':
                        verifyDob();
                        break;
                    case 'confirm-check':
                        verifyCheckbox();
                        break;
                    case 'retry':
                        retryGate();
                        break;
                }
            });
        });

        /* ── Init ──────────────────────────────────────────── */
        if (isEditMode) {
            // Always visible inline for styling; never persists or locks the canvas.
            root.classList.add('is-preview', 'is-open');
        } else if (hasPassed()) {
            root.classList.add('is-passed');
        } else {
            openGate();
        }

        /* ── Teardown ──────────────────────────────────────── */
        root._cwkTeardown = function () {
            handlers.forEach(function (off) { off(); });
            handlers = [];
            document.body.classList.remove('captwiki-age-gate-open');
            root._cwkTeardown = null;
        };
    };

    /* ── Register with Elementor frontend ───────────────────── */
    $(window).on('elementor/frontend/init', function () {
        elementorFrontend.hooks.addAction(
            'frontend/element_ready/captwiki-age-gate.default',
            CaptwikiAgeGateHandler
        );
    });

})(jQuery);
