// Initialize function, create initial tokens with itens that are already selected by the user
function init(element) {
    // Create div that wroaps all the elements inside (select, elements selected, search div) to put select inside
    const wrapper = document.createElement("div");
    wrapper.addEventListener("click", clickOnWrapper);
    wrapper.classList.add("multi-select-component");

    // Create elements of search
    const search_div = document.createElement("div");
    search_div.classList.add("search-container");
    const input = document.createElement("input");
    input.classList.add("selected-input");
    input.setAttribute("autocomplete", "off");
    input.setAttribute("tabindex", "0");
    input.addEventListener("keyup", inputChange);
    input.addEventListener("keydown", deletePressed);
    input.addEventListener("click", openOptions);

    const dropdown_icon = document.createElement("a");
    dropdown_icon.setAttribute("href", "#");
    dropdown_icon.classList.add("dropdown-icon");

    dropdown_icon.addEventListener("click", clickDropdown);
    const autocomplete_list = document.createElement("ul");
    autocomplete_list.classList.add("autocomplete-list")
    search_div.appendChild(input);
    search_div.appendChild(autocomplete_list);
    search_div.appendChild(dropdown_icon);

    // set the wrapper as child (instead of the element)
    element.parentNode.replaceChild(wrapper, element);
    // set element as child of wrapper
    wrapper.appendChild(element);
    wrapper.appendChild(search_div);

    createInitialTokens(element);
    addPlaceholder(wrapper);
}

function removePlaceholder(wrapper) {
    const input_search = wrapper.querySelector(".selected-input");
    input_search.removeAttribute("placeholder");
}

function addPlaceholder(wrapper) {
    const input_search = wrapper.querySelector(".selected-input");
    const tokens = wrapper.querySelectorAll(".selected-wrapper");
    if (!tokens.length && !(document.activeElement === input_search))
        input_search.setAttribute("placeholder", " ");
}


// Function that create the initial set of tokens with the options selected by the users
function createInitialTokens(select) {
    let {
        options_selected
    } = getOptions(select);
    const wrapper = select.parentNode;
    for (let i = 0; i < options_selected.length; i++) {
        createToken(wrapper, options_selected[i]);
    }
}


// Listener of user search
function inputChange(e) {
    const wrapper = e.target.parentNode.parentNode;
    const select = wrapper.querySelector("select");
    const dropdown = wrapper.querySelector(".dropdown-icon");

    const input_val = e.target.value;

    if (input_val) {
        dropdown.classList.add("active");
        populateAutocompleteList(select, input_val.trim());
    } else {
        dropdown.classList.remove("active");
        const event = new Event('click');
        dropdown.dispatchEvent(event);
    }
}


// Listen for clicks on the wrapper, if click happens focus on the input
function clickOnWrapper(e) {
    const wrapper = e.target;
    if (wrapper.tagName == "DIV") {
        const input_search = wrapper.querySelector(".selected-input");
        const dropdown = wrapper.querySelector(".dropdown-icon");
        if (!dropdown.classList.contains("active")) {
            const event = new Event('click');
            dropdown.dispatchEvent(event);
        }
        input_search.focus();
        removePlaceholder(wrapper);
    }

}

function openOptions(e) {
    const input_search = e.target;
    const wrapper = input_search.parentElement.parentElement;
    const dropdown = wrapper.querySelector(".dropdown-icon");
    if (!dropdown.classList.contains("active")) {
        const event = new Event('click');
        dropdown.dispatchEvent(event);
    }
    e.stopPropagation();

}

// Function that create a token inside of a wrapper with the given value
function createToken(wrapper, value) {
    const search = wrapper.querySelector(".search-container");
    // Create token wrapper
    const token = document.createElement("div");
    token.classList.add("selected-wrapper");
    const token_span = document.createElement("span");
    token_span.classList.add("selected-label");
    token_span.innerText = value;
    const close = document.createElement("a");
    close.classList.add("selected-close");
    close.setAttribute("tabindex", "-1");
    close.setAttribute("data-option", value);
    close.setAttribute("data-hits", 0);
    close.setAttribute("href", "#");
    close.innerText = "x";
    close.addEventListener("click", removeToken)
    token.appendChild(token_span);
    token.appendChild(close);
    wrapper.insertBefore(token, search);
}


