"use strict";

const api = require("../api.js");
const events = require("../events.js");
const misc = require("../util/misc.js");
const keyboard = require('../util/keyboard.js');
const views = require("../util/views.js");
const Note = require("../models/note.js");
const Point = require("../models/point.js");
const TagInputControl = require("./tag_input_control.js");
const PoolInputControl = require("./pool_input_control.js");
const ExpanderControl = require("../controls/expander_control.js");
const FileDropperControl = require("../controls/file_dropper_control.js");
const PostMetricInputControl = require("./post_metric_input_control.js");

const template = views.getTemplate("post-edit-sidebar");

class PostEditSidebarControl extends events.EventTarget {
    constructor(hostNode, ctx, postContentControl, postNotesOverlayControl) {
        super();
        this._hostNode = hostNode;
        this._ctx = ctx;
        this._post = ctx.post;
        this._postContentControl = postContentControl;
        this._postNotesOverlayControl = postNotesOverlayControl;
        this._newPostContent = null;

        this._postNotesOverlayControl.switchToPassiveEdit();

        views.replaceContent(
            this._hostNode,
            template({
                post: this._post,
                enableSafety: api.safetyEnabled(),
                hasClipboard: document.queryCommandSupported("copy"),
                canEditPostSafety: api.hasPrivilege("posts:edit:safety"),
                canEditPostSource: api.hasPrivilege("posts:edit:source"),
                canEditPostTags: api.hasPrivilege("posts:edit:tags"),
                canEditPostMetrics: api.hasPrivilege("metrics:edit:posts"),
                canEditPostRelations: api.hasPrivilege("posts:edit:relations"),
                canEditPostNotes:
                    api.hasPrivilege("posts:edit:notes") &&
                    this._post.type !== "video" &&
                    this._post.type !== "flash",
                canEditPostFlags: api.hasPrivilege("posts:edit:flags"),
                canEditPostContent: api.hasPrivilege("posts:edit:content"),
                canEditPostThumbnail: api.hasPrivilege("posts:edit:thumbnail"),
                canEditPoolPosts: api.hasPrivilege("pools:edit:posts"),
                canCreateAnonymousPosts: api.hasPrivilege(
                    "posts:create:anonymous"
                ),
                canDeletePosts: api.hasPrivilege("posts:delete"),
                canFeaturePosts: api.hasPrivilege("posts:feature"),
                canMergePosts: api.hasPrivilege("posts:merge"),
            })
        );

        new ExpanderControl(
            "post-info",
            "Basic info",
            this._hostNode.querySelectorAll(
                ".safety, .relations, .flags, .post-source"
            )
        );
        this._tagsExpander = new ExpanderControl(
            "post-tags",
            `Tags (${this._post.tags.length})`,
            this._hostNode.querySelectorAll(".tags")
        );
        this._metricsExpander = new ExpanderControl(
            "post-metrics",
            `Metrics (${this._post.tags.filterMetrics().length})`,
            this._hostNode.querySelectorAll(".metrics")
        );
        this._notesExpander = new ExpanderControl(
            "post-notes",
            "Notes",
            this._hostNode.querySelectorAll(".notes")
        );
        this._poolsExpander = new ExpanderControl(
            "post-pools",
            `Pools (${this._post.pools.length})`,
            this._hostNode.querySelectorAll(".pools")
        );
        new ExpanderControl(
            "post-content",
            "Content",
            this._hostNode.querySelectorAll(".post-content, .post-thumbnail")
        );
        new ExpanderControl(
            "post-management",
            "Management",
            this._hostNode.querySelectorAll(".management")
        );

        this._syncExpanderTitles();

        if (this._formNode) {
            this._formNode.addEventListener("submit", (e) =>
                this._evtSubmit(e)
            );
        }

        if (this._tagInputNode) {
            this._tagControl = new TagInputControl(
                this._tagInputNode,
                this._post.tags,
                null,
                this._post,
            );
        }

        if (this._poolInputNode) {
            this._poolControl = new PoolInputControl(
                this._poolInputNode,
                this._post.pools
            );
        }

        if (this._metricInputNode) {
            this._metricControl = new PostMetricInputControl(
                this._metricInputNode,
                this._ctx
            );
        }

        if (this._contentInputNode) {
            this._contentFileDropper = new FileDropperControl(
                this._contentInputNode,
                {
                    allowUrls: true,
                    lock: true,
                    urlPlaceholder: "...or paste an URL here.",
                }
            );
            this._contentFileDropper.addEventListener("fileadd", (e) => {
                this._newPostContent = e.detail.files[0];
            });
            this._contentFileDropper.addEventListener("urladd", (e) => {
                this._newPostContent = e.detail.urls[0];
            });
        }

        if (this._thumbnailInputNode) {
            this._thumbnailFileDropper = new FileDropperControl(
                this._thumbnailInputNode,
                { lock: true }
            );
            this._thumbnailFileDropper.addEventListener("fileadd", (e) => {
                this._newPostThumbnail = e.detail.files[0];
                this._thumbnailRemovalLinkNode.style.display = "block";
            });
        }

        if (this._thumbnailRemovalLinkNode) {
            this._thumbnailRemovalLinkNode.addEventListener("click", (e) =>
                this._evtRemoveThumbnailClick(e)
            );
            this._thumbnailRemovalLinkNode.style.display = this._post
                .hasCustomThumbnail
                ? "block"
                : "none";
        }

        if (this._addNoteLinkNode) {
            this._addNoteLinkNode.addEventListener("click", (e) =>
                this._evtAddNoteClick(e)
            );
        }

        if (this._copyNotesLinkNode) {
            this._copyNotesLinkNode.addEventListener("click", (e) =>
                this._evtCopyNotesClick(e)
            );
        }

        if (this._pasteNotesLinkNode) {
            this._pasteNotesLinkNode.addEventListener("click", (e) =>
                this._evtPasteNotesClick(e)
            );
        }

        if (this._deleteNoteLinkNode) {
            this._deleteNoteLinkNode.addEventListener("click", (e) =>
                this._evtDeleteNoteClick(e)
            );
        }

        if (this._featureLinkNode) {
            this._featureLinkNode.addEventListener("click", (e) =>
                this._evtFeatureClick(e)
            );
        }

        if (this._mergeLinkNode) {
            this._mergeLinkNode.addEventListener("click", (e) =>
                this._evtMergeClick(e)
            );
        }

        if (this._deleteLinkNode) {
            this._deleteLinkNode.addEventListener("click", (e) =>
                this._evtDeleteClick(e)
            );
        }

        this._postNotesOverlayControl.addEventListener("blur", (e) =>
            this._evtNoteBlur(e)
        );

        this._postNotesOverlayControl.addEventListener("focus", (e) =>
            this._evtNoteFocus(e)
        );

        this._post.addEventListener("changeContent", (e) =>
            this._evtPostContentChange(e)
        );

        this._post.addEventListener("changeThumbnail", (e) =>
            this._evtPostThumbnailChange(e)
        );

        if (this._formNode) {
            const inputNodes = this._formNode.querySelectorAll(
                "input, textarea"
            );
            for (let node of inputNodes) {
                node.addEventListener("change", (e) =>
                    this.dispatchEvent(new CustomEvent("change"))
                );
            }
            this._postNotesOverlayControl.addEventListener("change", (e) =>
                this.dispatchEvent(new CustomEvent("change"))
            );
        }

        for (let eventType of ["add", "remove"]) {
            this._post.notes.addEventListener(eventType, (e) => {
                this._syncExpanderTitles();
            });
            this._post.pools.addEventListener(eventType, (e) => {
                this._syncExpanderTitles();
            });
        }

        if (this._tagControl) {
            this._tagControl.addEventListener("change", (e) => {
                this.dispatchEvent(new CustomEvent("change"));
                this._syncExpanderTitles();
                this._post.removeMetricsWithoutTag();
                if (this._metricControl) {
                    this._metricControl.refreshContent();
                }
            });
        }

        if (this._metricControl) {
            this._metricControl.addEventListener("change", (e) => {
                this.dispatchEvent(new CustomEvent("change"));
                this._syncExpanderTitles();
            });
        }

        if (this._noteTextareaNode) {
            this._noteTextareaNode.addEventListener("change", (e) =>
                this._evtNoteTextChangeRequest(e)
            );
        }

        if (this._poolControl) {
            this._poolControl.addEventListener("change", (e) => {
                this.dispatchEvent(new CustomEvent("change"));
                this._syncExpanderTitles();
            });
        }

        keyboard.bind(["command+s", "ctrl+s"], (e) => this._evtSubmit(e));
        if (this._tagInputNode) {
            const realTagInput = this._formNode.querySelector(".tag-input input");
            keyboard.bindElement(realTagInput, ["command+s", "ctrl+s"], (e) => this._evtSubmit(e));
            keyboard.bind('t', (e) => {
                e.preventDefault();
                realTagInput.focus();
            });
        }
    }

