(gina.ready(function onGinaReady($){
/**
 * Contact handler
 */
var FormValidator   = require('gina/validator');

var ContactHandler = ( function onContactHandled() {
    var self                = {}
        , $validator        = null
        , $popin            = null
        , $link             = null
    ;

    var
        $select = null
      , hash = null
      , type = null
      , $messages = null
      , $title = null
      , $returnLink = null
    ;

    function _prefersReducedMotion() {
        return !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches);
    }

    function _slideDuration(speed) {
        if (speed === 'fast') return 200;
        if (speed === 'slow') return 600;
        if (typeof(speed) == 'number') return speed;
        return 400;
    }

    function _slideUp(el, speed, callback) {
        // If already hidden, do not register a transitionend listener — no height
        // transition fires here, so the listener would instead fire on a later
        // _slideDown of the same element and re-hide it (jQuery-removal gotcha).
        if (getComputedStyle(el).display == 'none') {
            el.style.display = 'none';
            if (typeof(callback) == 'function') callback();
            return;
        }
        // Honor prefers-reduced-motion: collapse instantly, no height animation.
        if (_prefersReducedMotion()) {
            el.style.display = 'none';
            if (typeof(callback) == 'function') callback();
            return;
        }
        var duration = _slideDuration(speed);
        el.style.overflow = 'hidden';
        el.style.height = el.scrollHeight + 'px';
        el.offsetHeight; // force reflow
        el.style.transition = 'height ' + duration + 'ms ease';
        el.style.height = '0px';
        el.addEventListener('transitionend', function handler() {
            el.removeEventListener('transitionend', handler);
            el.style.display = 'none';
            el.style.transition = '';
            el.style.height = '';
            el.style.overflow = '';
            if (typeof(callback) == 'function') callback();
        });
    }

    function _slideDown(el, speed) {
        // Explicit 'block' (not ''): the CSS base rule `.message-type li { display: none }`
        // would win over an empty inline value and keep the panel hidden.
        el.style.display = 'block';
        // Honor prefers-reduced-motion: reveal instantly, no height animation.
        if (_prefersReducedMotion()) {
            return;
        }
        var duration = _slideDuration(speed);
        el.style.overflow = 'hidden';
        el.style.height = '0px';
        el.offsetHeight; // force reflow
        var targetHeight = el.scrollHeight;
        el.style.transition = 'height ' + duration + 'ms ease';
        el.style.height = targetHeight + 'px';
        el.addEventListener('transitionend', function handler() {
            el.removeEventListener('transitionend', handler);
            el.style.transition = '';
            el.style.height = '';
            el.style.overflow = '';
        });
    }

    /**
     * Where «Retour au tableau de bord» should land if the tab cannot close itself.
     *
     * `document.referrer` IS the dashboard page that opened us — rel="noopener" severs
     * window.opener but does NOT strip the referrer (rel="noreferrer" would). Measured, not
     * assumed. It is only ever used as a navigation target, and only after being checked to be
     * a dashboard URL on our own origin: a referrer is attacker-influenceable, and following one
     * blindly is how you build an open redirect.
     *
     * Falls back to the server-rendered href (the dashboard home) when the referrer is absent
     * — some privacy settings strip it — or points anywhere else.
     */
    function _resolveReturnUrl(fallbackHref) {
        var referrer = document.referrer || '';

        if (referrer.indexOf(window.location.origin + '/entreprise') === 0) {
            return referrer;
        }

        return fallbackHref;
    }

    function bindReturnToDashboard() {
        if (!$returnLink) {
            return;
        }

        var returnUrl = _resolveReturnUrl($returnLink.getAttribute('href'));

        $returnLink.addEventListener('click', function (e) {
            e.preventDefault();

            // This tab was opened by the dashboard's Aide link, so it is allowed to close itself
            // (verified in Chromium even under rel="noopener"). Browsers that refuse get the
            // navigation instead — the setTimeout simply never runs when the close succeeds.
            window.close();
            setTimeout(function () {
                window.location.href = returnUrl;
            }, 250);
        });
    }

    var init = function() {

        $select     = document.getElementById('contact-type');
        hash        = location.hash.substring(1) || ''; // $select.value
        $messages   = document.getElementById('message-type');
        $title      = document.getElementById('contact-title');
        // Rendered only when the visitor arrived from the dashboard (`?from=`), so its absence
        // is the "did not come from the dashboard" case — nothing to bind, nothing to reveal.
        $returnLink = document.getElementById('contact-return-dashboard');

        bindReturnToDashboard();

        handle();
    }

    var handle = function () {
        console.debug('ContactHandler loaded !');

        // On change show the right text
        $select.addEventListener('change', function (e) {
            e.preventDefault();

            changeContactType()
        });

        // Select the correct question type if passed in the hash
        if (hash != '') {
            // console.log('hash',hash);
            $select.value = hash;
            changeContactType();

            return;
        }

        // getCurrentType();
        // $messages.find('li').hide();
        // $('#contact-type-' + type).slideDown();
        changeContactType(true)
    }

    var getCurrentType = function() {
        type = $select.value;
        console.log('type',type);
    }


    var changeContactType = function(isOninit) {
        if ( typeof(isOninit) == 'undefined' ) {
            isOninit = false;
        }
        getCurrentType();
        var items = $messages.querySelectorAll('li');
        var target = document.getElementById('contact-type-' + type);
        if (isOninit) {
            for (var i = 0; i < items.length; i++) {
                items[i].style.display = 'none';
            }
        } else {
            // Collapse every panel except the one we are about to reveal — sliding the
            // target up too would leave a stuck transitionend that re-hides it on reveal.
            for (var i = 0; i < items.length; i++) {
                if (items[i] !== target) _slideUp(items[i]);
            }
        }

        if (target) _slideDown(target);

        // Reflect the context in the heading: the bug type (and the popin entry point,
        // which is dedicated to bug reports) shows "Rapport de bug"; everything else is
        // the generic "Contact". Guarded so a missing #contact-title can't halt init().
        if ($title) {
            $title.innerHTML = (type == 'bug') ? 'Rapport de bug' : 'Contact';
        }
    }

    /**
     * Collapse the page down to the confirmation.
     *
     * Walks up from the response block to the `.contact-form` section, hiding every sibling met on
     * the way: the two intro blurbs, the type selector with its explainer panels, and every field
     * the visitor just filled in. The page title, the site navigation and the footer sit OUTSIDE
     * that section and are deliberately left alone.
     *
     * Nothing here enumerates what to hide — the rule is "keep the confirmation's ancestors, hide
     * their siblings" — so a field added to this form later collapses with the rest by construction.
     *
     * Inline `display:none` rather than the `hidden` attribute: `[hidden]` is a UA-stylesheet rule
     * and any `display:` declaration on these elements would outrank it.
     */
    var isolateResponse = function (response) {
        var boundary = response.closest('.contact-form');
        // No section to collapse (the popin teaser renders no form) — leave the page as it is.
        if (!boundary) {
            return;
        }

        var node = response;
        while (node !== boundary) {
            var parent = node.parentNode;
            if (!parent) {
                return;
            }

            for (var i = 0; i < parent.children.length; i++) {
                if (parent.children[i] !== node) {
                    parent.children[i].style.display = 'none';
                }
            }
            node = parent;
        }
    }

    var onContactFormSent = function(form, status, data) {
        var error = null;
        if (status != 'success') { // handle errors first
            console.error('[ serviceError ] ', data);
            error = data;
        }

        var formSubmit = form.querySelector('.form-submit');
        //success.contact.hform
        if (
            typeof(status) != 'undefined'
            && status == 'success'
            && typeof(data.isSent) != 'undefined'
            && /^true$/i.test(data.isSent)
        ) {
            // remove submit and cancel buttons
            var triggers = formSubmit.querySelectorAll('.form-submit-trigger');
            for (var i = 0; i < triggers.length; i++) {
                triggers[i].parentNode.removeChild(triggers[i]);
            }

            // display message
            var successMsg = formSubmit.querySelector('.form-submit-response > .success');
            if (successMsg) successMsg.hidden = false;

            // «Retour au tableau de bord» — only after the message is actually sent, and only if
            // the server rendered it (i.e. the visitor came from the dashboard). Present but
            // hidden until now, so the offer to leave never competes with the send.
            var returnLink = formSubmit.querySelector('.form-submit-response > .return-to-dashboard');
            if (returnLink) returnLink.hidden = false;

            // The confirmation is one line at the foot of a long form — sent or not, the page looks
            // the same, so the message is easy to miss. Collapse the form and the copy around it:
            // what is left in the section IS the confirmation (and the way back to the dashboard).
            // Errors deliberately do NOT collapse — the visitor still needs the form to try again.
            if ( !form.classList.contains('popin-form') ) {
                isolateResponse(formSubmit.querySelector('.form-submit-response'));
            }
        }
        //error.contact.hform
        else {
            // display message
            var errorMsg = formSubmit.querySelector('.form-submit-response > .error');
            if (errorMsg) errorMsg.hidden = false;
        }

        var response = formSubmit.querySelector('.form-submit-response');
        if (response) response.hidden = false;

        // Popin case
        if ( form.classList.contains('popin-form') ) {
            // form.querySelector('.contact-form > .wrap').style.display = 'none';
            var jsTrigger = formSubmit.querySelector('.form-submit-main.js-trigger');
            if (jsTrigger) jsTrigger.parentNode.removeChild(jsTrigger);

            var submitMain = formSubmit.querySelector('.form-submit-main');
            if (submitMain) submitMain.classList.remove('hidden');
        }
    }

    var onContactXhrResponse = function (event, result) {

        var status = null;
        if ( typeof(event.type) != 'undefined' ) {
            status = event.type.split(/\./)[0];
        }
        // status -> `event.type` ; /^success/.test(event.type)
        console.debug('[ onGenericXhrResponse ] : ', event, result);


        // Generic events handlers
        // handle reload
        if (
            typeof(result.status) != 'undefined' && result.satus == 401  && typeof(result.reload) != 'undefined' && result.reload == true
            || typeof(result.status) != 'undefined' && /^2/.test(result.status) && typeof(result.reload) != 'undefined' && result.reload == true
            || typeof(result.operation) != 'undefined' && result.operation == 'reload'
        ) {
            window.location.hash = ''; //removing hashtag
            window.location.reload();
            return false;
        }

        // handle redirect
        if ( typeof(result.error) != 'undefined' && typeof(result.error.sessionError) != 'undefined' ) {
            window.location.hash = ''; //removing hashtag

            result.location = (!/^http/.test(result.location) && !/^\//.test(result.location) ) ? location.protocol +'//' + result.location : result.location;
            window.location.href = result.location;
            return false;
        }

        // Contact form sent
        if ( /\.contact/.test(event.type) ) {
            onContactFormSent(document.getElementById(event.target.id), status, result)
            return;
        }

    }

    var dependencies = ['formValidator'], triggered = false;
    var onReady = function (dependency) {

        dependencies.splice(dependency, 1);
        if ( !dependencies.length && !triggered ) {
            triggered = true;
            init();
        }
    };

    /**  adding dependencies */
    // loading formValidator
    var formValidator = new FormValidator(gina.forms.rules);
    formValidator.on('ready', function (e, validator) {
        e.preventDefault();

        // useful for CORS
        validator.setOptions({ withCredentials: true });

        // exposing globals
        $validator = validator; // formValidator

        // exports
        // the event used for the form
        window.onContactXhrResponse = onContactXhrResponse; // application events handler

        onReady('formValidator');
    });

})();
},window[originalContext]));
