/**
 * Created by Flynn Buckingham (https://github.com/flynnham) on 19/05/17.
 */

/* I am aware that this file contains quite the mess of code. Vanilla Javascript comes at a cost, which is development time.
    But in all respects, doing this in pure Javascript is helping me learn and forcing me to research better alternatives
    to certain JS practices.

    ToDO: consider, after initial release, to migrate distro related calls into distro module

 */

import './layout.css'; // layout

import { centerElementX, centerElementY, centerElement, isMobile, isAnimated } from '../global';
import { asciiArtExists, asciiRenderName } from '../ascii';
import { doSearchFromQuery, updateQuery, createDistro, updateFeatureList } from '../distro';

import settings from '../settings';

import '../theme/default.css'; // import theme

// the values of the questions based on index - corresponds with "a" values in the "values/language.json" files
import quizModifiers from '../../values/questions'
import distroData from '../../values/distros.json';

let elems = {}, // global storage for elems object
    overlayOpen = false, // the flag that is set when the overlay is open
    transitionState = false; // the flag that is set when question transitioning is happening - helps prevent events from firing during transitions.

// 0 - off; 1 - on <---- should be moved to a config file? maybe, I'm not entirely sure
const ANIMATION_SPEED = 500; // the default wait time for CSS, is 0 when animations are disabled.

let currentQuestionElement = null, // reference to currently active question element
    activeDistroElement = null; // currently activated distro element

function quizQuestion(elems, languageData, questionNumber) {
    let quizTile, // object that contains the currently rendered frame
        isFinal = false; // boolean that signals if the quiz is done (and the final tile has been rendered)

    if (questionNumber < quizModifiers.length) {
        // the created question is likely to exist -> render
        const quizLanguageStrings = languageData.quiz[questionNumber];
        const artId = 'q' + questionNumber;

        quizTile = document.createElement('div');
        quizTile.className = 'quiz-tile';

    quizTile.innerHTML = `
    <h1>${ quizLanguageStrings.q }</h1>
    <div class="quiz-art">${ (asciiArtExists(artId)) ? asciiRenderName(artId) : '[MISSING ART]' }</div>
    <div class="quiz-responses">${ 
        quizLanguageStrings.a.map( answer => `<button>${ answer }</button>` ).join('')
    }</div>`;

        // add current question to the document
        elems.root.appendChild(quizTile);
    } else if (questionNumber >= quizModifiers.length) {
        isFinal = true;
        // there are no more questions render dummy tile as needed

        quizTile = document.createElement('div');
        quizTile.className = 'quiz-tile';

    quizTile.innerHTML = `
    <p>${ languageData.ui.quiz['end-message'] }</p>
    <button data-role="restart-quiz">${ languageData.ui.buttons['restart-quiz'] }</button>`;

        // add curent question to the document
        elems.root.appendChild(quizTile);
    }

    // vertical center quiz-tile
    centerElementY(quizTile);

    if (typeof quizTile === "object") {
        // there is a new active tile so animate
        setTimeout(()=> {
            transitionState = true; // disable click events on question
            // ready to set the class
            if (currentQuestionElement) {
                // remove the class from the previous element
                currentQuestionElement.classList.add('inactive');
                currentQuestionElement.classList.remove('active');
            }

            isFinal && document.body.classList.add('complete'); // if the tile is final then flag as complete
            quizTile.classList.add('active'); // set the new element to active

            setTimeout(()=> {
                // the transition should be finished now;
                (currentQuestionElement) && elems.root.removeChild(currentQuestionElement);
                currentQuestionElement = quizTile;
                console.log(currentQuestionElement);
                transitionState = false; // enable click events on question
            }, 1100 * isAnimated());
        }, 25);
    }
}

// performs basic search and updates elements accordingly

// small function that updates the disroscroller element
function updateScroller(){
    elems.scroller.firstChild.style.width = elems.distros.scrollWidth - elems.distroMarginStyle.marginLeft.slice(0, -2)+ 'px';
}

