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

const PROBABILITY_POPUP = "probabilityPopup";

export default class ActionsPopupView {

    hoveredElement: HTMLElement;
    elementToMouseHandlerMap: Map<Node, { show: EventListener, hide: EventListener }>;
    onMouseHoverAction: Function;
    
    constructor(onMouseHoverAction) {
        this.hoveredElement = null;
        this.elementToMouseHandlerMap = new Map();
        this.onMouseHoverAction = onMouseHoverAction
    }

    init(): Promise<void> {
        return new Promise(resolve => {
            const probabilityPopup = document.createElement("div");
            probabilityPopup.setAttribute("id", PROBABILITY_POPUP);
            document.body.appendChild(probabilityPopup);
            probabilityPopup.style.position = "absolute";
    
            document.body.addEventListener('mousemove', (e) => {
                let x = e.pageX;
                let bounding = document.body.getBoundingClientRect();
                if (e.pageX + probabilityPopup.offsetWidth > bounding.right) {
                    x = bounding.right - probabilityPopup.offsetWidth;
                }
                probabilityPopup.style.left = x + 'px';
                probabilityPopup.style.top = e.pageY + 'px';
            });
    
            setInterval( function() {
                if (this.hoveredElement) {
                    const hoveredElements = querySelectorAllDeep(':hover');
                    let found = false;
                    for (const hovered of hoveredElements) {
                        if (hovered === this.hoveredElement) {
                            found = true;
                            break
                        }
                    }
                    if (!found) {
                        return this.hide()
                    }
                }
            }, 1000)
            resolve();

        }).then(() => this.hide());
    }

    clear(): Promise<void> {
        return new Promise((resolve) => {
            for (const element of this.elementToMouseHandlerMap.keys()) {
                const {show, hide} = this.elementToMouseHandlerMap.get(element);
                if (element) {
                    element.removeEventListener("mouseenter", show);
                    element.removeEventListener("mouseleave", hide);
                }
                this.elementToMouseHandlerMap.delete(element);
            }
            resolve();
        })
    }

    hide(): Promise<void> {
        const probabilityPopup = document.getElementById(PROBABILITY_POPUP);
        probabilityPopup.style.visibility = "hidden";
        return Promise.resolve();
    }

    show(): Promise<void> {
        const probabilityPopup = document.getElementById(PROBABILITY_POPUP);
        probabilityPopup.style.visibility = "visible";
        return Promise.resolve();
    }

    refresh(state: State): Promise<void> {
        return this.attach(state).then(() => {
            const probabilityPopup = document.getElementById(PROBABILITY_POPUP);

            //clean the popup
            while (probabilityPopup.firstChild) {
                probabilityPopup.removeChild(probabilityPopup.firstChild);
            }
            const P_elements = [];
            const actionList = state.elementActionListMap.get(this.hoveredElement);
            if (!actionList) {
                return Promise.resolve();
            }
            for (const action of Array.from(actionList).slice(0,9)) {
                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);
        
                P_elements.push(P_element);
            }
        
            if (P_elements.length > 0) {
                P_elements.forEach(p => probabilityPopup.appendChild(p));
            }
        })  
    }

    attach(state: State): Promise<void> {
        return this.clear().then(() => {
            for (const element of state.elementActionListMap.keys()) {            
                if (this.elementToMouseHandlerMap.has(element)) {
                    const {show, hide} = this.elementToMouseHandlerMap.get(element);
                    element.removeEventListener("mouseenter", show);
                    element.removeEventListener("mouseleave", hide);
                }
                let show = (event) => { 
                    this.hoveredElement = event.target; 
                    this.onMouseHoverAction();
                };
    
                let hide = () => { 
                    this.hoveredElement = null; 
                    this.hide();
                }
                this.elementToMouseHandlerMap.set(element, {
                    show,
                    hide
                });
                element.addEventListener("mouseenter", show);
                element.addEventListener("mouseleave" , hide);
            }
        })
    }

}