    _syncExpanderTitles() {
        this._notesExpander.title = `Notes (${this._post.notes.length})`;
        this._tagsExpander.title = `Tags (${this._post.tags.length})`;
        this._poolsExpander.title = `Pools (${this._post.pools.length})`;
        let metricCount = this._post.tags.filterMetrics().length;
        if (metricCount > 0) {
            this._metricsExpander.containerNode.style.display = "block";
            this._metricsExpander.title = `Metrics (${metricCount})`;
        } else {
            this._metricsExpander.containerNode.style.display = "none";
        }
    }

    _evtPostContentChange(e) {
        this._contentFileDropper.reset();
    }

    _evtPostThumbnailChange(e) {
        this._thumbnailFileDropper.reset();
    }

    _evtRemoveThumbnailClick(e) {
        e.preventDefault();
        this._thumbnailFileDropper.reset();
        this._newPostThumbnail = null;
        this._thumbnailRemovalLinkNode.style.display = "none";
    }

    _evtFeatureClick(e) {
        e.preventDefault();
        if (confirm("Are you sure you want to feature this post?")) {
            this.dispatchEvent(
                new CustomEvent("feature", {
                    detail: {
                        post: this._post,
                    },
                })
            );
        }
    }

    _evtMergeClick(e) {
        e.preventDefault();
        this.dispatchEvent(
            new CustomEvent("merge", {
                detail: {
                    post: this._post,
                },
            })
        );
    }

