import {i18n} from './i18n';
import {css, html} from 'lit-element';
import {ScopedElementsMixin} from '@open-wc/scoped-elements';
import * as commonUtils from '@dbp-toolkit/common/utils';
import * as commonStyles from '@dbp-toolkit/common/styles';
import * as fileHandlingStyles from '@dbp-toolkit/file-handling/src/styles';
import {Icon} from '@dbp-toolkit/common';
import Tabulator from "tabulator-tables";
import {humanFileSize} from "@dbp-toolkit/common/i18next";
import {FileSink} from "@dbp-toolkit/file-handling/src/file-sink";
import {FileSource} from "@dbp-toolkit/file-handling/src/file-source";
import {name as pkgName} from "@dbp-toolkit/file-handling/package.json";
import {send} from "@dbp-toolkit/common/notification";
import {AdapterLitElement} from "@dbp-toolkit/provider/src/adapter-lit-element";


export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
    constructor() {
        super();
        this.lang = 'de';
        this.allowedMimeTypes = '*/*';
        this.clipboardFiles = {files: ''};
        this.clipboardSelectBtnDisabled = true;
        this.tabulatorTable = null;
        this._onReceiveBeforeUnload = this.onReceiveBeforeUnload.bind(this);
        this.filesToSave = [];
        this.numberOfSelectedFiles = 0;
        this.showAdditionalButtons = false;
        this.enabledTargets = 'local';

        this.nextcloudWebAppPasswordURL = "";
        this.nextcloudWebDavURL = "";
        this.nextcloudName = "";
        this.nextcloudFileURL = "";

        this.isFileSource = false;
        this.isFileSink = false;
    }

    static get scopedElements() {
        return {
            'dbp-icon': Icon,
            'dbp-file-sink': FileSink,
            'dbp-file-source': FileSource,
        };
    }

    static get properties() {
        return {
            ...super.properties,
            lang: { type: String },
            allowedMimeTypes: { type: String, attribute: 'allowed-mime-types' },
            clipboardSelectBtnDisabled: { type: Boolean, attribute: true },
            clipboardFiles: {type: Object, attribute: 'clipboard-files'},
            filesToSave: {type: Array, attribute: 'files-to-save'},
            numberOfSelectedFiles: {type: Number, attribute: false },
            showAdditionalButtons: {type: Boolean, attribute: 'show-additional-buttons' },
            enabledTargets: {type: String, attribute: 'enabled-targets'},

            nextcloudWebAppPasswordURL: { type: String, attribute: 'nextcloud-auth-url' },
            nextcloudWebDavURL: { type: String, attribute: 'nextcloud-web-dav-url' },
            nextcloudName: { type: String, attribute: 'nextcloud-name' },
            nextcloudFileURL: { type: String, attribute: 'nextcloud-file-url' },

            isFileSource: {type: Boolean, attribute: 'file-sink' },
            isFileSink: {type: Boolean, attribute: 'file-source' },
        };
    }

    _(selector) {
        return this.shadowRoot === null ? this.querySelector(selector) : this.shadowRoot.querySelector(selector);
    }

    update(changedProperties) {
        changedProperties.forEach((oldValue, propName) => {
            switch (propName) {
                case "lang":
                    i18n.changeLanguage(this.lang);
                    break;
                case "clipboardFiles":
                    this.generateClipboardTable();
                    break;
            }
        });

        super.update(changedProperties);
    }

    connectedCallback() {
        super.connectedCallback();
        const that = this;
        this.updateComplete.then(() => {

            // see: http://tabulator.info/docs/4.7
            this.tabulatorTable = new Tabulator(this._("#clipboard-content-table"), {
                layout: "fitColumns",
                selectable: true,
                selectableRangeMode: "drag",
                responsiveLayout: true,
                resizableColumns: false,
                placeholder: i18n.t("clipboard.no-data"),
                columns: [
                    {
                        title: "",
                        field: "type",
                        align: "center",
                        headerSort: false,
                        width: 50,
                        responsive: 1,
                        formatter: (cell, formatterParams, onRendered) => {
                            const icon_tag = that.getScopedTagName("dbp-icon");
                            let icon = `<${icon_tag} name="empty-file" class="nextcloud-picker-icon"></${icon_tag}>`;
                            return icon;
                        }
                    },
                    {
                        title: i18n.t("clipboard.file-name"),
                        responsive: 0,
                        widthGrow: 5,
                        minWidth: 150,
                        field: "name",
                        sorter: "alphanum",
                        formatter: (cell) => {
                            let data = cell.getRow().getData();
                            if (data.edit) {
                                cell.getElement().classList.add("fokus-edit");
                            }
                            return cell.getValue();
                        }
                    },
                    {
                        title: i18n.t("clipboard.file-size"),
                        responsive: 4,
                        widthGrow: 1,
                        minWidth: 50,
                        field: "size",
                        formatter: (cell, formatterParams, onRendered) => {
                            return cell.getRow().getData().type === "directory" ? "" : humanFileSize(cell.getValue());
                        }
                    },
                    {
                        title: i18n.t("clipboard.file-type"),
                        responsive: 2,
                        widthGrow: 1,
                        minWidth: 20,
                        field: "type",
                        formatter: (cell, formatterParams, onRendered) => {
                            if (typeof cell.getValue() === 'undefined') {
                                return "";
                            }
                            const [, fileSubType] = cell.getValue().split('/');
                            return fileSubType;
                        }
                    },
                    {
                        title: i18n.t("clipboard.file-mod"),
                        responsive: 3,
                        widthGrow: 1,
                        minWidth: 150,
                        field: "lastModified",
                        sorter: (a, b, aRow, bRow, column, dir, sorterParams) => {
                            const a_timestamp = Date.parse(a);
                            const b_timestamp = Date.parse(b);
                            return a_timestamp - b_timestamp;
                        },
                        formatter: function (cell, formatterParams, onRendered) {
                            const timestamp = new Date(cell.getValue());
                            const year = timestamp.getFullYear();
                            const month = ("0" + (timestamp.getMonth() + 1)).slice(-2);
                            const date = ("0" + timestamp.getDate()).slice(-2);
                            const hours = ("0" + timestamp.getHours()).slice(-2);
                            const minutes = ("0" + timestamp.getMinutes()).slice(-2);
                            return date + "." + month + "." + year + " " + hours + ":" + minutes;
                        }
                    },
                    {title: "file", field: "file", visible: false}
                ],
                initialSort: [
                    {column: "name", dir: "asc"},
                    {column: "type", dir: "asc"},
                ],
                rowClick: (e, row) => {
                    this.numberOfSelectedFiles = this.tabulatorTable !== null ? this.tabulatorTable.getSelectedRows().length : 0;
                    if (this.tabulatorTable !== null
                        && this.tabulatorTable.getSelectedRows().length === this.tabulatorTable.getRows().filter(row => this.checkFileType(row.getData())).length) {
                        this._("#select_all").checked = true;

                    } else {
                        this._("#select_all").checked = false;

                    }
                },
                rowSelectionChanged: (data, rows) => {
                    if (this.tabulatorTable && this.tabulatorTable.getSelectedRows().length > 0) {
                        this.clipboardSelectBtnDisabled = false;
                    } else {
                        this.clipboardSelectBtnDisabled = true;
                    }
                }
            });
            that.generateClipboardTable();

        });
        if(!window.clipboardWarning)  {
            window.addEventListener('beforeunload', this._onReceiveBeforeUnload, false);
            window.clipboardWarning = true;
        }

    }

    disconnectedCallback() {

        //We doesn't want to deregister this event, because we want to use this event over activities
        //window.removeEventListener('beforeunload', this._onReceiveBeforeUnload);

        super.disconnectedCallback();
    }

    /**
     * Select or deselect all files from tabulator table
     *
     */
    selectAllFiles() {
        let maxSelected = this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length;
        let selected = this.tabulatorTable.getSelectedRows().length;

        if (selected === maxSelected) {
            this.tabulatorTable.getSelectedRows().forEach(row => row.deselect());
            this.numberOfSelectedFiles = 0;
        } else {
            this.tabulatorTable.selectRow(this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)));
            this.numberOfSelectedFiles = maxSelected;
        }
    }


    checkFileType(file) {
        // check if file is allowed
        const [fileMainType, fileSubType] = file.type.split('/');
        const mimeTypes = this.allowedMimeTypes.split(',');
        let deny = true;

        mimeTypes.forEach((str) => {
            const [mainType, subType] = str.split('/');
            deny = deny && ((mainType !== '*' && mainType !== fileMainType) || (subType !== '*' && subType !== fileSubType));
        });

        if (deny) {
            console.log(`mime type ${file.type} of file '${file.name}' is not compatible with ${this.allowedMimeTypes}`);
            return false;
        }
        return true;
    }

    generateClipboardTable() {
        if (this.clipboardFiles.files) {
            let data = [];
            for (let i = 0; i < this.clipboardFiles.files.length; i++){
                data[i] = {
                    name: this.clipboardFiles.files[i].name,
                    size: this.clipboardFiles.files[i].size,
                    type: this.clipboardFiles.files[i].type,
                    lastModified: this.clipboardFiles.files[i].lastModified,
                    file: this.clipboardFiles.files[i]
                };
            }

            if (this.tabulatorTable !== null){
                this.tabulatorTable.clearData();
                this.tabulatorTable.setData(data);
            }
        }
    }

    async sendClipboardFiles(files) {

        for(let i = 0; i < files.length; i ++)
        {
            await this.sendFileEvent(files[i].file);
        }
        this.tabulatorTable.deselectRow();

    }

    async sendFileEvent(file) {
        const data = {"file": file, "data": file};

        const event = new CustomEvent("dbp-clipboard-file-picker-file-downloaded",
            { "detail": data, bubbles: true, composed: true });
        this.dispatchEvent(event);
    }


    /**
     * Decides if the "beforeunload" event needs to be canceled
     *
     * @param event
     */
    onReceiveBeforeUnload(event){
        // we don't need to stop if there are no signed files
        if (this.clipboardFiles.files.length === 0) {
            return;
        }

        // we need to handle custom events ourselves
        if(event.target && event.target.activeElement && event.target.activeElement.nodeName) {

            send({
                "summary": i18n.t('clipboard.file-warning'),
                "body": i18n.t('clipboard.file-warning-body', {count: this.clipboardFiles.files.length}),
                "type": "warning",
                "timeout": 5,
            });
            if (!event.isTrusted) {
                // note that this only works with custom event since calls of "confirm" are ignored
                // in the non-custom event, see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
                const result = confirm("##carefulsaveialuge");
                // don't stop the page leave if the user wants to leave
                if (result) {
                    return;
                }
            }
            // Cancel the event as stated by the standard
            event.preventDefault();
            // Chrome requires returnValue to be set
            event.returnValue = '';
        }
    }

    saveFilesToClipboard(ev)
    {
        //save it
        let data = {};
        let files = [];
        if (this.clipboardFiles && this.clipboardFiles.files.length !== 0) {
            files = files.concat(this.clipboardFiles.files);
            files = files.concat(ev.detail.file);
        } else {
            files = files.concat(ev.detail.file);
        }
        this.filesToSave = files;
        if (files && files.length !== 0) {
            data = {"files": files};
            this.sendSetPropertyEvent('clipboard-files', data);
            const event = new CustomEvent("dbp-clipboard-file-picker-file-uploaded",
                {  bubbles: true, composed: true });
            this.dispatchEvent(event);
        }
    }

    finishedSaveFilesToClipboard(ev) {
        send({
            "summary": i18n.t('clipboard.saved-files-title', {count: ev.detail.count}),
            "body": i18n.t('clipboard.saved-files-body', {count: ev.detail.count}),
            "type": "success",
            "timeout": 5,
        });
    }

    saveFilesFromClipboard() {
        const fileSink = this._("#file-sink-clipboard");
        if ( fileSink ) {
            this._("#file-sink-clipboard").files = Object.create(this.tabulatorTable.getSelectedData().length > 0 ? this.tabulatorTable.getSelectedData() : this.clipboardFiles.files);
            this._("#file-sink-clipboard").openDialog();
        }
    }

    getClipboardFileList() {
        let files = [];
        for (let i = 0; i < this.clipboardFiles.files.length; i ++)
        {
            files[i] =  html`<div class="clipboard-list"><strong>${this.clipboardFiles.files[i].name}</strong> ${humanFileSize(this.clipboardFiles.files[i].size)}</div>`;
        }
        return files;
    }

    /**
     * Open Filesink for multiple files
     */
    async openClipboardFileSink() {
        const fileSink = this._("#file-sink-clipboard");
        if (fileSink) {
            this._("#file-sink-clipboard").files = Object.create(this.clipboardFiles.files);
            this._("#file-sink-clipboard").openDialog();
        }
    }

    clearClipboard() {
        if(this.tabulatorTable && this.tabulatorTable.getSelectedData().length > 0) {
            let data = {"files": this.clipboardFiles.files};
            this.tabulatorTable.getSelectedData().forEach(toRemove =>
                data.files = data.files.filter(file => toRemove.name !== file.name)
            );
            this.sendSetPropertyEvent('clipboard-files', data);
            const event = new CustomEvent("dbp-clipboard-file-picker-file-uploaded",
                {  bubbles: true, composed: true });
            this.dispatchEvent(event);
            send({
                "summary": i18n.t('clipboard.clear-count-clipboard-title', {count: this.tabulatorTable.getSelectedData().length}),
                "body": i18n.t('clipboard.clear-count-clipboard-body', {count: this.tabulatorTable.getSelectedData().length}),
                "type": "success",
                "timeout": 5,
            });
            this.numberOfSelectedFiles = 0;

        } else {
            let data = {"files": []};
            this.sendSetPropertyEvent('clipboard-files', data);
            const event = new CustomEvent("dbp-clipboard-file-picker-file-uploaded",
                {  bubbles: true, composed: true });
            this.dispatchEvent(event);
            send({
                "summary": i18n.t('clipboard.clear-clipboard-title'),
                "body": i18n.t('clipboard.clear-clipboard-body'),
                "type": "success",
                "timeout": 5,
            });
        }
    }

    openFilesink() {
        const fileSink = this._("#file-source");
        if (fileSink) {
            this._("#file-source").setAttribute("dialog-open", "");
        }
    }

    getAdditionalButtons() {

        return html`
            <div class="flex-container">
                       
                        <div class="btn-flex-container-mobile">
                            <button @click="${() => { this.openFilesink(); }}"
                                    class="button" title="${i18n.t('clipboard.add-files')}">
                                <dbp-icon class="nav-icon" name="clipboard"></dbp-icon> ${i18n.t('clipboard.add-files-btn')}
                            </button>
                            <button @click="${() => { this.clearClipboard(); }}"
                                    class="button" title="${(this.numberOfSelectedFiles > 0) ? i18n.t('clipboard.remove-count', {count: this.numberOfSelectedFiles}) : i18n.t('clipboard.remove-all')}"
                                    ?disabled="${this.clipboardFiles.files.length === 0}">
                                ${(this.numberOfSelectedFiles > 0) ? i18n.t('clipboard.remove-count-btn', {count: this.numberOfSelectedFiles}) : i18n.t('clipboard.remove-all-btn')}
                            </button>
                        </div>
                        <div class="btn-flex-container-mobile">
                            <button @click="${() => { this.saveFilesFromClipboard(); }}"
                                    ?disabled="${this.clipboardFiles.files.length === 0}"
                                    class="button" title="${(this.numberOfSelectedFiles > 0) ? i18n.t('clipboard.save-count', {count: this.numberOfSelectedFiles}) : i18n.t('clipboard.save-all')}">
                                ${(this.numberOfSelectedFiles > 0) ? i18n.t('clipboard.save-count-btn', {count: this.numberOfSelectedFiles}) : i18n.t('clipboard.save-all-btn')}
                            </button>
                        </div>
                        
                    </div>
                    <dbp-file-source
                                id="file-source"
                                context="${i18n.t('clipboard.add-files')}"
                                allowed-mime-types="${this.allowedMimeTypes}"
                                nextcloud-auth-url="${this.nextcloudWebAppPasswordURL}"
                                nextcloud-web-dav-url="${this.nextcloudWebDavURL}"
                                nextcloud-name="${this.nextcloudName}"
                                nextcloud-file-url="${this.nextcloudFileURL}"
                                enabled-targets="${this.enabledTargets}"
                                decompress-zip
                                lang="${this.lang}"
                                text="${i18n.t('clipboard.upload-area-text')}"
                                button-label="${i18n.t('clipboard.upload-button-label')}"
                                show-clipboard
                                @dbp-file-source-file-selected="${this.saveFilesToClipboard}"
                                @dbp-nextcloud-file-picker-number-files="${this.finishedSaveFilesToClipboard}"
                                @dbp-file-source-file-upload-finished="${this.finishedSaveFilesToClipboard}"
                        ></dbp-file-source>
                    <dbp-file-sink id="file-sink-clipboard"
                                   context="${(this.numberOfSelectedFiles > 0) ? i18n.t('clipboard.save-count', {count: this.numberOfSelectedFiles}) : i18n.t('clipboard.save-all')}"
                                   filename="clipboard-documents.zip"
                                   allowed-mime-types="${this.allowedMimeTypes}"
                                   enabled-targets="${this.enabledTargets}"
                                   show-clipboard
                                   nextcloud-auth-url="${this.nextcloudWebAppPasswordURL}"
                                   nextcloud-web-dav-url="${this.nextcloudWebDavURL}"
                                   nextcloud-name="${this.nextcloudName}"
                                   nextcloud-file-url="${this.nextcloudFileURL}"
                                   lang="${this.lang}"
                                   subscribe="nextcloud-file-url:nextcloud-file-url"
                    ></dbp-file-sink>
        `;
    }

    getClipboardSink() {
        return html`
            //todo header + table
            <!-- Clipboard Footer -->
            <div class="clipboard-footer">
                <button class="button select-button is-primary" ?disabled="${this.clipboardSelectBtnDisabled}"
                        @click="${() => {this.sendClipboardFiles(this.tabulatorTable.getSelectedData());}}">${i18n.t('nextcloud-file-picker.select-files')}
                </button>
            </div>
        `;
    }

    getClipboardSource() {
        return html`
            //todo header + table
            <!-- Clipboard Footer -->
            <div class="clipboard-footer">
                <button class="button select-button is-primary" ?disabled="${this.clipboardSelectBtnDisabled}"
                        @click="${() => {this.sendClipboardFiles(this.tabulatorTable.getSelectedData());}}">${i18n.t('nextcloud-file-picker.select-files')}
                </button>
            </div>
        `;
    }

    static get styles() {
        // language=css
        return css`
            ${commonStyles.getThemeCSS()}
            ${commonStyles.getGeneralCSS(false)}
            ${commonStyles.getButtonCSS()}
            ${commonStyles.getTextUtilities()}
            ${commonStyles.getModalDialogCSS()}
            ${commonStyles.getRadioAndCheckboxCss()}
            ${fileHandlingStyles.getFileHandlingCss()}

            a {
                border-bottom: 1px solid rgba(0,0,0,0.3);
                padding: 0;
            }

            a:hover {
                color: #fff;
                background-color: #000;
            }

            h2:first-child {
                margin-top: 0;
                margin-bottom: 0px;
            }

            .subheadline{
                font-style: italic;
                padding-left: 2em;
                margin-top: -1px;
                /*line-height: 1.8;*/
                margin-bottom: 1.2em;
            }
            
            .warning-container{
                display: flex;
                flex-direction: inherit;
                align-items: center;
                margin-bottom: 1.5rem;
            }
            
            .warning-icon{
                margin-right: 20px;
                font-size: 1.5rem;
            }
            
            .container{
                margin-top: 2rem;
            }
            
            .flex-container{
                margin-bottom: 5px;
            }
            
            .select-btn-wrapper{
                float: right;
            }
            
            .init{
                margin: 0px;
            }
            
            .flex-container{
                display: flex;
                justify-content: space-between;
            }

            .tabulator .tabulator-tableHolder .tabulator-placeholder span{
                margin: initial;
            }
            
            .checkmark{
                height: 20px;
                width:20px;
            }
            
            .button-container .checkmark::after{
                left: 8px;
                top: 3px;
                width: 4px;
                height: 11px;
            }
            
            .table-wrapper{
                position: relative;
            }
            
            .select-all-icon{
                position: absolute;
                top: 17px;
                left: 10px;
                z-index: 100;
                height: 40px;
            }

            .clipboard-footer {
                align-self: end;
            }

            @media only screen
            and (orientation: portrait)
            and (max-device-width: 765px) {
                .flex-container{
                    justify-content: space-between;
                    display: flex;
                }
                
                .btn-flex-container-mobile{
                    width: 100%;
                    display: flex;
                    justify-content: space-between;
                    margin-bottom: 5px;
                }
                
                .select-btn-wrapper{
                    width: 100%;
                    display: flex;
                    justify-content: end;
                    float: none;
                }
                
                .flex-container{
                    display: block;
                }

                .checkmark{
                    height: 30px;
                    width:30px;
                }

                .button-container .checkmark::after{
                    left: 11px;
                    top: 4px;
                    width: 8px;
                    height: 15px;
                }
                

                .select-all-icon{
                    top: 10px;
                    left: 10px;
                }
                
                .btn-flex-container-mobile{
                    flex-direction: column;
                }
                
                .btn-flex-container-mobile button:nth-child(2){
                    margin-top: 5px;
                }

                .clipboard-footer {
                    padding-top: 10px;
                    align-self: center;
                }
            }

        `;
    }

    render() {
        const tabulatorCss = commonUtils.getAssetURL(pkgName, 'tabulator-tables/css/tabulator.min.css');

        let additionalButtons = this.showAdditionalButtons ? this.getAdditionalButtons() : "";

        if (this.isFileSink)
            return this.getClipboardSink();
        if (this.isFileSource)
            return this.getClipboardSource()

        return html`
            <div class="container">
                
                ${additionalButtons}
                
                <link rel="stylesheet" href="${tabulatorCss}">
               
                <div class="table-wrapper">
                    <label class="button-container select-all-icon">
                        <input type="checkbox" id="select_all" name="select_all" value="select_all" @click="${() => {this.selectAllFiles();}}">
                        <span class="checkmark"></span>
                    </label>
                    <table id="clipboard-content-table" class="force-no-select"></table>
                </div>
            </div>
        `;
    }
}