// Listen for clicks in the dropdown option
function clickDropdown(e) {

    const dropdown = e.target;
    const wrapper = dropdown.parentNode.parentNode;
    const input_search = wrapper.querySelector(".selected-input");
    const select = wrapper.querySelector("select");
    dropdown.classList.toggle("active");

    if (dropdown.classList.contains("active")) {
        removePlaceholder(wrapper);
        input_search.focus();

        if (!input_search.value) {
            populateAutocompleteList(select, "", true);
        } else {
            populateAutocompleteList(select, input_search.value);

        }
    } else {
        clearAutocompleteList(select);
        addPlaceholder(wrapper);
    }
}


// Clears the results of the autocomplete list
function clearAutocompleteList(select) {
    const wrapper = select.parentNode;

    const autocomplete_list = wrapper.querySelector(".autocomplete-list");
    autocomplete_list.innerHTML = "";
}

// Populate the autocomplete list following a given query from the user
function populateAutocompleteList(select, query, dropdown = false) {
    const {
        autocomplete_options
    } = getOptions(select);


    let options_to_show;

    if (dropdown)
        options_to_show = autocomplete_options;
    else
        options_to_show = autocomplete(query, autocomplete_options);

    const wrapper = select.parentNode;
    const input_search = wrapper.querySelector(".search-container");
    const autocomplete_list = wrapper.querySelector(".autocomplete-list");
    autocomplete_list.innerHTML = "";
    const result_size = options_to_show.length;

    if (result_size == 1) {

        const li = document.createElement("li");
        li.innerText = options_to_show[0];
        li.setAttribute('data-value', options_to_show[0]);
        li.addEventListener("click", selectOption);
        autocomplete_list.appendChild(li);
        if (query.length == options_to_show[0].length) {
            const event = new Event('click');
            li.dispatchEvent(event);

        }
    } else if (result_size > 1) {

        for (let i = 0; i < result_size; i++) {
            const li = document.createElement("li");
            li.innerText = options_to_show[i];
            li.setAttribute('data-value', options_to_show[i]);
            li.addEventListener("click", selectOption);
            autocomplete_list.appendChild(li);
        }
    } else {
        const li = document.createElement("li");
        li.classList.add("not-cursor");
        li.innerText = "No options found";
        autocomplete_list.appendChild(li);
    }
}


// Listener to autocomplete results when clicked set the selected property in the select option 
function selectOption(e) {
    const wrapper = e.target.parentNode.parentNode.parentNode;
    const input_search = wrapper.querySelector(".selected-input");
    const option = wrapper.querySelector(`select option[value="${e.target.dataset.value}"]`);

    option.setAttribute("selected", "");
    createToken(wrapper, e.target.dataset.value);
    if (input_search.value) {
        input_search.value = "";
    }

    input_search.focus();

    e.target.remove();
    const autocomplete_list = wrapper.querySelector(".autocomplete-list");


    if (!autocomplete_list.children.length) {
        const li = document.createElement("li");
        li.classList.add("not-cursor");
        li.innerText = "No options found";
        autocomplete_list.appendChild(li);
    }

    const event = new Event('keyup');
    input_search.dispatchEvent(event);
    e.stopPropagation();
}


// function that returns a list with the autcomplete list of matches
function autocomplete(query, options) {
    // No query passed, just return entire list
    if (!query) {
        return options;
    }
    let options_return = [];

    for (let i = 0; i < options.length; i++) {
        if (query.toLowerCase() === options[i].slice(0, query.length).toLowerCase()) {
            options_return.push(options[i]);
        }
    }
    return options_return;
}


