/*
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
 *
 *  Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import { Controller } from "@hotwired/stimulus";
import { autocomplete } from '@algolia/autocomplete-js';
//import "@algolia/autocomplete-theme-classic/dist/theme.css";
import "../../css/components/autocomplete_bootstrap_theme.css";
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
import {marked} from "marked";

import {
    trans,
    SEARCH_PLACEHOLDER,
    SEARCH_SUBMIT,
    STATISTICS_PARTS
} from '../../translator';


/**
 * This controller is responsible for the search fields in the navbar and the homepage.
 * It uses the Algolia Autocomplete library to provide a fast and responsive search.
 */
export default class extends Controller {

    static targets = ["input"];

    _autocomplete;

    // Highlight the search query in the results
    _highlight = (text, query) => {
        if (!text) return text;
        if (!query) return text;

        const HIGHLIGHT_PRE_TAG = '__aa-highlight__'
        const HIGHLIGHT_POST_TAG = '__/aa-highlight__'

        const escaped = query.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
        const regex = new RegExp(escaped, 'gi');

        return text.replace(regex, (match) => `${HIGHLIGHT_PRE_TAG}${match}${HIGHLIGHT_POST_TAG}`);
    }

    initialize() {
        // The endpoint for searching parts
        const base_url = this.element.dataset.autocomplete;
        // The URL template for the part detail pages
        const part_detail_uri_template = this.element.dataset.detailUrl;

        //The URL of the placeholder picture
        const placeholder_image = this.element.dataset.placeholderImage;

        //If the element is in navbar mode, or not
        const navbar_mode = this.element.dataset.navbarMode === "true";

        const that = this;

        const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
            key: 'RECENT_SEARCH',
            limit: 5,
        });

        this._autocomplete = autocomplete({
            container: this.element,
            //Place the panel in the navbar, if the element is in navbar mode
            panelContainer: navbar_mode ? document.getElementById("navbar-search-form") : document.body,
            panelPlacement: this.element.dataset.panelPlacement,
            plugins: [recentSearchesPlugin],
            openOnFocus: true,
            placeholder: trans(SEARCH_PLACEHOLDER),
            translations: {
                submitButtonTitle: trans(SEARCH_SUBMIT)
            },

            // Use a navigator compatible with turbo:
            navigator: {
                navigate({ itemUrl }) {
                    window.Turbo.visit(itemUrl, { action: "advance" });
                },
                navigateNewTab({ itemUrl }) {
                    const windowReference = window.open(itemUrl, '_blank', 'noopener');

                    if (windowReference) {
                        windowReference.focus();
                    }
                },
                navigateNewWindow({ itemUrl }) {
                    window.open(itemUrl, '_blank', 'noopener');
                },
            },

            // If the form is submitted, forward the term to the form
            onSubmit({state, event, ...setters}) {
                //Put the current text into each target input field
                const input = that.inputTarget;

                if (!input) {
                    return;
                }

                //Do not submit the form, if the input is empty
                if (state.query === "") {
                    return;
                }

                input.value = state.query;
                input.form.requestSubmit();
            },


            getSources({ query }) {
                return [
                    // The parts source
                    {
                        sourceId: 'parts',
                        getItems() {
                            const url = base_url.replace('__QUERY__', encodeURIComponent(query));

                            const data = fetch(url)
                                .then((response) => response.json())
                                ;

                            //Iterate over all fields besides the id and highlight them
                            const fields = ["name", "description", "category", "footprint"];

                            data.then((items) => {
                                items.forEach((item) => {
                                    for (const field of fields) {
                                        item[field] = that._highlight(item[field], query);
                                    }
                                });
                            });

                            return data;
                        },
                        getItemUrl({ item }) {
                            return part_detail_uri_template.replace('__ID__', item.id);
                        },
                        templates: {
                            header({ html }) {
                                return html`<span class="aa-SourceHeaderTitle">${trans(STATISTICS_PARTS)}</span>
                                    <div class="aa-SourceHeaderLine" />`;
                            },
                            item({item, components, html}) {
                                const details_url = part_detail_uri_template.replace('__ID__', item.id);

                                return html`
                                    <a class="aa-ItemLink" href="${details_url}">
                                        <div class="aa-ItemContent">
                                            <div class="aa-ItemIcon aa-ItemIcon--picture aa-ItemIcon--alignTop">
                                                <img src="${item.image !== "" ? item.image : placeholder_image}" alt="${item.name}" width="30" height="30"/>
                                            </div>
                                            <div class="aa-ItemContentBody">
                                                <div class="aa-ItemContentTitle">
                                                    <b>
                                                        ${components.Highlight({hit: item, attribute: 'name'})}
                                                    </b>
                                                </div>
                                                <div class="aa-ItemContentDescription">
                                                    ${components.Highlight({hit: item, attribute: 'description'})}
                                                    ${item.category ? html`<p class="m-0"><span class="fa-solid fa-tags fa-fw"></span>${components.Highlight({hit: item, attribute: 'category'})}</p>` : ""}
                                                    ${item.footprint ? html`<p class="m-0"><span class="fa-solid fa-microchip fa-fw"></span>${components.Highlight({hit: item, attribute: 'footprint'})}</p>` : ""}
                                                </div>
                                            </div>
                                        </div>
                                    </a>
                                `;
                            },
                        },
                    },
                ];
            },
        });

        //Try to find the input field and register a defocus handler. This is necessarry, as by default the autocomplete
        //lib has problems when multiple inputs are present on the page. (see https://github.com/algolia/autocomplete/issues/1216)
        const inputs = this.element.getElementsByClassName('aa-Input');
        for (const input of inputs) {
            input.addEventListener('blur', () => {
                this._autocomplete.setIsOpen(false);
            });
        }

    }
}