import State from "../domain/State";
import Comment from "../domain/Comment";
import Action from "../../background/domain/Action";

const COMMENT_SECTION = "commentSection";
const COMMENT_SECTION_HEANDER = "commentSectionHeader";
const COMMENT_SECTION_BODY = "commentSectionBody";

export default class CommentPopupView {

    position: {x: string, y: string};
    onCommentPopupMove: Function;
    onCommentUp: Function;
    header: HTMLElement;
    body: HTMLElement;
    section: HTMLElement;

    constructor(onCommentPopupMove, onCommentUp) {
        this.onCommentPopupMove = onCommentPopupMove;
        this.onCommentUp = onCommentUp
    } 

    init(position: {x: string, y: string}) {
        return new Promise((resolve) => {
            this.position = position;

            let oldCommentSection = document.getElementById(COMMENT_SECTION)
            if (oldCommentSection) {
                oldCommentSection.remove()
            }
            this.section = document.createElement("div");
            this.section.style.visibility = "hidden";
            this.section.setAttribute("id", COMMENT_SECTION);
            document.body.appendChild(this.section);

            this.header = document.createElement("div")
            this.header.setAttribute("id", COMMENT_SECTION_HEANDER);

            this.body = document.createElement("div")
            this.body.setAttribute("id", COMMENT_SECTION_BODY);
            this.header.addEventListener("dblclick", this.dropdownCommentSectionBody)

            this.section.appendChild(this.header)
            this.section.appendChild(this.body)
            this.dragPopup();
            resolve();
        })
    }

    refresh(state: State): Promise<void> {
        if (!state.displayComments) {
            return this.hide();
        } 
        return this.show(state).then(() => {
            if (state.isActive) {
                document.getElementById(COMMENT_SECTION).style.visibility = "visible";
            } else {
                this.hide();
            }
            let body = document.getElementById(COMMENT_SECTION_BODY)
            while (body.firstElementChild) {
                body.firstElementChild.remove();
            }
        
            this.setCommentSectionHeader(state.commentList)
            for (const comment of state.commentList) {
                this.addCommentInCommentSection(state.commentsUp, comment)
            }
        })
    }

    hide(): Promise<void> {
        const commentSection = document.getElementById(COMMENT_SECTION)
        commentSection.hidden = true;
        return Promise.resolve();
    }

    show(state: State): Promise<void> {
        const commentSection = document.getElementById(COMMENT_SECTION)
        commentSection.hidden = false;
        return Promise.resolve();
    }


    private setCommentSectionHeader(commentList: Comment[]) {
        let header = document.getElementById(COMMENT_SECTION_HEANDER)
        if (header.firstElementChild) {
            header.removeChild(header.firstElementChild)
        }
        let headerText = document.createElement("p")
        headerText.innerText = `Comments : ${commentList.length}`

        header.classList.remove(...header.classList);
        if (commentList.length > 0) {
            header.classList.add("commentSectionHeaderNotEmpty")
        } else {
            header.classList.add("commentSectionHeaderEmpty")
        }
        header.appendChild(headerText)
    }

    private addCommentInCommentSection(commentsUp: Comment[], comment: Comment) {
        let body = document.getElementById(COMMENT_SECTION_BODY)
        let commentInfo = document.createElement("div")
        body.appendChild(commentInfo)

        let commentConfirmButton = document.createElement("button")
        if (!commentsUp.some(commentUp => commentUp.note === comment.note)) {
            commentConfirmButton.classList.add("commentUpButton")
            commentConfirmButton.innerText = "up"
            commentConfirmButton.addEventListener("click", (e) => this.confirmCommentCallback(e, comment))
            commentInfo.appendChild(commentConfirmButton)
        }

        let commentKind = document.createElement("span")
        commentKind.classList.add("commentKind")
        commentKind.innerText = comment.type

        let commentMessage = document.createElement("span")
        commentMessage.classList.add("commentMessage")
        if (comment.note !== undefined) {
            commentMessage.innerText = comment.note
        }
        let commentContext = document.createElement("div")
        commentContext.classList.add("commentContext")
        for (const distribution of comment.distributionList) {
            let contextDetail = document.createElement("div")
            let contextDetailOccurence = document.createElement("span")
            contextDetailOccurence.classList.add("commentOccurence")
            if (distribution.noteOccurence === 0) {
                continue
            }
            contextDetailOccurence.innerText = `${distribution.noteOccurence} / ${distribution.occurence}̀`
            contextDetail.appendChild(contextDetailOccurence)
            distribution.actions.forEach((action: Action) => {
                const contextNode = document.createElement("span")
                contextNode.classList.add("commentActionContext")
                contextNode.innerText = action.toString();
                contextDetail.appendChild(contextNode)
            })
            commentContext.appendChild(contextDetail)
        }

        commentInfo.appendChild(commentKind)
        commentInfo.appendChild(commentMessage)
        commentInfo.appendChild(commentContext)

    }

    private dropdownCommentSectionBody(e: Event) {
        e.preventDefault()
        let sectionBody = document.getElementById(COMMENT_SECTION_BODY)
        if (sectionBody.style.display === "none") {
            sectionBody.style.display = "block"
        } else {
            sectionBody.style.display = "none"
        }
    }

    private confirmCommentCallback(e, comment: Comment) {
        e.preventDefault()
        if (!e.target.disabled) {
            this.onCommentUp(comment).then(() => {
                e.target.remove();
            })
        }
    }

    private dragPopup() {
        var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        this.section.style.top = this.position.y 
        this.section.style.left =  this.position.x

        const dragMouseDownCallback = dragMouseDown.bind(this);
        const elementDragCallback = elementDrag.bind(this);
        const closeDragElementCallback = closeDragElement.bind(this);

        this.header.addEventListener('mousedown', dragMouseDownCallback)

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            // get the mouse cursor position at startup:
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.addEventListener("mouseup", closeDragElementCallback)
            // call a function whenever the cursor moves:
            document.addEventListener("mousemove", elementDragCallback);
        }
    
        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            // calculate the new cursor position:
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            // set the element's new position:

            this.section.style.top = (this.section.offsetTop - pos2) + "px";
            this.section.style.left = (this.section.offsetLeft - pos1) + "px";
        }
    
        function closeDragElement() {
            // stop moving when mouse button is released:
            document.removeEventListener("mouseup", closeDragElementCallback);
            document.removeEventListener("mousemove", elementDragCallback);
            let x = this.section.style.left;
            let y = this.section.style.top;

            this.onCommentPopupMove({ x, y })
        }
    }
}