function distroClose(){
    if (activeDistroElement) {

        document.body.classList.remove('fade');
        activeDistroElement.classList.remove('activated');
        activeDistroElement.style.top = ''; // begin animation

        // this is instant if animations are disabled
        setTimeout(() => {
            // start animations
            activeDistroElement.classList.remove('expanded', 'ready');
            document.body.classList.remove('overlay');

            activeDistroElement.removeAttribute('style'); // remove any inline stylings
            activeDistroElement.parentNode.removeChild(activeDistroElement); // remove the node

            activeDistroElement = null;

        }, ANIMATION_SPEED * isAnimated());

        overlayOpen = false;
        document.body.removeEventListener('click', activeDistroElement.__closeDistroEvent);
    }
}

function distroExpand(distroNode){
    // update list items if not already updated (before cloning the Node)
    if (!distroNode.dataset.updatedList){
        // update the list
        updateFeatureList(distroNode);

        // distroNode.dataset.updatedList = true; // don't re-render this node again until next search
    }

    let showNode = distroNode.cloneNode(true); // create temporary node for animation effect
    showNode.classList.add('temp'); // add the temp class

    elems.overlay.appendChild(showNode); // add distro tile to overlay

    showNode.classList.add('expanded'); // enable expanded mode
    document.body.classList.add('overlay'); // enable overlay

    !isMobile() && centerElementX(showNode); // center horizontally
    setTimeout(() => {
        showNode.classList.add('ready');
        setTimeout(() => {
            // start animations
            !isMobile() && centerElementY(showNode); // center verically
            showNode.classList.add('activated');
            document.body.classList.add('fade');
            updateScroller();
        }, 25);
    }, 25);

    // set up temporary event handler - bind to distroNode for easy removal
    showNode.__closeDistroEvent = (ee) => {
        if (ee.target.id === "overlay") distroClose(showNode);
    }

    overlayOpen = true; // set overlay module flag to true
    activeDistroElement = showNode; // set reference primarily used for Chromium/Webkit rendering-fix

    console.log(activeDistroElement);

    document.body.addEventListener('click', showNode.__closeDistroEvent);
}

// function that gets the distro node as the child - ONLY to be used inside of a sub-distro call
function getDistroNodefromChild(child){
    let node = child;

    while (node !== elems.distros){
        if (node.classList.contains('distro')) {
            // success! it's actually a distroNode
            return node;
        }

        node = node.parentNode; // iterate to next parent node
    }
    return null // return null otherwise
}