// Returns the options that are selected by the user and the ones that are not
function getOptions(select) {
    // Select all the options available
    const all_options = Array.from(
        select.querySelectorAll("option")
    ).map(el => el.value);

    // Get the options that are selected from the user
    const options_selected = Array.from(
        select.querySelectorAll("option:checked")
    ).map(el => el.value);

    // Create an autocomplete options array with the options that are not selected by the user
    const autocomplete_options = [];
    all_options.forEach(option => {
        if (!options_selected.includes(option)) {
            autocomplete_options.push(option);
        }
    });

    autocomplete_options.sort();

    return {
        options_selected,
        autocomplete_options
    };

}

// Listener for when the user wants to remove a given token.
function removeToken(e) {
    // Get the value to remove
    const value_to_remove = e.target.dataset.option;
    const wrapper = e.target.parentNode.parentNode;
    const input_search = wrapper.querySelector(".selected-input");
    const dropdown = wrapper.querySelector(".dropdown-icon");
    // Get the options in the select to be unselected
    const option_to_unselect = wrapper.querySelector(`select option[value="${value_to_remove}"]`);
    option_to_unselect.removeAttribute("selected");
    // Remove token attribute
    e.target.parentNode.remove();
    input_search.focus();
    dropdown.classList.remove("active");
    const event = new Event('click');
    dropdown.dispatchEvent(event);
    //e.stopPropagation();
}

// Listen for 2 sequence of hits on the delete key, if this happens delete the last token if exist
function deletePressed(e) {
    const wrapper = e.target.parentNode.parentNode;
    const input_search = e.target;
    const key = e.keyCode || e.charCode;
    const tokens = wrapper.querySelectorAll(".selected-wrapper");

    if (tokens.length) {
        const last_token_x = tokens[tokens.length - 1].querySelector("a");
        let hits = +last_token_x.dataset.hits;

        if (key == 8 || key == 46) {
            if (!input_search.value) {

                if (hits > 1) {
                    // Trigger delete event
                    const event = new Event('click');
                    last_token_x.dispatchEvent(event);
                } else {
                    last_token_x.dataset.hits = 2;
                }
            }
        } else {
            last_token_x.dataset.hits = 0;
        }
    }
    return true;
}

// You can call this function if you want to add new options to the select plugin
// Target needs to be a unique identifier from the select you want to append new option for example #multi-select-plugin
// Example of usage addOption("#multi-select-plugin", "tesla", "Tesla")
function addOption(target, val, text) {
    const select = document.querySelector(target);
    let opt = document.createElement('option');
    opt.value = val;
    opt.innerHTML = text;
    select.appendChild(opt);
}

document.addEventListener("DOMContentLoaded", () => {

    // get select that has the options available
    const select = document.querySelectorAll("[data-multi-select-plugin]");
    select.forEach(select => {

        init(select);
    });

    // Dismiss on outside click
    document.addEventListener('click', () => {
        // get select that has the options available
        const select = document.querySelectorAll("[data-multi-select-plugin]");
        for (let i = 0; i < select.length; i++) {
            if (event) {
                var isClickInside = select[i].parentElement.parentElement.contains(event.target);

                if (!isClickInside) {
                    const wrapper = select[i].parentElement.parentElement;
                    const dropdown = wrapper.querySelector(".dropdown-icon");
                    const autocomplete_list = wrapper.querySelector(".autocomplete-list");
                    //the click was outside the specifiedElement, do something
                    dropdown.classList.remove("active");
                    autocomplete_list.innerHTML = "";
                    addPlaceholder(wrapper);
                }
            }
        }
    });

});



document.addEventListener('click', function(event) {
    var target = event.target;
    
    // Check if the clicked element has the class "selected-close"
    if (target.classList.contains('selected-close')) {
        event.preventDefault(); // Prevent the default behavior of the link click

        var selectedWrapper = closestByClass(target, 'selected-wrapper'); // Find the closest selected-wrapper div
        var value = target.getAttribute('data-option'); // Get the value of the option to be deselected

        // Remove the selected attribute from the corresponding option in the select element
        var selectOptions = document.querySelectorAll('.multi-select-component select option[value="' + value + '"]');
        selectOptions.forEach(function(option) {
            option.selected = false;
        });

        // Remove the "selected" attribute from the option element itself
        selectOptions.forEach(function(option) {
            option.removeAttribute('selected');
        });

        // Remove the selected-wrapper div from the DOM
        selectedWrapper.parentNode.removeChild(selectedWrapper);
    }
});

