<script type="module">
    var suggestions = document.getElementById('suggestions');
    var search = document.getElementById('flexsearch');

    const flexsearchContainer = document.getElementById('FlexSearchCollapse');

    const hideFlexsearchBtn = document.getElementById('hideFlexsearch');

    const configObject = { toggle: false }
    const flexsearchContainerCollapse = new Collapse(flexsearchContainer, configObject) // initialized with no keyboard

    if (search !== null) {
        document.addEventListener('keydown', inputFocus);
        flexsearchContainer.addEventListener('shown.bs.collapse', function () {
            search.focus();
        });
        // hide search collapse containder by clicking outside (except top header)
        var topHeader = document.getElementById("top-header");
        document.addEventListener('click', function(elem) {
            if (!flexsearchContainer.contains(elem.target) && !topHeader.contains(elem.target))
                flexsearchContainerCollapse.hide();
        });
    }

    hideFlexsearchBtn.addEventListener('click', () =>{
        flexsearchContainerCollapse.hide()
    })

    function inputFocus(e) {
        if (e.ctrlKey && e.key === '/') {
            e.preventDefault();
            flexsearchContainerCollapse.toggle();
        }
        if (e.key === 'Escape' ) {
            search.blur();
            // suggestions.classList.add('d-none');
            flexsearchContainerCollapse.hide();
        }
    };

    document.addEventListener('click', function(event) {

    var isClickInsideElement = suggestions.contains(event.target);

    if (!isClickInsideElement) {
        suggestions.classList.add('d-none');
    }

    });

    /*
    Source:
    - https://dev.to/shubhamprakash/trap-focus-using-javascript-6a3
    */

    document.addEventListener('keydown',suggestionFocus);

    function suggestionFocus(e) {
    const suggestionsHidden = suggestions.classList.contains('d-none');
    if (suggestionsHidden) return;

    const focusableSuggestions= [...suggestions.querySelectorAll('a')];
    if (focusableSuggestions.length === 0) return;

    const index = focusableSuggestions.indexOf(document.activeElement);

    if (e.key === "ArrowUp") {
        e.preventDefault();
        const nextIndex = index > 0 ? index - 1 : 0;
        focusableSuggestions[nextIndex].focus();
    }
    else if (e.key === "ArrowDown") {
        e.preventDefault();
        const nextIndex= index + 1 < focusableSuggestions.length ? index + 1 : index;
        focusableSuggestions[nextIndex].focus();
    }

    }

    /*
    Source:
    - https://github.com/nextapps-de/flexsearch#index-documents-field-search
    - https://raw.githack.com/nextapps-de/flexsearch/master/demo/autocomplete.html
    */

    (function(){

    var index = new FlexSearch.Document({
        // charset: "latin:default",
        tokenize: {{ .Site.Params.flexsearch.tokenize | default "forward" }},
        minlength: {{ .Site.Params.flexsearch.minQueryChar | default 0}},
        cache: {{ .Site.Params.flexsearch.cache | default 100 }},
        optimize: {{ .Site.Params.flexsearch.optimize | default true }},
        document: {
        id: 'id',
        store: [
            "href", "title", "description"
        ],
        index: ["title", "description", "content"]
        }
    });


    // Not yet supported: https://github.com/nextapps-de/flexsearch#complex-documents


    // var docs = [
    //     {{ range $index, $page := (where .Site.Pages "Section" "docs") -}}
    //     {
    //         id: {{ $index }},
    //         href: {{ .Permalink }},
    //         title: {{ .Title }},
    //         description: {{ .Params.description }},
    //         content: {{ .Content }}
    //     },
    //     {{ end -}}
    // ];


    // https://discourse.gohugo.io/t/range-length-or-last-element/3803/2

    {{ $list := slice }}
    {{- if and (isset .Site.Params.flexsearch "searchsectionsindex") (not (eq (len .Site.Params.flexsearch.searchSectionsIndex) 0)) }}
        {{- if eq .Site.Params.flexsearch.searchSectionsIndex "ALL" }}
            {{- $list = .Site.Pages }}
        {{- else }}
            {{- $list = (where .Site.Pages "Type" "in" .Site.Params.flexsearch.searchSectionsIndex) }}
        {{- if (in .Site.Params.flexsearch.searchSectionsIndex "HomePage") }}
            {{ $list = $list | append .Site.Home }}
        {{- end }}
        {{- end }}
    {{- else }}
        {{- $list = (where .Site.Pages "Section" ($.Scratch.Get "pathName")) }}
    {{- end }}

    {{ $len := (len $list) -}}

    {{ range $index, $element := $list -}}
        index.add(
            {
                id: {{ $index }},
                href: "{{ .RelPermalink }}",
                title: {{ .Title }},
                {{ with .Description -}}
                    description: {{ . }},
                {{ else -}}
                description: {{ .Summary | htmlUnescape | plainify }},
                {{ end -}}
                content: {{ .Content | htmlUnescape | plainify }}
            }
        );
    {{ end -}}

    search.addEventListener('input', show_results, true);

    function show_results(){
        const maxResult = {{ .Site.Params.flexsearch.maxResult | default 5}};
        const minlength = {{ .Site.Params.flexsearch.minQueryChar | default 0}};
        var searchQuery = sanitizeHTML(this.value);
        var results = index.search(searchQuery, {limit: maxResult, enrich: true});

        // flatten results since index.search() returns results for each indexed field
        const flatResults = new Map(); // keyed by href to dedupe results
        for (const result of results.flatMap(r => r.result)) {
        if (flatResults.has(result.doc.href)) continue;
        flatResults.set(result.doc.href, result.doc);
        }

        suggestions.innerHTML = "";
        suggestions.classList.remove('d-none');

        // inform user of search query minimum character requirement
        if (searchQuery.length < minlength) {
            const minCharMessage = document.createElement('div')
            minCharMessage.innerHTML = `Please type at least <strong>${minlength}</strong> characters`
            minCharMessage.classList.add("suggestion__no-results");
            suggestions.appendChild(minCharMessage);
            return;
        } else {
            // inform user that no results were found
            if (flatResults.size === 0 && searchQuery) {
                const noResultsMessage = document.createElement('div')
                noResultsMessage.innerHTML = {{ i18n "search_no_results" | default "No results for" }} + ` "<strong>${searchQuery}</strong>"`
                noResultsMessage.classList.add("suggestion__no-results");
                suggestions.appendChild(noResultsMessage);
                return;
            }
        }

        // construct a list of suggestions
        for(const [href, doc] of flatResults) {
            const entry = document.createElement('div');
            suggestions.appendChild(entry);

            const a = document.createElement('a');
            a.href = href;
            entry.appendChild(a);

            const title = document.createElement('span');
            title.textContent = doc.title;
            title.classList.add("suggestion__title");
            a.appendChild(title);

            const description = document.createElement('span');
            description.textContent = doc.description;
            description.classList.add("suggestion__description");
            a.appendChild(description);

            suggestions.appendChild(entry);

            if(suggestions.childElementCount == maxResult) break;
        }
    }
    }());
</script>