/** @odoo-module **/

import {Component, useEffect, useRef, useState} from "@odoo/owl";

class AutocompletePopup extends Component {
    /**
     * Component setup method that initializes refs, state, and effects
     */
    setup() {
        this.popupRef = useRef("popupRef");
        this.searchInput = useRef("searchInput");
        this.itemsContainer = useRef("itemsContainer");

        // State for search functionality
        this.state = useState({
            searchTerm: "",
        });

        useEffect(
            () => {
                this.scrollToSelected();
            },
            () => [this.props.selectedIndex]
        );

        // Auto-focus search input when popup opens
        useEffect(
            () => {
                if (this.searchInput.el) {
                    // Use setTimeout to ensure DOM is ready
                    const timeoutId = setTimeout(() => {
                        this.searchInput.el.focus();
                    }, 0);
                    return () => clearTimeout(timeoutId);
                }
            },
            () => []
        );

        useEffect(
            () => {
                if (this.props.position) {
                    const timeoutId = setTimeout(() => {
                        if (this.popupRef.el) {
                            this.popupRef.el.style.left = `${this.props.position.left}px`;
                            this.popupRef.el.style.top = `${this.props.position.top}px`;
                            this.popupRef.el.style.position = "fixed";
                        }
                    }, 0);
                    return () => clearTimeout(timeoutId);
                }
            },
            () => [this.props.position]
        );

        // Cleanup effect to clear search timeout
        useEffect(
            () => {
                return () => {
                    if (this.searchTimeout) {
                        clearTimeout(this.searchTimeout);
                    }
                };
            },
            () => []
        );
    }

    /**
     * Updates search term from external keyboard input (from editor)
     * @param {String} char - The character typed or 'Backspace' for deletion
     */
    updateSearchFromEditor(char) {
        if (char === "Backspace") {
            this.state.searchTerm = this.state.searchTerm.slice(0, -1);
        } else if (char.length === 1) {
            this.state.searchTerm += char;
        }
        if (this.props.onSelectedIndexChange) {
            this.props.onSelectedIndexChange(0);
        }
    }

    /**
     * Filters commands based on search term with enhanced search capabilities
     * @returns {Array} Filtered and sorted array of commands matching the search term
     */
    get filteredCommands() {
        if (!this.state.searchTerm.trim()) {
            return this.props.commands;
        }

        const searchTerm = this.state.searchTerm.toLowerCase();

        // Filter and score commands based on search relevance
        const scoredCommands = this.props.commands
            .map((command) => {
                const name = (command.name || "").toLowerCase();
                const reference = (command.reference || "").toLowerCase();

                let score = 0;

                // Exact matches get highest priority
                if (name === searchTerm || reference === searchTerm) {
                    score = 1000;
                }
                // Starts with search term gets high priority
                else if (
                    name.startsWith(searchTerm) ||
                    reference.startsWith(searchTerm)
                ) {
                    score = 100;
                }
                // Contains search term gets medium priority
                else if (name.includes(searchTerm) || reference.includes(searchTerm)) {
                    score = 10;
                }
                // No match
                else {
                    return null;
                }

                // Boost score for name matches over reference matches
                if (name.includes(searchTerm)) {
                    score += 5;
                }

                // Boost score for shorter matches (more relevant)
                score += Math.max(0, 50 - Math.min(name.length, reference.length));

                return {command, score};
            })
            .filter((item) => item !== null)
            .sort((a, b) => b.score - a.score)
            .map((item) => item.command);

        return scoredCommands;
    }

    /**
     * Debounces the search filtering
     * @param {String} searchTerm - The search term to set
     */
    debouncedSearch(searchTerm) {
        if (this.searchTimeout) {
            clearTimeout(this.searchTimeout);
        }
        this.searchTimeout = setTimeout(() => {
            this.state.searchTerm = searchTerm;
            if (this.props.onSelectedIndexChange) {
                this.props.onSelectedIndexChange(0);
            }
        }, 150);
    }

    /**
     * Handles search input changes
     * @param {Event} ev - The input event
     */
    onSearchInput(ev) {
        ev.stopPropagation();
        this.debouncedSearch(ev.target.value);
    }