// Function to find the closest ancestor element with a specific class
function closestByClass(el, className) {
    while (el && !el.classList.contains(className)) {
        el = el.parentElement;
    }
    return el;
}



// $(document).ready(function() {
//     // Initialize function, create initial tokens with items that are already selected by the user
//     function init(element) {
//         // Create div that wraps all the elements inside (select, elements selected, search div) to put select inside
//         var wrapper = $("<div>").addClass("multi-select-component").click(clickOnWrapper);

//         // Create elements of search
//         var search_div = $("<div>").addClass("search-container");
//         var input = $("<input>").addClass("selected-input").attr({
//             "autocomplete": "off",
//             "tabindex": "0"
//         }).keyup(inputChange).keydown(deletePressed).click(openOptions);

//         var dropdown_icon = $("<a>").attr("href", "#").addClass("dropdown-icon").click(clickDropdown);
//         var autocomplete_list = $("<ul>").addClass("autocomplete-list");

//         search_div.append(input).append(autocomplete_list).append(dropdown_icon);

//         // set the wrapper as child (instead of the element)
//         element.parent().replaceWith(wrapper);
//         // set element as child of wrapper
//         wrapper.append(element).append(search_div);

//         createInitialTokens(element);
//         addPlaceholder(wrapper);
//     }

//     function removePlaceholder(wrapper) {
//         var input_search = wrapper.find(".selected-input");
//         input_search.removeAttr("placeholder");
//     }

//     function addPlaceholder(wrapper) {
//         var input_search = wrapper.find(".selected-input");
//         var tokens = wrapper.find(".selected-wrapper");
//         // if (!tokens.length && !(document.activeElement === input_search.get(0)))
//         //     input_search.attr("placeholder", "---------");
//     }

//     // Function that create the initial set of tokens with the options selected by the users
//     function createInitialTokens(select) {
//         var options_selected = getOptions(select).options_selected;
//         var wrapper = select.parent();
//         options_selected.forEach(function(value) {
//             createToken(wrapper, value);
//         });
//     }

//     // Listener of user search
//     function inputChange(e) {
//         var wrapper = $(e.target).parent().parent();
//         var select = wrapper.find("select");
//         var dropdown = wrapper.find(".dropdown-icon");
//         var input_val = $(e.target).val();

//         if (input_val) {
//             dropdown.addClass("active");
//             populateAutocompleteList(select, input_val.trim());
//         } else {
//             dropdown.removeClass("active");
//             var event = new Event('click');
//             dropdown.get(0).dispatchEvent(event);
//         }
//     }

//     // Listen for clicks on the wrapper, if click happens focus on the input
//     function clickOnWrapper(e) {
//         var wrapper = $(e.target);
//         if (wrapper.prop("tagName") == "DIV") {
//             var input_search = wrapper.find(".selected-input");
//             var dropdown = wrapper.find(".dropdown-icon");
//             if (!dropdown.hasClass("active")) {
//                 var event = new Event('click');
//                 dropdown.get(0).dispatchEvent(event);
//             }
//             input_search.focus();
//             removePlaceholder(wrapper);
//         }
//     }

//     function openOptions(e) {
//         var input_search = $(e.target);
//         var wrapper = input_search.parent().parent();
//         var dropdown = wrapper.find(".dropdown-icon");
//         if (!dropdown.hasClass("active")) {
//             var event = new Event('click');
//             dropdown.get(0).dispatchEvent(event);
//         }
//         e.stopPropagation();
//     }

//     // Function that create a token inside of a wrapper with the given value
//     function createToken(wrapper, value) {
//         var search = wrapper.find(".search-container");
//         var token = $("<div>").addClass("selected-wrapper");
//         var token_span = $("<span>").addClass("selected-label").text(value);
//         var close = $("<a>").attr({
//             "tabindex": "-1",
//             "data-option": value,
//             "data-hits": 0,
//             "href": "#"
//         }).addClass("selected-close").text("x").click(removeToken);
//         token.append(token_span).append(close);
//         search.before(token);
//     }