export default (app, quizElement, languageData) => {

    // add animations css if animations are enabled
    elems = {
        root: quizElement,
        overlay: document.getElementById('overlay'),
        distros: quizElement.getElementsByClassName('quiz-distros')[0],
        distroPrompt: quizElement.getElementsByClassName('distro-prompt')[0],
        settings: quizElement.getElementsByClassName('quiz-settings')[0],
        scroller: quizElement.getElementsByClassName('distro-scroller')[0],
        distroMarginStyle: quizElement.getElementsByClassName('distro-margin')[0].style // assumes element exists! (as it should)
    }

    // set matchbar element from parent of distros element
    elems.matchbar = elems.distros.parentNode;

    // very specific code that looks for the first span and first element within it. (should point to em element)
    elems.resultNumber = elems.matchbar.getElementsByClassName('distro-prompt')[0];
    elems.resultNumber = elems.resultNumber.getElementsByTagName('em')[0];

    elems.distroMarginStyle.marginLeft = '0'; // set scroller margin to allow proper width calculations

    let currentQuestion, // stores the current question (should be set at end of this module)
        tempList = document.createDocumentFragment(),     // add the distros to the element
        i = 0;

    // create the distrobution nodes
    for (i; i < distroData.length; i++){
        tempList.appendChild(createDistro(distroData[i], languageData)); // add to search indexer list and to fragment list (for appending)
    }

    elems.distros.appendChild(tempList); // send large list to the DOM

    // set up click event to handle questions (mainly clicked buttons)
    elems.root.addEventListener('click', (e) => {
        const target = e.target;

        if (target.nodeName === "BUTTON") {
            // it's a button, but which kind
            if (target.parentNode.className === "quiz-responses") {
                // it's a quiz response button

                if (transitionState === false) {
                    // only run this code if there is not an ongoing transition between questions
                    let i = 0, node = target;

                    // get target element's index - counts how many nodes are behind it (as i)
                    for (i; (node = node.previousSibling); i++);

                    // modify the query result
                    updateQuery(quizModifiers[currentQuestion][i]);

                    // update the question
                    quizQuestion(elems, languageData, ++currentQuestion);

                    if (currentQuestion > 0){
                        document.body.classList.add('started'); // flag quiz as started
                    }

                    // perform search + update stuff based on the search
                    doSearchFromQuery(elems.distros, elems.resultNumber);
                    updateScroller();
                }
            } else {
                switch (target.dataset.role){
                    case 'restart-quiz':
                        // restarts the quiz
                        window.location.reload();
                        break;
                }
            }
        }
    });

    // set up click event to handle when a user clicks a distro
    elems.distros.addEventListener('click', (e) => {
        if (!overlayOpen) { // only do things if the overlay isn't already open

            let distroNode = getDistroNodefromChild(e.target); // setup the iterator

            // success! it's actually a distroNode -- ToDo: add check in case a future dev decides to use call on non-distro elem
            distroExpand(distroNode);
        }
    });

    // mobile event for mobile tap of the distro bar
    elems.distroPrompt.addEventListener('touchstart', (e) => {
        document.body.classList.add('matchbar-touch');

        let blurEvent;

        blurEvent = (e) =>{
            let target = e.target;

            if (global.matchesAncestor(target, 4, (node) => { return node.classList.contains('quiz-matchbar') })){
                // the target is an ancestor of the matchbar
            } else {
                // it's a blur event
                document.body.classList.remove('matchbar-touch');
                elems.root.removeEventListener('touchend', blurEvent);
            }
        }

        elems.root.addEventListener('touchend', blurEvent);
    });

    elems.overlay.addEventListener('click', (e) => {
        if (overlayOpen) { // only do things if the overlay is already open
            let target = e.target;

            if (target.tagName === "BUTTON") {

                switch (target.dataset.role) {
                    case "close-distro":
                        console.log('close requested');
                        activeDistroElement && distroClose(activeDistroElement);
                        break;
                }
            }
        }
    });

    elems.scroller.addEventListener('scroll', (e) => {
        if (!overlayOpen) elems.distroMarginStyle.marginLeft = -elems.scroller.scrollLeft + 'px';
    });

    // add scroll-wheel event to distro container - allows vertical scrolling with mousewheel
    elems.distros.addEventListener('wheel', (e) =>{
        if (!overlayOpen) elems.scroller.scrollLeft += (e.deltaY / Math.abs(e.deltaY)) * 20;
    });

    function throttledResizeEvent(){

        if (currentQuestionElement){ // if there is a currentQuestion -> center it vertically
            centerElementY(currentQuestionElement);
        }

        if (activeDistroElement){ // if there is an active distro element
            if (!isMobile()) { // if the screen width is wide enough to consider it a desktop
                centerElement(activeDistroElement);
            } else if (activeDistroElement.style.top){
                activeDistroElement.removeAttribute('style'); // remove all in-line styles
            }
        }

        // throttler for the scoller update (fixes issues when maximising or minimizing browser window)
        if (!window.scrollerResizeEvent){
            window.scrollerResizeEvent = setTimeout(function() {
                window.scrollerResizeEvent = null;
                updateScroller(); // update scroller size -> since browser size has most likely changed (? - maybe add check for later)
            }, 250);
        };
    }

    window.addEventListener('resize', () =>{
        if (!window.resizeTimeout) {
            window.resizeTimeout = setTimeout(function() {
                window.resizeTimeout = null;
                throttledResizeEvent();
            }, 33); // approx 30 times per second
        }
    })

    // set question number and render question
    quizQuestion(elems, languageData, currentQuestion = 0);

    // bind the settings module event handler - also pass the search object to enable re-running searches (in the same context);
    settings(elems, languageData.ui.settings);
}