// Based on https://github.com/orcnog/autocomplete-whisper/blob/master/scripts/autocomplete-whisper.js
export default class Autocomplete {

    handleRenderSidebarTab(app, html, data) {
        /* Set up markup for our UI to be injected */
        const $whisperMenuContainer = $('<div id="command-menu"></div>');
        const $ghostTextarea = $('<textarea class="chatghosttextarea" autocomplete="off" readonly disabled></textarea>');
        let $whisperMenu = $('<nav id="context-menu" class="expand-up"><ol class="context-items"></ol></nav>');

        let regex = new RegExp("\/[A-z]*");

        /* Add our UI to the DOM */
        $("#chat-message").before($whisperMenuContainer);
        $("#chat-message").after($ghostTextarea);

        /* Unbind original FVTT chat textarea keydown handler and implemnt our own to catch up/down keys first */
        $("#chat-message").off("keydown");
        $("#chat-message").on("keydown.menufocus", jumpToMenuHandler);
        /* Listen for chat input. Do stuff.*/
        $("#chat-message").on("input.whisperer", handleChatInput);
        /* Listen for "]" to close an array of targets (names) */
        $("#chat-message").on("keydown.closearray", listFinishHandler);
        /* Listen for up/down arrow presses to navigate exposed menu */
        $("#command-menu").on("keydown.menufocus", menuNavigationHandler);
        /* Listen for click on a menu item */
        $("#command-menu").on("click", "li", menuItemSelectionHandler);

        function handleChatInput() {

            if (!game.settings.get("_chatcommands", "autocomplete")) return;

            resetGhostText();
            const val = $("#chat-message").val();
            //console.log(val);
            if (val.match(regex)) {
    
                // It's a commands! Show a menu of commands and typeahead text if possible
                // let splt = val.split(regex);
                // console.log(splt);

                let input = val;


                let allCommands = [];
                allCommands = allCommands.concat(window.game.chatCommands.registeredCommands);

                if (game.settings.get("_chatcommands", "includeCoreCommands")) {
                    allCommands = allCommands.concat(_getCoreCommands());
                }

                let matchingCommands = allCommands.filter((target) => {
                    const p = target.commandKey.toUpperCase();
                    const i = val.toUpperCase();
                    return p.indexOf(i) >= 0 && p !== i;
                });

                //console.log(matchingCommands);

                if (matchingCommands.length > 0) {
    
                    // At least one potential target exists.
                    // show ghost text to autocomplete if there's a match starting with the characters already typed
                    ghostText(input, matchingCommands);
                    // set up and display the menu of whisperable names
                    let listOfPlayers = "";
                    for (let p in matchingCommands) {
                        if (isNaN(p)) continue;
                        let command = matchingCommands[p];
                        const name = command.commandKey;
                        let nameHtml = name;
                        let startIndex = name.toUpperCase().indexOf(input.toUpperCase());
                        if (input && startIndex > -1) {
                            nameHtml = name.substr(0, startIndex) + "<strong>" + name.substr(startIndex, input.length) + "</strong>" + name.substr(startIndex + input.length);
                        }
                        listOfPlayers += `<li class="context-item" data-name="${name}" tabIndex="0"><i class="fas ${command.iconClass} fa-fw" style="padding-right: 5px;"></i>${nameHtml} - ${command.description}</li>`;
                    }
                    $whisperMenu.find("ol").html(listOfPlayers);
                    $("#command-menu").html($whisperMenu);
    
                    // set up click-outside listener to close menu
                    $(window).on("click.outsidewhispermenu", (e) => {
                        var $target = $(e.target);
                        if (!$target.closest("#command-menu").length) {
                            closeWhisperMenu();
                        }
                    });
                } else {
                    closeWhisperMenu();
                }
            } else {
                closeWhisperMenu();
            }
        }

        function _getCoreCommands() {
            let commands = [];

            let chatCommands = window.game.chatCommands;

            commands.push(chatCommands.createCommandFromData({
                commandKey: "/ic",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Speak in character"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/ooc",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Speak out of character"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/emote",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Emote in character"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/whisper",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Send a whisper to another player"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/w",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Send a whisper to another player"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/roll",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Roll dice"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/gmroll",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Roll dice that only the GM can see"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/blindroll",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Roll dice that are hidden"
              }));
            
              commands.push(chatCommands.createCommandFromData({
                commandKey: "/selfroll",
                invokeOnCommand: (chatlog, messageText, chatdata) => {
                },
                shouldDisplayToChat: false,
                iconClass: "fa-dice-d20",
                description: "Roll dice that only you can see"
              }));

            return commands;
        }
    
        function listFinishHandler(e) {
            if (e.which == 221) { // `]`
                let val = $("#chat-message").val();
                if (val.match(listOfNamesRegex)) {
                    if (typeof e === "object") e.preventDefault();
                    val = val.trim();
                    const newval = val.substring(val.length - 1) === "," ? val.substring(0, val.length - 1) : val; // remove `,` from the end
                    $("#chat-message").val(newval + "] ");
                    closeWhisperMenu();
                }
            }
        }
    
        function jumpToMenuHandler(e) {
            if ($("#command-menu").find("li").length) {
                if (e.which === 38) { // `up`
                    $("#command-menu li:last-child").focus();
                    return false;
                } else if (e.which === 40) { // `down`
                    $("#command-menu li:first-child").focus();
                    return false;
                }
            }
            if (game.modules.get("autocomplete-whisper") != undefined) {
              if ($("#whisper-menu").find("li").length) {
                if (e.which === 38) { // `up`
                  $("#whisper-menu li:last-child").focus();
                  return false;
                } else if (e.which === 40) { // `down`
                  $("#whisper-menu li:first-child").focus();
                  return false;
                }
              }
            }
            // if player menu is not visible/DNE, execute FVTT's original keydown handler
            ui.chat._onChatKeyDown(e);
        }
    
        function menuNavigationHandler(e) {
            if ($(e.target).is("li.context-item")) {
                if (e.which === 38) { // `up`
                    if ($(e.target).is(":first-child")) {
                        $("#chat-message").focus();
                    } else {
                        $(e.target).prev().focus();
                    }
                    return false;
                } else if (e.which === 40) { // `down`
                    if ($(e.target).is(":last-child")) {
                        $("#chat-message").focus();
                    } else {
                        $(e.target).next().focus();
                    }
                    return false;
                } else if (e.which === 13) { // `enter`
                    menuItemSelectionHandler(e);
                    return false;
                }
            }
        }
    
        function menuItemSelectionHandler(e) {
            e.stopPropagation();
            var autocompleteText = autocomplete($(e.target).text());
            $("#chat-message").val(autocompleteText.ghost);
            $("#chat-message").focus();
            closeWhisperMenu();
            if ($("#chat-message").val().indexOf("[") > -1) {
                handleChatInput();
            }
        }
    
        function ghostText(input, matches) {
            // show ghost text to autocomplete if there's a match starting with the characters already typed
            let filteredMatches = matches.filter((target) => {
                const p = target.commandKey.toUpperCase();
                const i = input.toUpperCase();
                return p.indexOf(i) === 0 && p !== i;
            });
            if (filteredMatches.length === 1) {
                var autocompleteText = autocomplete(filteredMatches[0].commandKey);
                $(".chatghosttextarea").val(autocompleteText.ghost);
                $(".chatghosttextarea").addClass("show");
                $("#chat-message").on("keydown.ghosttab", (e) => {
                    if (e.which == 9) { // tab
                        e.preventDefault();
                        $("#chat-message").val(autocompleteText.ghost);
                        resetGhostText();
                        $("#chat-message").focus();
                        closeWhisperMenu();
                        if ($("#chat-message").val().indexOf("[") > -1) {
                            handleChatInput();
                        }
                    }
                });
            } else {
                resetGhostText();
            }
        }
    
        function autocomplete(match) {
            if (!match) return;

            const typedCharacters = $("#chat-message").val();
            let nameToAdd = '';
            if (match.toUpperCase().indexOf(typedCharacters.toUpperCase()) === 0) {
                var restOfTheName = match.substr(typedCharacters.length);
                nameToAdd = typedCharacters + restOfTheName;
            } else {
                nameToAdd = match;
            }

            if (nameToAdd.includes(" - ")) {
                nameToAdd = nameToAdd.substr(0, nameToAdd.indexOf(" - "));
            }

            const ghostString = nameToAdd;
            
            return ({
                ghost: ghostString
            });
        }
    
        function closeWhisperMenu() {
            $("#command-menu").empty();
            $(window).off("click.outsidewhispermenu");
            resetGhostText();
        }
    
        function resetGhostText() {
            $("#chat-message").off("keydown.ghosttab");
            $(".chatghosttextarea").val("").removeClass("show");
        }
    }
}