//     // Listen for clicks in the dropdown option
//     function clickDropdown(e) {
//         var dropdown = $(e.target);
//         var wrapper = dropdown.parent().parent();
//         var input_search = wrapper.find(".selected-input");
//         var select = wrapper.find("select");
//         dropdown.toggleClass("active");

//         if (dropdown.hasClass("active")) {
//             removePlaceholder(wrapper);
//             input_search.focus();

//             if (!input_search.val()) {
//                 populateAutocompleteList(select, "", true);
//             } else {
//                 populateAutocompleteList(select, input_search.val());
//             }
//         } else {
//             clearAutocompleteList(select);
//             addPlaceholder(wrapper);
//         }
//     }

//     // Clears the results of the autocomplete list
//     function clearAutocompleteList(select) {
//         var wrapper = select.parent();
//         var autocomplete_list = wrapper.find(".autocomplete-list");
//         autocomplete_list.empty();
//     }

//     // Populate the autocomplete list following a given query from the user
//     function populateAutocompleteList(select, query, dropdown) {
//         var autocomplete_options = getOptions(select).autocomplete_options;

//         var options_to_show;

//         if (dropdown)
//             options_to_show = autocomplete_options;
//         else
//             options_to_show = autocomplete(query, autocomplete_options);

//         var wrapper = select.parent();
//         var input_search = wrapper.find(".selected-input");
//         var autocomplete_list = wrapper.find(".autocomplete-list");
//         autocomplete_list.empty();
//         var result_size = options_to_show.length;

//         if (result_size == 1) {

//             var li = $("<li>").text(options_to_show[0]).attr('data-value', options_to_show[0]).click(selectOption);
//             autocomplete_list.append(li);
//             if (query.length == options_to_show[0].length) {
//                 var event = new Event('click');
//                 li.get(0).dispatchEvent(event);
//             }
//         } else if (result_size > 1) {

//             for (var i = 0; i < result_size; i++) {
//                 var li = $("<li>").text(options_to_show[i]).attr('data-value', options_to_show[i]).click(selectOption);
//                 autocomplete_list.append(li);
//             }
//         } else {
//             var li = $("<li>").addClass("not-cursor").text("No options found");
//             autocomplete_list.append(li);
//         }
//     }

//     // Listener to autocomplete results when clicked set the selected property in the select option
//     function selectOption(e) {
//         var wrapper = $(e.target).parent().parent().parent();
//         var input_search = wrapper.find(".selected-input");
//         var option = wrapper.find(`select option[value="${$(e.target).attr('data-value')}"]`);

//         option.attr("selected", "");
//         createToken(wrapper, $(e.target).attr('data-value'));
//         if (input_search.val()) {
//             input_search.val("");
//         }

//         input_search.focus();

//         $(e.target).remove();
//         var autocomplete_list = wrapper.find(".autocomplete-list");

//         if (!autocomplete_list.children().length) {
//             var li = $("<li>").addClass("not-cursor").text("No options found");
//             autocomplete_list.append(li);
//         }

//         var event = new Event('keyup');
//         input_search.get(0).dispatchEvent(event);
//         e.stopPropagation();
//     }

//     // function that returns a list with the autcomplete list of matches
//     function autocomplete(query, options) {
//         // No query passed, just return entire list
//         if (!query) {
//             return options;
//         }
//         var options_return = [];

//         for (var i = 0; i < options.length; i++) {
//             if (query.toLowerCase() === options[i].slice(0, query.length).toLowerCase()) {
//                 options_return.push(options[i]);
//             }
//         }
//         return options_return;
//     }

//     // Returns the options that are selected by the user and the ones that are not
//     function getOptions(select) {
//         // Select all the options available
//         var all_options = select.find("option").map(function() {
//             return $(this).val();
//         }).get();

//         // Get the options that are selected from the user
//         var options_selected = select.find("option:checked").map(function() {
//             return $(this).val();
//         }).get();

