define(['jquery',
      'core/log',
      'core/ajax',
      'mod_minilesson/definitions',
      'mod_minilesson/pollyhelper',
      'mod_minilesson/ttrecorder',
      'mod_minilesson/animatecss',
      'core/templates',
      'core/str',
      'core/notification'
    ], function ($, log, ajax, def, polly, ttrecorder, anim, templates,str,notification) {
        "use strict"; // jshint ;_;

        log.debug('MiniLesson listen and repeat: initialising');

        return {

          //a handle on the tt recorder
            ttrec: null,

          //for making multiple instances
            clone: function () {
                return $.extend(true, {}, this);
            },

            init: function (index, itemdata, quizhelper) {
                var self = this;
                var theCallback = function (message) {

                    switch (message.type) {
                        case 'recording':
            break;

                        case 'speech':
                            log.debug("speech at listen_repeat");
                          //var wordcount = quizhelper.count_words(message.capturedspeech);
                            self.getComparison(
                                self.items[self.game.pointer].target,
                                message.capturedspeech,
                                self.items[self.game.pointer].phonetic,
                                function (comparison) {
                                    self.gotComparison(comparison, message);
                                }
                            );
            break;
                    }

                };

                if (quizhelper.use_ttrecorder()) {
                    var opts = {};
                    opts.uniqueid = itemdata.uniqueid;
                    opts.callback = theCallback;
                    opts.stt_guided = quizhelper.is_stt_guided();
                    opts.wwwroot = quizhelper.is_stt_guided();
                    self.ttrec = ttrecorder.clone();
                    self.ttrec.init(opts);
                } else {
                  //init cloudpoodll push recorder
                    cloudpoodll.init('minilesson-recorder-listenrepeat-' + itemdata.id, theCallback);
                }

                self.itemdata = itemdata;
                self.quizhelper = quizhelper;
                self.index = index;
                self.strings = {};

      //anim
                var animopts = {};
                animopts.useanimatecss = quizhelper.useanimatecss;
                anim.init(animopts);

                self.init_controls();
                self.init_strings();
                self.register_events();
                self.setvoice();
                self.getItems();
            },

            init_controls: function () {
                var self = this;
                self.controls = {
                    container: $("#" + self.itemdata.uniqueid + "_container"),
                    nextbutton: $("#" + self.itemdata.uniqueid + "_container .minilesson_nextbutton"),
                    start_btn: $("#" + self.itemdata.uniqueid + "_container .landr_start_btn"),
                    skip_btn: $("#" + self.itemdata.uniqueid + "_container .landr_skip_btn"),
                    ctrl_btn: $("#" + self.itemdata.uniqueid + "_container .landr_ctrl-btn"),
                    game: $("#" + self.itemdata.uniqueid + "_container .landr_game"),
                    controlsbox: $("#" + self.itemdata.uniqueid + "_container .landr_controls"),
                    resultscontainer: $("#" + self.itemdata.uniqueid + "_container .landr_resultscontainer"),
                    speakbtncontainer: $("#" + self.itemdata.uniqueid + "_container .landr_speakbtncontainer"),
                    mainmenu: $("#" + self.itemdata.uniqueid + "_container .landr_mainmenu"),
                    title: $("#" + self.itemdata.uniqueid + "_container .landr_title"),
                    question: $("#" + self.itemdata.uniqueid + "_container .landr_question"),
                    speech_container: $("#" + self.itemdata.uniqueid + "_container .landr_speechcontainer"),
                    landr_correctfeedback: $("#" + self.itemdata.uniqueid + "_container .landr_correctfeedback"),
                    landr_incorrectfeedback: $("#" + self.itemdata.uniqueid + "_container .landr_incorrectfeedback"),
                    landr_fbcontainer: $("#" + self.itemdata.uniqueid + "_container .landr_fbcontainer"),
                    landr_feedback: $("#" + self.itemdata.uniqueid + "_container .landr_feedback"),
                    landr_listen_btn: $("#" + self.itemdata.uniqueid + "_container .landr_listen_btn"),
                    progress_container: $("#" + self.itemdata.uniqueid + "_container .progress-container"),
                    description: $("#" + self.itemdata.uniqueid + "_container .landr_description"),
                    image: $("#" + self.itemdata.uniqueid + "_container .landr_image_container"),
                    maintitle: $("#" + self.itemdata.uniqueid + "_container .landr_maintitle"),
                    itemquestion: $("#" + self.itemdata.uniqueid + "_container .landr_itemtext"),
                };
            },

            init_strings: function () {
                var self = this;
                str.get_strings([
                { "key": "nextlessonitem", "component": 'mod_minilesson'},
                { "key": "confirm_desc", "component": 'mod_minilesson'},
                { "key": "yes", "component": 'moodle'},
                { "key": "no", "component": 'moodle'},
                ]).done(function (s) {
                          var i = 0;
                          self.strings.nextlessonitem = s[i++];
                          self.strings.confirm_desc = s[i++];
                          self.strings.yes = s[i++];
                          self.strings.no = s[i++];
                });
            },

            next_question: function (percent) {
                var self = this;
                var stepdata = {};
                stepdata.index = self.index;
                stepdata.hasgrade = true;
                stepdata.totalitems = self.items.length;
                stepdata.correctitems = self.items.filter(function (e) {
                            return e.correct;
                }).length;
                stepdata.grade = stepdata.totalitems > 0 ? Math.round((stepdata.correctitems / stepdata.totalitems) * 100) : 0;

      //stop audio
                self.stop_audio();

      //transition
                self.quizhelper.do_next(stepdata);
            },

            show_item_review: function () {
                var self = this;

                self.items.forEach(function (item) {
                            var itemwordlist = [];
                            item.landr_targetWords.forEach(function (data) {
                                if (data !== '') {
                                    itemwordlist.push(data);
                                }
                            });
                            var wordmatch = itemwordlist.join("");
                            var regex = new RegExp(wordmatch, "gi");
                            var answerclass = item.correct ? 'correctitem' : 'wrongitem';
                            var result = item.target.replace(regex, `<span class="${answerclass}">${wordmatch}</span>`);
                            item.target = result;
                });

                var review_data = {};
                review_data.items = self.items;
                review_data.totalitems = self.items.length;
                review_data.correctitems = self.items.filter(function (e) {
                            return e.correct;
                }).length;

      //display results
                var gamebox = self.controls.game;
                var controlsbox = self.controls.controlsbox;
                var recorderbox = self.controls.speakbtncontainer;
                var resultsbox = self.controls.resultscontainer;
                var audioplayerbtn = self.controls.landr_listen_btn;
                templates.render('mod_minilesson/listitemresults', review_data).then(
                    function (html, js) {
                            resultsbox.html(html);
                            //show and hide
                            resultsbox.show();
                            gamebox.hide();
                            controlsbox.hide();
                            recorderbox.hide();
                            audioplayerbtn.hide();
                            self.controls.progress_container.hide();
                            self.controls.title.hide();
                            // Run js for audio player events
                            templates.runTemplateJS(js);
                    }
                );// End of templates
            },

            register_events: function () {

                var self = this;
      //on next button click
                self.controls.nextbutton.on('click', function (e) {
                    if (self.items.some(item => !item.answered)) {
                        notification.confirm(
                            self.strings.nextlessonitem,
                            self.strings.confirm_desc,
                            self.strings.yes,
                            self.strings.no,
                            function () {
                                self.next_question();
                            }
                        );
                    } else {
                        self.next_question();
                    }
                });
      //on start button click
                self.controls.start_btn.on("click", function () {
                            self.start();
                });


      //AUDIO PLAYER Button events
                var audioplayerbtn = self.controls.landr_listen_btn;
      // On listen button click
                audioplayerbtn.on("click", function () {
                            var theaudio = self.items[self.game.pointer].audio;

                            //if we are already playing stop playing
                    if (!theaudio.paused) {
                        theaudio.pause();
                        theaudio.currentTime = 0;
                        $(audioplayerbtn).children('.fa').removeClass('fa-stop');
                        $(audioplayerbtn).children('.fa').addClass('fa-volume-up');
                        return;
                    }

                  //change icon to indicate playing state
                    theaudio.addEventListener('ended', function () {
                        $(audioplayerbtn).children('.fa').removeClass('fa-stop');
                        $(audioplayerbtn).children('.fa').addClass('fa-volume-up');
                    });

                            theaudio.addEventListener('play', function () {
                                $(audioplayerbtn).children('.fa').removeClass('fa-volume-up');
                                $(audioplayerbtn).children('.fa').addClass('fa-stop');
                            });
                            theaudio.load();
                            theaudio.play();
                });

      //on skip button click
                self.controls.skip_btn.on("click", function () {
                            //disable the buttons
                            self.controls.ctrl_btn.prop("disabled", true);
                            //reveal the prompt
                            self.controls.container.find('.landr_speech.landr_teacher_left').text(self.items[self.game.pointer].displayprompt + "");
                            //reveal the answer
                            self.controls.container.find('.landr_word_input').each(function () {
                                var realidx = $(this).data("realidx");
                                var landr_word_input = self.items[self.game.pointer].landr_targetWords[realidx];
                                $(this).val(landr_word_input);
                            });

                            //mark as answered and incorrect
                            self.items[self.game.pointer].answered = true;
                            self.items[self.game.pointer].correct = false;

                            //Stop timer
                            self.stopTimer(self.items[self.game.pointer].timer);

                            //next prompt or end
                    if (self.game.pointer < self.items.length - 1) {
                        self.controls.skip_btn.prop("disabled", true);
                        self.controls.skip_btn.children('.fa').removeClass('fa-arrow-right');
                        self.controls.skip_btn.children('.fa').addClass('fa-spinner fa-spin');
          //move on after short time to next prompt
                        setTimeout(function () {
                            self.controls.skip_btn.children('.fa').removeClass('fa-spinner fa-spin');
                            self.controls.skip_btn.children('.fa').addClass('fa-arrow-right');
                            self.controls.skip_btn.prop("disabled", false);
                            self.game.pointer++;
                            self.nextPrompt();
                        }, 2200);
          //end question
                    } else {
                        self.end();
                    }
                });

            },


            game: {
                pointer: 0
            },
            usevoice: '',
            setvoice: function () {
                var self = this;
                self.usevoice = self.itemdata.usevoice;
                self.voiceoption = self.itemdata.voiceoption;
                return;
            },
            getItems: function () {
                var self = this;
                var text_items = self.itemdata.sentences;

                self.items = text_items.map(function (target) {
                            return {
                                landr_targetWords: target.sentence.trim().split(self.quizhelper.spliton_regexp).filter(function (e) {
                                    return e !== "";
                                }),
                            target: target.sentence,
                            prompt: target.prompt,
                            displayprompt: target.displayprompt,
                            phonetic: target.phonetic,
                            typed: "",
                            answered: false,
                            correct: false,
                            audio: null,
                            timer: [],
                            audiourl: target.audiourl ? target.audiourl : "",
                            imageurl: target.imageurl,
                    };
                }).filter(function (e) {
                          return e.target !== "";
                });


                $.each(self.items, function (index, item) {
                            item.audio = new Audio();
                            item.audio.src = item.audiourl;
                    if (self.items.filter(function (e) {
                        return e.audio === null;
                    }).length === 0) {
                        self.appReady();
                    }
                });
            },

            appReady: function () {
                var self = this;
                self.controls.container.find('.landr_not_loaded').hide();
                self.controls.container.find('.landr_loaded').show();
                if (self.itemdata.hidestartpage) {
                            self.start();
                } else {
                          self.controls.start_btn.prop("disabled", false);
                }

            },

            gotComparison: function (comparison, typed) {
                var self = this;

                self.controls.container.find('.landr_word_input').removeClass("landr_correct landr_incorrect");
                self.controls.container.find('.landr_feedback_icon').removeClass("fa fa-check fa-times");

                var allCorrect = comparison.filter(function (e) {
                            return !e.matched;
                }).length == 0;

                if (allCorrect && comparison && comparison.length > 0) {
                            self.controls.container.find('.landr_word_input').addClass("landr_correct");
                            self.controls.container.find('.landr_feedback_icon').addClass("fa fa-check");
                            self.controls.container.find('.landr_speech.landr_teacher_left').text(self.items[self.game.pointer].displayprompt + "");

                            self.items[self.game.pointer].answered = true;
                            self.items[self.game.pointer].correct = true;
                            self.items[self.game.pointer].typed = typed;

                            //stop timer
                            self.stopTimer(self.items[self.game.pointer].timer);

                            self.controls.ctrl_btn.prop("disabled", true);
                    if (self.game.pointer < self.items.length - 1) {
                        setTimeout(function () {
                                  self.game.pointer++;
                                  self.nextPrompt();
                        }, 2200);
                    } else {
                        self.end();
                    }
                } else {
                    //mark up the words as correct or not
                    comparison.forEach(function (obj) {
                        if (!obj.matched) {
                            self.controls.container.find('.landr_word_input[data-idx="' + obj.wordnumber + '"]').addClass("landr_incorrect");
                            self.controls.container.find('.landr_feedback_icon[data-idx="' + obj.wordnumber + '"]').addClass("fa fa-times");
                        } else {
                            self.controls.container.find('.landr_word_input[data-idx="' + obj.wordnumber + '"]').addClass("landr_correct");
                            self.controls.container.find('.landr_feedback_icon[data-idx="' + obj.wordnumber + '"]').addClass("fa fa-check");
                        }
                    });
                    var thereply = self.controls.container.find('.landr_reply_' + self.game.pointer);
                    anim.do_animate(thereply, 'shakeX animate__faster').then(
                        function () {
                              self.controls.ctrl_btn.prop("disabled", false);
                        }
                    );
                }
      //show all the correct words
                self.controls.container.find('.landr_word_input.landr_correct').each(function () {
                          var realidx = $(this).data("realidx");
                          var landr_word_input = self.items[self.game.pointer].landr_targetWords[realidx];
                          $(this).val(landr_word_input);
                });

            },

            getWords: function (thetext) {
                var self = this;
                var checkcase = false;
                if (checkcase == 'false') {
                            thetext = thetext.toLowerCase();
                }
                var chunks = thetext.split(self.quizhelper.spliton_regexp).filter(function (e) {
                          return e !== "";
                });
                var words = [];
                for (var i = 0; i < chunks.length; i++) {
                    if (!chunks[i].match(self.quizhelper.spliton_regexp)) {
                        words.push(chunks[i]);
                    }
                }
                return words;
            },
            getComparison: function (passage, transcript, phonetic, callback) {
                var self = this;

                self.controls.ctrl_btn.prop("disabled", true);
                self.quizhelper.comparePassageToTranscript(passage, transcript, phonetic, self.itemdata.language, self.itemdata.alternates).then(function (ajaxresult) {
                            var payloadobject = JSON.parse(ajaxresult);
                    if (payloadobject) {
                        callback(payloadobject);
                    } else {
                        callback(false);
                    }
                });

            },
            end: function () {
                var self = this;
                self.controls.nextbutton.prop("disabled", true);

      //progress dots are updated on next_item. The last item has no next item, so we update from here
                self.updateProgressDots();

      //disable the buttons and go to next question or review
                setTimeout(function () {
                            self.controls.nextbutton.prop("disabled", false);
                    if (self.quizhelper.showitemreview) {
                        self.show_item_review();
                    } else {
                        self.next_question();
                    }
                }, 2200);

            },
            start: function () {
                var self = this;

                self.controls.ctrl_btn.prop("disabled", true);
                self.controls.speakbtncontainer.show();
                self.controls.title.show();

                self.items.forEach(function (item) {
                            item.spoken = "";
                            item.answered = false;
                            item.correct = false;
                });

                self.game.pointer = 0;

                self.controls.game.show();
                self.controls.start_btn.hide();
                self.controls.description.hide();
                self.controls.image.hide();
                self.controls.maintitle.show();
                self.controls.itemquestion.show();
                self.controls.container.find('.landr_listen_cont').show();
                self.controls.mainmenu.hide();
                self.controls.controlsbox.show();
                self.nextPrompt();
            },

            nextPrompt: function () {
                var showText = parseInt(this.itemdata.show_text);
                var self = this;

      //target is the speech we expect
                var target = self.items[self.game.pointer].target;
      //in some cases ttrecorder wants to know the target
                if (self.quizhelper.use_ttrecorder()) {
                            self.ttrec.currentPrompt = target;
                }
                var displayprompt = self.items[self.game.pointer].displayprompt;
                if (!showText) {
                          var nopunc = displayprompt.replace(self.quizhelper.nopunc_regexp, "");
                          var dots = nopunc.replace(self.quizhelper.nonspaces_regexp, '•');
                          var showprompt = dots;
                } else {
                        var showprompt = displayprompt;
                }

                templates.render(
                    'minilessonitem_listenrepeat/listenrepeat_prompt',
                    {showprompt: showprompt, pointer: self.game.pointer}
                )
                .then(function (html, js) {
                    self.controls.game.html(html);
                    self.controls.ctrl_btn.prop("disabled", false);
                    self.updateProgressDots();
                    var newprompt = self.controls.container.find(".landr_prompt_" + self.game.pointer);
                    anim.do_animate(newprompt, 'zoomIn animate__faster', 'in').then(
                        function () {
                        }
                    );
                    self.nextReply();
                });// End of templates
            },

            updateProgressDots: function () {
                var self = this;
                var color,icon;
                var progress = self.items.map(function (item, idx) {
                            color = "#E6E9FD";
                            icon = "fa fa-square";
                    if (self.items[idx].answered && self.items[idx].correct) {
                        color = "#74DC72";
                        icon = 'fa fa-check-square';
                    } else if (self.items[idx].answered && !self.items[idx].correct) {
                        color = "#FB6363";
                        icon = "fa fa-window-close";
                    }
                    return "<i style='color:" + color + "' class='" + icon + " pl-1'></i>";
                }).join(" ");
                self.controls.title.html(progress);
            },

            nextReply: function () {
                var self = this;
                var idx = 0;
                var words = self.items[self.game.pointer].landr_targetWords.map(function (word, realidx) {
                            var theword = {};
                    if (!word.match(self.quizhelper.spliton_regexp)) {
                        idx++;
                        theword.isword = true;
                        theword.idx = idx;
                        theword.length = word.length;
                        theword.lengthplusone = word.length + 1;
                        theword.realidx = realidx;
                    } else {
                        theword.isword = false;
                        theword.text = word;
                    }
                    return theword;
                });
                var displaytimer = self.itemdata.timelimit > 0;

                templates.render(
                    'minilessonitem_listenrepeat/listenrepeat_reply',
                    {words: words, pointer: self.game.pointer, imageurl: self.items[self.game.pointer].imageurl, displaytimer}
                )
                .then(function (html, js) {
                        //update html reply area
                        self.controls.game.append(html);
                        // set handle to the reply and animate it in
                        var newreply = self.controls.container.find(".landr_reply_" + self.game.pointer);
                        anim.do_animate(newreply, 'zoomIn animate__faster', 'in').then(
                            function () {
                            }
                        );

                        // Enable the skip button
                        self.controls.ctrl_btn.prop("disabled", false);

                        //we autoplay the audio on item entry, if its not a mobile user
                        //and we have a startpage (or we have a startpage but its not the first item)
                    if (!self.quizhelper.mobile_user()) {
                        if (self.itemdata.hidestartpage && self.game.pointer === 0) {
                            self.controls.container.on("showElement", () => {
                                setTimeout(function () {
                                    self.controls.landr_listen_btn.trigger('click');
                                }, 1000);
                            });
                        } else {
                            setTimeout(function () {
                                self.controls.landr_listen_btn.trigger('click');
                            }, 1000);
                        }
                    }

                  //do the timer
                    if (displaytimer) {
                        self.startTimer();
                    }

                });//end of templates.render
            },//end of next reply

          // Stop audio .. usually when leaving the item or sentence
            stop_audio: function () {
                var self = this;
      //pause audio if its playing
                var theaudio = self.items[self.game.pointer].audio;
                if (theaudio && !theaudio.paused) {
                            theaudio.pause();
                }
            },

            startTimer: function () {
                var self = this;
                var progress_container = self.controls.progress_container;
        // If we have a time limit, set up the timer, otherwise return
                if (self.itemdata.timelimit > 0) {
                          // This is a function to start the timer (we call it conditionally below)
                          var doStartTimer = function () {
                        // This shows progress bar
                            progress_container.show();
                            progress_container.find('i').show();
                            var progresbar = progress_container.find('#progresstimer').progressTimer({
                                height: '5px',
                                timeLimit: self.itemdata.timelimit,
                                onFinish: function () {
                                    self.controls.skip_btn.trigger('click');
                                }
                            });
                            progresbar.each(function () {
                                self.items[self.game.pointer].timer.push($(this).attr('timer'));
                            });
                          }

            // This adds the timer and starts it. But if we dont have a start page and its the first item
            // we need to defer the timer start until the item is shown
                    if (self.itemdata.hidestartpage && self.game.pointer === 0) {
                        self.controls.container.on("showElement", () => {
                            doStartTimer();
                        });
                    } else {
                        doStartTimer();
                    }
                }
            }, //end of start timer

            stopTimer: function (timers) {
                if (timers.length) {
                          timers.forEach(function (timer) {
                            clearInterval(timer);
                          });
                }
            },// end of stop timer

        } // end of return
    });//end of define