    /**
     * Common keyboard navigation logic
     * @param {KeyboardEvent} ev - The keyboard event
     */
    handleKeyboardNavigation(ev) {
        if (ev.key === "ArrowDown") {
            ev.preventDefault();
            const newIndex = Math.min(
                (this.props.selectedIndex || 0) + 1,
                this.filteredCommands.length - 1
            );
            if (this.props.onSelectedIndexChange) {
                this.props.onSelectedIndexChange(newIndex);
            }
            this.scrollToSelected();
        } else if (ev.key === "ArrowUp") {
            ev.preventDefault();
            const newIndex = Math.max((this.props.selectedIndex || 0) - 1, 0);
            if (this.props.onSelectedIndexChange) {
                this.props.onSelectedIndexChange(newIndex);
            }
            this.scrollToSelected();
        } else if (ev.key === "Enter") {
            ev.preventDefault();
            const selectedCommand =
                this.filteredCommands[this.props.selectedIndex || 0];
            if (selectedCommand) {
                this.onItemClick(selectedCommand);
            }
        } else if (ev.key === "Escape") {
            ev.preventDefault();
            this.props.onItemClick(null);
        }
    }

    /**
     * Handles keydown events on search input
     * @param {KeyboardEvent} ev - The keyboard event
     */
    onSearchKeyDown(ev) {
        ev.stopPropagation();
        this.handleKeyboardNavigation(ev);
    }

    /**
     * Handles focus events on search input
     * @param {FocusEvent} ev - The focus event
     */
    onSearchFocus(ev) {
        ev.stopPropagation();
    }

    /**
     * Handles blur events on search input
     * @param {FocusEvent} ev - The blur event
     */
    onSearchBlur(ev) {
        ev.stopPropagation();
    }

    /**
     * Handles click events on search input
     * @param {MouseEvent} ev - The click event
     */
    onSearchClick(ev) {
        ev.stopPropagation();
    }

    /**
     * Handles mousedown events on search input
     * @param {MouseEvent} ev - The mousedown event
     */
    onSearchMouseDown(ev) {
        ev.stopPropagation();
    }

    /**
     * Handles item click events
     * @param {Object} command - The selected command object
     */
    onItemClick(command) {
        this.props.onItemClick(command);
    }

    /**
     * Handles close button click events
     */
    onCloseClick() {
        this.props.onItemClick(null);
    }

    /**
     * Handles global keydown events for the popup
     * @param {KeyboardEvent} ev - The keyboard event
     */
    onKeyDown(ev) {
        // Handle search input from editor keyboard events
        if (ev.key.length === 1 && ev.key.match(/[a-zA-Z0-9_]/)) {
            // Add typed character to search
            this.updateSearchFromEditor(ev.key);
        } else if (ev.key === "Backspace") {
            // Remove last character from search
            this.updateSearchFromEditor("Backspace");
        } else {
            // Use common keyboard navigation logic
            this.handleKeyboardNavigation(ev);
        }
    }

    /**
     * Scrolls the selected item into view
     */
    scrollToSelected() {
        const itemsContainer = this.itemsContainer.el;
        if (
            itemsContainer &&
            this.props.selectedIndex !== undefined &&
            this.props.selectedIndex >= 0 &&
            this.props.selectedIndex < itemsContainer.children.length
        ) {
            const selectedItem = itemsContainer.children[this.props.selectedIndex];
            if (selectedItem) {
                selectedItem.scrollIntoView({
                    block: "nearest",
                    behavior: "smooth",
                });
            }
        }
    }

    /**
     * Returns CSS class for autocomplete item based on selection state
     * @param {Number} index - The item index
     * @returns {String} CSS class string
     */
    getItemClass(index) {
        return index === (this.props.selectedIndex || 0)
            ? "ace-autocomplete-item ace-autocomplete-item-selected"
            : "ace-autocomplete-item";
    }
}

AutocompletePopup.template = "cetmix_tower_server.AutocompletePopup";
AutocompletePopup.props = {
    commands: {type: Array},
    onItemClick: {type: Function},
    position: {type: Object},
    selectedIndex: {type: Number, optional: true},
    onSelectedIndexChange: {type: Function, optional: true},
    type: {type: String, optional: true},
};

export {AutocompletePopup};