    _evtDeleteClick(e) {
        e.preventDefault();
        if (confirm("Are you sure you want to delete this post?")) {
            this.dispatchEvent(
                new CustomEvent("delete", {
                    detail: {
                        post: this._post,
                    },
                })
            );
        }
    }

    _evtNoteTextChangeRequest(e) {
        if (this._editedNote) {
            this._editedNote.text = this._noteTextareaNode.value;
        }
    }

    _evtNoteFocus(e) {
        this._editedNote = e.detail.note;
        this._addNoteLinkNode.classList.remove("inactive");
        this._deleteNoteLinkNode.classList.remove("inactive");
        this._noteTextareaNode.removeAttribute("disabled");
        this._noteTextareaNode.value = e.detail.note.text;
    }

    _evtNoteBlur(e) {
        this._evtNoteTextChangeRequest(null);
        this._addNoteLinkNode.classList.remove("inactive");
        this._deleteNoteLinkNode.classList.add("inactive");
        this._noteTextareaNode.blur();
        this._noteTextareaNode.setAttribute("disabled", "disabled");
        this._noteTextareaNode.value = "";
    }

    _evtAddNoteClick(e) {
        e.preventDefault();
        if (e.target.classList.contains("inactive")) {
            return;
        }
        this._addNoteLinkNode.classList.add("inactive");
        this._postNotesOverlayControl.switchToDrawing();
    }

    _evtCopyNotesClick(e) {
        e.preventDefault();
        let textarea = document.createElement("textarea");
        textarea.style.position = "fixed";
        textarea.style.opacity = "0";
        textarea.value = JSON.stringify(
            [...this._post.notes].map((note) => ({
                polygon: [...note.polygon].map((point) => [point.x, point.y]),
                text: note.text,
            }))
        );
        document.body.appendChild(textarea);
        textarea.select();

        let success = false;
        try {
            success = document.execCommand("copy");
        } catch (err) {
            // continue regardless of error
        }
        textarea.blur();
        document.body.removeChild(textarea);
        alert(
            success
                ? "Notes copied to clipboard."
                : "Failed to copy the text to clipboard. Sorry."
        );
    }

    _evtPasteNotesClick(e) {
        e.preventDefault();
        const text = window.prompt(
            "Please enter the exported notes snapshot:"
        );
        if (!text) {
            return;
        }
        const notesObj = JSON.parse(text);
        this._post.notes.clear();
        for (let noteObj of notesObj) {
            let note = new Note();
            for (let pointObj of noteObj.polygon) {
                note.polygon.add(new Point(pointObj[0], pointObj[1]));
            }
            note.text = noteObj.text;
            this._post.notes.add(note);
        }
    }

