import { querySelectorAllDeep } from 'query-selector-shadow-dom';
import Action from "../domain/Action";

const PROBABILITY_POPUP = "AIFEX_probabilityPopup";
const MAX_DISPLAYED_LINES = 9;

export default class ActionsPopupView {
    hoveredElement: HTMLElement;

    private checkHoverElementsExistsInterval: NodeJS.Timeout
    private probabilityPopup: HTMLElement;

    constructor() {
        this.hoveredElement = null;
    }

    show(elementActionListMap: Map<Element, Action[]>): void {
        if (!this.probabilityPopup) {
            this.probabilityPopup = document.createElement("div");
            this.probabilityPopup.setAttribute("id", PROBABILITY_POPUP);
            document.body.appendChild(this.probabilityPopup);
            this.probabilityPopup.style.position = "absolute";
        }
        if (this.hoveredElement) {
            if (elementActionListMap.has(this.hoveredElement)) {
                this.updatePopupContent(elementActionListMap.get(this.hoveredElement));
            }
        }
        this.attachMouseMoveHandler();
        this.attachMouseEnterHandlers(elementActionListMap);
        if(!this.checkHoverElementsExistsInterval) {
            this.checkHoverElementsExistsInterval = setInterval(this.checkHoveredElementExists.bind(this), 1000)
        }
    }

    hide() {
        clearInterval(this.checkHoverElementsExistsInterval);
        this.hidePopup()
    }

    private updatePopupContent(actionList: Action[]) {
        while(this.probabilityPopup.hasChildNodes()) {
            this.probabilityPopup.firstChild.remove();
        }
        if (actionList.length === 0) {
            return;
        }
        for (const action of actionList.slice(0, MAX_DISPLAYED_LINES)) {
            const probability = (action.probability * 100).toFixed(2);
    
            const P_element = document.createElement("p");
            P_element.classList.add("popupItem")
            const actionSpan = document.createElement("span");
            actionSpan.classList.add("popupAction");
            actionSpan.textContent = `${action.toString()}: `;
    
            const probabilitySpan = document.createElement("span");
            probabilitySpan.classList.add("popupProbability");
            probabilitySpan.textContent = `${probability}%`;
    
            P_element.appendChild(actionSpan);
            P_element.appendChild(probabilitySpan);

            this.probabilityPopup.appendChild(P_element)
        }
    }

    private attachMouseEnterHandlers(elementActionListMap: Map<Element, Action[]>) {
        for (const element of elementActionListMap.keys()) {

            let showHandler = (event) => { 
                this.hoveredElement = event.target;
                if (elementActionListMap.has(this.hoveredElement)) {
                    this.probabilityPopup.style.visibility = "visible";
                    this.updatePopupContent(elementActionListMap.get(this.hoveredElement));
                }
            };

            let hideHandler = () => { 
                this.hoveredElement = null; 
                this.probabilityPopup.style.visibility = "hidden";
            }

            element.removeEventListener("mouseenter", showHandler);
            element.removeEventListener("mouseleave" , hideHandler);

            element.addEventListener("mouseenter", showHandler);
            element.addEventListener("mouseleave" , hideHandler);
        }

    }

    private attachMouseMoveHandler() {

        document.body.addEventListener('mousemove', (e) => {
            let x = e.pageX;
            let bounding = document.body.getBoundingClientRect();
            if (e.pageX + this.probabilityPopup.offsetWidth > bounding.right) {
                x = bounding.right - this.probabilityPopup.offsetWidth;
            }
            this.probabilityPopup.style.left = x + 'px';
            this.probabilityPopup.style.top = e.pageY + 'px';
        });
    }

    private hidePopup() {
        const probabilityPopup = document.getElementById(PROBABILITY_POPUP);
        if (probabilityPopup) {
            probabilityPopup.style.visibility = "hidden";
        }
    }

    private checkHoveredElementExists() {
        if (this.hoveredElement) {
            const hoveredElements = querySelectorAllDeep(':hover');
            for (const hovered of hoveredElements) {
                if (hovered === this.hoveredElement) {
                    return;
                }
            }
        } 
        this.hoveredElement = null; 
        this.probabilityPopup.style.visibility = "hidden";
    }

}