import View from "../../../src/view/View.js";
import Signal from "../../../src/core/events/signal/Signal.js";
import dom from "../../../src/view/DOM.js";
import ObservedBoolean from "../../../src/core/model/ObservedBoolean.js";
import LabelView from "../../../src/view/common/LabelView.js";
import ButtonView from "../../../src/view/elements/button/ButtonView.js";
import EmptyView from "../../../src/view/elements/EmptyView.js";

import {downloadAsFile} from "../../../src/core/binary/downloadAsFile.js";

export async function obtainClipBoard() {
    const navigator = globalThis.navigator;

    if (navigator.clipboard === undefined) {
        const queries = [{
            name: "clipboard-read"
        }, {
            name: "clipboard-write"
        }];

        const permission_queries = queries.map(q => navigator.permissions.query(q));

        const statuses = await Promise.all(permission_queries);

        for (let i = 0; i < statuses.length; i++) {
            const permissionStatus = statuses[i];

            if (permissionStatus.state !== "granted") {
                throw new Error(`Permission for query not granted (actual state = ${permissionStatus.state}). Query:${JSON.stringify(queries[i])}`)
            }
        }
    }

    return navigator.clipboard;
}

/**
 *
 * @param {string} text
 * @param {string} [data_name]
 * @returns {Promise<void>}
 */
export async function safeClipboardWriteText(text, data_name = "data") {

    return obtainClipBoard().then(
        () => {
            const navigator = globalThis.navigator;
            return navigator.clipboard.writeText(text);
        },
        () => {
            // no clipboard available
            console.log(`No clipboard available, downloading instead`);
            downloadAsFile(text, `${data_name}.json`);
        }
    );
}

export async function safeClipboardReadText() {

    return obtainClipBoard().then(() => {

        const navigator = globalThis.navigator;
        return navigator.clipboard.readText();
    }, () => {
        // clipboard not available
        console.log(`No clipboard available, using a prompt instead`);

        function clickElem(elem) {
            // Thx user1601638 on Stack Overflow (6/6/2018 - https://stackoverflow.com/questions/13405129/javascript-create-and-save-file )
            var eventMouse = document.createEvent("MouseEvents")
            eventMouse.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
            elem.dispatchEvent(eventMouse)
        }

        function openFile(func) {
            const fileInput = document.createElement("input");

            const readFile = function (e) {
                var file = e.target.files[0];
                if (!file) {
                    return;
                }
                var reader = new FileReader();
                reader.onload = function (e) {
                    var contents = e.target.result;
                    fileInput.func(contents)
                    document.body.removeChild(fileInput)
                }
                reader.readAsText(file)
            }
            fileInput.type = 'file'
            fileInput.style.display = 'none'
            fileInput.onchange = readFile
            fileInput.func = func
            document.body.appendChild(fileInput)
            clickElem(fileInput)
        }

        return new Promise((resolve, reject) => {
            openFile(resolve);
        });


    });

}

/**
 * @template T
 */
export class ComponentControlView extends View {
    /**
     * @template T
     * @param {number} entity
     * @param {T} component
     * @param {EntityManager} entityManager
     * @param {View} vController
     * @param engine
     * @constructor
     */
    constructor(entity, component, entityManager, vController, engine) {
        super();

        this.signal = {
            remove: new Signal()
        };

        const dRoot = dom('div');

        dRoot.addClass('entity-editor-component-control-view');

        this.el = dRoot.el;

        const folded = this.folded = new ObservedBoolean(false);

        const componentType = component.constructor;
        const typeName = componentType.typeName;

        const vComponentName = new LabelView(typeName);

        const bFold = new ButtonView({
            classList: ['fold-toggle'],
            action() {
                folded.invert();
            }
        });

        const bRemove = new ButtonView({
            classList: ['remove'],
            action() {
                self.signal.remove.dispatch();
            }
        });

        const bCopy = new ButtonView({
            classList: ['copy'],
            async action() {
                const json = component.toJSON();

                const data = JSON.stringify({
                    type: typeName,
                    data: json
                }, 3, 3);

                safeClipboardWriteText(data, typeName).then(() => {
                    console.log(`${entity}:${typeName} dumped`);
                });
            }
        });

        bCopy.setClass('disabled', component.hasOwnProperty('toJSON') && typeof component.toJSON !== "function");

        const bPaste = new ButtonView({
            classList: ['paste'],
            async action() {

                safeClipboardReadText().then(text => {
                    const json = JSON.parse(text);

                    if (json.type !== typeName) {
                        throw new Error(`Component type(=${json.type}) in clipboard does not match current component type(=${typeName})`);
                    }

                    //get system
                    component.fromJSON(json.data, engine);

                    console.log(`${entity}:${typeName} pasted from clip`);
                });

            }
        });

        bPaste.setClass('disabled', component.hasOwnProperty('fromJSON') && typeof component.fromJSON !== "function");

        const vTitleBar = new EmptyView();
        dom(vTitleBar.el).addClass('title-bar');

        vTitleBar.addChild(vComponentName);
        vTitleBar.addChild(bCopy);
        vTitleBar.addChild(bPaste);
        vTitleBar.addChild(bFold);
        vTitleBar.addChild(bRemove);

        this.addChild(vTitleBar);

        const self = this;

        folded.process(function (v) {

            dRoot.setClass('folded', v);

            if (v) {
                self.removeChild(vController);
            } else {
                self.addChild(vController);
            }
        });
    }
}