    _evtDeleteNoteClick(e) {
        e.preventDefault();
        if (e.target.classList.contains("inactive")) {
            return;
        }
        this._post.notes.remove(this._editedNote);
        this._postNotesOverlayControl.switchToPassiveEdit();
    }

    _evtSubmit(e) {
        e.preventDefault();
        this.dispatchEvent(
            new CustomEvent("submit", {
                detail: {
                    post: this._post,

                    safety: this._safetyButtonNodes.length
                        ? Array.from(this._safetyButtonNodes)
                              .filter((node) => node.checked)[0]
                              .value.toLowerCase()
                        : undefined,

                    flags: this._videoFlags,

                    tags: this._tagInputNode
                        ? misc.splitByWhitespace(this._tagInputNode.value)
                        : undefined,

                    pools: this._poolInputNode
                        ? misc.splitByWhitespace(this._poolInputNode.value)
                        : undefined,

                    relations: this._relationsInputNode
                        ? misc
                              .splitByWhitespace(
                                  this._relationsInputNode.value
                              )
                              .map((x) => parseInt(x))
                        : undefined,

                    content: this._newPostContent
                        ? this._newPostContent
                        : undefined,

                    thumbnail:
                        this._newPostThumbnail !== undefined
                            ? this._newPostThumbnail
                            : undefined,

                    source: this._sourceInputNode
                        ? this._sourceInputNode.value
                        : undefined,
                },
            })
        );
    }

    get _formNode() {
        return this._hostNode.querySelector("form");
    }

    get _submitButtonNode() {
        return this._hostNode.querySelector(".submit");
    }

    get _safetyButtonNodes() {
        return this._formNode.querySelectorAll(".safety input");
    }

    get _tagInputNode() {
        return this._formNode.querySelector(".tags input");
    }

    get _poolInputNode() {
        return this._formNode.querySelector(".pools input");
    }

    get _loopVideoInputNode() {
        return this._formNode.querySelector(".flags input[name=loop]");
    }

    get _soundVideoInputNode() {
        return this._formNode.querySelector(".flags input[name=sound]");
    }

    get _videoFlags() {
        if (!this._loopVideoInputNode) {
            return undefined;
        }
        let ret = [];
        if (this._loopVideoInputNode.checked) {
            ret.push("loop");
        }
        if (this._soundVideoInputNode.checked) {
            ret.push("sound");
        }
        return ret;
    }

    get _relationsInputNode() {
        return this._formNode.querySelector(".relations input");
    }

    get _contentInputNode() {
        return this._formNode.querySelector(
            ".post-content .dropper-container"
        );
    }

    get _thumbnailInputNode() {
        return this._formNode.querySelector(
            ".post-thumbnail .dropper-container"
        );
    }

    get _thumbnailRemovalLinkNode() {
        return this._formNode.querySelector(".post-thumbnail a");
    }

    get _sourceInputNode() {
        return this._formNode.querySelector(".post-source textarea");
    }

    get _featureLinkNode() {
        return this._formNode.querySelector(".management .feature");
    }

    get _mergeLinkNode() {
        return this._formNode.querySelector(".management .merge");
    }

    get _deleteLinkNode() {
        return this._formNode.querySelector(".management .delete");
    }

    get _addNoteLinkNode() {
        return this._formNode.querySelector(".notes .add");
    }

    get _copyNotesLinkNode() {
        return this._formNode.querySelector(".notes .copy");
    }

    get _pasteNotesLinkNode() {
        return this._formNode.querySelector(".notes .paste");
    }

    get _deleteNoteLinkNode() {
        return this._formNode.querySelector(".notes .delete");
    }

    get _noteTextareaNode() {
        return this._formNode.querySelector(".notes textarea");
    }

    get _metricInputNode() {
        return this._formNode.querySelector(".metrics input");
    }

    enableForm() {
        views.enableForm(this._formNode);
    }

    disableForm() {
        views.disableForm(this._formNode);
    }

    clearMessages() {
        views.clearMessages(this._hostNode);
    }

    showSuccess(message) {
        views.showSuccess(this._hostNode, message);
    }

    showError(message) {
        views.showError(this._hostNode, message);
    }
}

module.exports = PostEditSidebarControl;