//         // Create an autocomplete options array with the options that are not selected by the user
//         var autocomplete_options = [];
//         $.each(all_options, function(index, option) {
//             if (!options_selected.includes(option)) {
//                 autocomplete_options.push(option);
//             }
//         });

//         autocomplete_options.sort();

//         return {
//             options_selected: options_selected,
//             autocomplete_options: autocomplete_options
//         };
//     }

//     // Listener for when the user wants to remove a given token.
//     function removeToken(e) {
//         // Get the value to remove
//         var value_to_remove = $(e.target).attr('data-option');
//         var wrapper = $(e.target).parent().parent().parent();
//         var input_search = wrapper.find(".selected-input");
//         var dropdown = wrapper.find(".dropdown-icon");
//         // Get the options in the select to be unselected
//         var option_to_unselect = wrapper.find(`select option[value="${value_to_remove}"]`);
//         option_to_unselect.removeAttr("selected");
//         // Remove token attribute
//         $(e.target).parent().remove();
//         input_search.focus();
//         dropdown.removeClass("active");
//         var event = new Event('click');
//         dropdown.get(0).dispatchEvent(event);
//         //e.stopPropagation();
//     }

//     // Listen for 2 sequence of hits on the delete key, if this happens delete the last token if exist
//     function deletePressed(e) {
//         var wrapper = $(e.target).parent().parent();
//         var input_search = $(e.target);
//         var key = e.keyCode || e.charCode;
//         var tokens = wrapper.find(".selected-wrapper");

//         if (tokens.length) {
//             var last_token_x = tokens.last().find("a");
//             var hits = +last_token_x.attr("data-hits");

//             if (key == 8 || key == 46) {
//                 if (!input_search.val()) {

//                     if (hits > 1) {
//                         // Trigger delete event
//                         var event = new Event('click');
//                         last_token_x.get(0).dispatchEvent(event);
//                     } else {
//                         last_token_x.attr("data-hits", 2);
//                     }
//                 }
//             } else {
//                 last_token_x.attr("data-hits", 0);
//             }
//         }
//         return true;
//     }

//     // You can call this function if you want to add new options to the select plugin
//     // Target needs to be a unique identifier from the select you want to append new option for example #multi-select-plugin
//     // Example of usage addOption("#multi-select-plugin", "tesla", "Tesla")
//     function addOption(target, val, text) {
//         var select = $(target);
//         var opt = $("<option>").val(val).html(text);
//         select.append(opt);
//     }

//     // get select that has the options available
//     $("[data-multi-select-plugin]").each(function() {
//         init($(this));
//     });

//     // Dismiss on outside click
//     $(document).on('click', function(event) {
//         // get select that has the options available
//         var select = $("[data-multi-select-plugin]");
//         select.each(function() {
//             if (event) {
//                 var isClickInside = $(this).parent().parent().get(0).contains(event.target);

//                 if (!isClickInside) {
//                     var wrapper = $(this).parent().parent();
//                     var dropdown = wrapper.find(".dropdown-icon");
//                     var autocomplete_list = wrapper.find(".autocomplete-list");
//                     //the click was outside the specifiedElement, do something
//                     dropdown.removeClass("active");
//                     autocomplete_list.empty();
//                     addPlaceholder(wrapper);
//                 }
//             }
//         });
//     });

//     $(document).on('click', '.selected-close', function(e) {
//         e.preventDefault(); // Prevent the default behavior of the link click
        
//         var $selectedWrapper = $(this).closest('.selected-wrapper'); // Find the closest selected-wrapper div
//         var value = $(this).data('option'); // Get the value of the option to be deselected
        
//         // Remove the selected attribute from the corresponding option in the select element
//         $('.multi-select-component select option[value="' + value + '"]').prop('selected', false);
        
//         // Remove the "selected" attribute from the option element itself
//         $('.multi-select-component select option[value="' + value + '"]').removeAttr('selected');
        
//         // Remove the selected-wrapper div from the DOM
//         $selectedWrapper.remove();
//     });

// });
