import { library } from '@fortawesome/fontawesome-svg-core';
import * as FAS from '@fortawesome/free-solid-svg-icons';
import { h } from "@stencil/core";
import { getInputCreator } from '../bce-input-creator/input-creator';
import { BceFile } from '../../utils/bce-file';
import { ripple } from '../../utils/ripple';
// const UNSPLASH: IconDefinition = {
//   prefix: 'bce' as any,
//   iconName: 'unsplash' as any,
//   icon: [
//     122.4,
//     122.4,
//     [],
//     '',
//     'M122.4,54.1v68.3H0V54.1h38.6v34.1h45.3V54.1H122.4z M83.9,0H38.6v34.1h45.3V0z'
//   ]
// };
library.add(
// FAS.faCloud,
FAS.faFileAudio, FAS.faFileImage, FAS.faFileUpload, FAS.faFileVideo, FAS.faGlobe
// UNSPLASH
);
export class Upload {
    constructor() {
        this.value = [];
        this.multiple = false;
        // #endregion
        this._highlight = false;
        this.data = {};
        this._initialValue = this.value;
        this._inputCreator = getInputCreator(this, err => (this.error = !!err));
        this._server = window.BCE.file;
        this.handleData = (data) => {
            this.data = data;
        };
        this.handleDragEnter = (event) => {
            event.preventDefault();
            event.stopPropagation();
            if (this.disabled)
                return;
            this._highlight = true;
        };
        this.handleDragLeave = (event) => {
            event.preventDefault();
            event.stopPropagation();
            if (this.disabled)
                return;
            this._highlight = false;
        };
        this.handleDragOver = (event) => {
            event.preventDefault();
            event.stopPropagation();
        };
        this.handleDrop = (event) => {
            event.preventDefault();
            event.stopPropagation();
            if (this.disabled)
                return;
            this._highlight = false;
            ripple(event.target, event);
            this.upload(event.dataTransfer.files);
        };
        this.handleUpload = (event) => {
            const input = event.target;
            if (!input || !input.files)
                return;
            this.upload(input.files);
            input.value = '';
        };
        this.handleUrl = async () => {
            if (this.disabled)
                return;
            const url = window.prompt();
            if (!url)
                return;
            // Download as blob
            const req = new Request(url);
            const res = await fetch(req);
            const blob = await res.blob();
            // Find filename
            const header = res.headers.get('content-disposition');
            const match = header === null || header === void 0 ? void 0 : header.match(/filename="(.+)"/);
            const name = match && match[1];
            const fallback = new URL(url).pathname.split('/').pop();
            // Download and use the file
            const file = this.toFile(blob, name || fallback || 'unnamed');
            this.upload([file]);
        };
        this.ignoreEvent = (event) => {
            event.stopPropagation();
        };
        this.triggerUpload = () => {
            if (this.disabled || (!this.multiple && this.value.length))
                return;
            const input = this.el.shadowRoot.querySelector('input');
            if (input)
                input.click();
        };
    }
    get fileIcon() {
        switch (this.accept) {
            case 'audio/*':
                return 'file-audio';
            case 'image/*':
                return 'file-image';
            case 'video/*':
                return 'file-video';
            default:
                return 'file-upload';
        }
    }
    async cancel(id) {
        return this._server.cancel(id);
    }
    async delete(id) {
        this.updateValue(this.value.filter(v => v !== id));
        return this._server.delete(id, this.metadata);
    }
    async download(id) {
        const value = this.data[id].file;
        if (!value)
            return;
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = value.url;
        a.download = value.name;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }
    async rename(id, filename) {
        const value = this.data[id].file;
        if (!value || value.name === filename)
            return;
        // Extract extension
        const regex = /\.[0-9a-z]+$/i;
        const match = value.name.match(regex);
        const ext = match && match[0];
        // Request new name
        const name = ext
            ? ((filename === null || filename === void 0 ? void 0 : filename.replace(regex, '')) || value.name) + ext
            : filename || value.name;
        return this._server.rename(id, name);
    }
    async upload(files) {
        if (!this.multiple && this.value.length)
            return;
        // Ensure input is a BceFile array
        const converted = Array.isArray(files)
            ? files
            : Array.from(files).map(f => this.toFile(f, f.name));
        // Filter files
        const tasks = converted.map(async (file) => {
            // Remove duplicates by comparing file hashes
            const hash = await file.hash();
            const list = this.value.map(id => this.data[id]).filter(Boolean);
            if (list.find(v => v && v.file.hash === hash))
                return undefined;
            // Remove files with incorrect types
            const accept = this.accept || '*';
            const regexStr = accept.replace('*', '.*').replace(/\,/g, '|');
            if (!new RegExp(regexStr).test(file.type))
                return undefined;
            // Accept file
            return file;
        });
        const filtered = (await Promise.all(tasks)).filter(Boolean);
        const upload = this.multiple ? filtered : filtered.slice(0, 1);
        if (!upload.length)
            return;
        const { metadata } = this;
        this.updateValue([...this.value, ...upload.map(u => u.id)], false);
        const uploads = upload.map(file => this._server.upload(file, metadata));
        return Promise.all(uploads);
    }
    watchValue(value) {
        this._server.subscribe(this.handleData, value);
    }
    toFile(blob, name) {
        const id = window.BCE.generateId();
        return new BceFile(id, name, blob);
    }
    updateValue(value, sort = true) {
        this.value = sort
            ? value
                .map(id => { var _a; return ((_a = this.data[id]) === null || _a === void 0 ? void 0 : _a.file) || { id, name: '' }; })
                .sort((a, b) => a.name.localeCompare(b.name))
                .map(ref => ref.id)
            : value;
        this.el.dispatchEvent(new globalThis.Event('input'));
    }
    componentWillLoad() {
        this.watchValue(this.value);
    }
    componentDidUnload() {
        this._server.unsubscribe(this.handleData);
    }
    renderPreview() {
        return this.value.map(id => {
            const item = this.data[id];
            const { file = id, progress = 1 } = item || {};
            return (h("bce-upload-item", { disabled: this.disabled, progress: progress, value: file }));
        });
    }
    renderDropzone() {
        const preview = !!this.value.length;
        const classes = { dropzone: true, highlight: this._highlight };
        return (h("div", { class: classes, onClick: this.triggerUpload, onDragEnter: this.handleDragEnter, onDragLeave: this.handleDragLeave, onDragOver: this.handleDragOver, onDrop: this.handleDrop },
            h("div", { class: "preview" }, preview && this.renderPreview()),
            h("div", { class: "placeholder", style: { display: preview ? 'none' : '' } },
                h("bce-icon", { pre: "fas", name: this.fileIcon }),
                h("span", null,
                    h("slot", null, "Drop a file here or click to select one.")))));
    }
    renderOptions() {
        if (this.disabled || (!this.multiple && this.value.length))
            return;
        return (h("bce-select", { type: "action" },
            h("bce-chip", { icon: `fas:${this.fileIcon}`, value: "file", onClick: this.triggerUpload }, "File"),
            h("bce-chip", { icon: "fas:globe", value: "url", onClick: this.handleUrl }, "URL")));
    }
    renderDebug() {
        if (!this.debug)
            return;
        const value = JSON.stringify(this.value, undefined, 2);
        const data = JSON.stringify(this.data, undefined, 2);
        const code = [];
        if (value)
            code.push(`const VALUE = ${value};`);
        if (this.value.length)
            code.push('');
        if (data)
            code.push(`const DATA = ${data};`);
        if (Object.keys(data).length)
            code.push('');
        return h("bce-code", { value: code, language: "js" });
    }
    renderContainer() {
        return (h("div", { class: "container" },
            this.renderDropzone(),
            this.renderOptions(),
            this.renderDebug()));
    }
    renderDialog() {
        return (h("bce-dialog", { active: this.active, "close-button": true },
            h("h3", null, "File Upload"),
            this.renderContainer()));
    }
    renderRegular() {
        const InputCreator = this._inputCreator;
        return h(InputCreator, null, this.renderContainer());
    }
    render() {
        return [
            !this.dialog ? this.renderRegular() : this.renderDialog(),
            h("input", { type: "file", accept: this.accept, multiple: this.multiple, onInput: this.ignoreEvent, onChange: this.handleUpload, tabIndex: -1 })
        ];
    }
    static get is() { return "bce-upload"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() { return {
        "$": ["bce-upload.scss"]
    }; }
    static get styleUrls() { return {
        "$": ["bce-upload.css"]
    }; }
    static get properties() { return {
        "active": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "active",
            "reflect": true
        },
        "debug": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "debug",
            "reflect": true
        },
        "dialog": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "dialog",
            "reflect": true
        },
        "disabled": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "disabled",
            "reflect": true
        },
        "error": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "error",
            "reflect": true
        },
        "hasFocus": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "focus",
            "reflect": true
        },
        "height": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "height",
            "reflect": true
        },
        "info": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "info",
            "reflect": true
        },
        "label": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "label",
            "reflect": true
        },
        "metadata": {
            "type": "any",
            "mutable": false,
            "complexType": {
                "original": "any",
                "resolved": "any",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "metadata",
            "reflect": false
        },
        "name": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "name",
            "reflect": true
        },
        "tooltip": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "tooltip",
            "reflect": false
        },
        "validation": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "validation",
            "reflect": true
        },
        "value": {
            "type": "unknown",
            "mutable": true,
            "complexType": {
                "original": "string[]",
                "resolved": "string[]",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": ""
            },
            "defaultValue": "[]"
        },
        "width": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "width",
            "reflect": true
        },
        "accept": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "accept",
            "reflect": true
        },
        "multiple": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "multiple",
            "reflect": true,
            "defaultValue": "false"
        }
    }; }
    static get states() { return {
        "_highlight": {},
        "data": {}
    }; }
    static get methods() { return {
        "cancel": {
            "complexType": {
                "signature": "(id: string) => Promise<void>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        },
        "delete": {
            "complexType": {
                "signature": "(id: string) => Promise<void>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        },
        "download": {
            "complexType": {
                "signature": "(id: string) => Promise<void>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        },
        "rename": {
            "complexType": {
                "signature": "(id: string, filename?: string) => Promise<void>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }, {
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        },
        "upload": {
            "complexType": {
                "signature": "(files: BceFile[] | FileList) => Promise<FileRef[]>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "FileRef": {
                        "location": "import",
                        "path": "../../models/file-ref"
                    },
                    "BceFile": {
                        "location": "import",
                        "path": "../../utils/bce-file"
                    },
                    "FileList": {
                        "location": "global"
                    }
                },
                "return": "Promise<FileRef[]>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        }
    }; }
    static get elementRef() { return "el"; }
    static get watchers() { return [{
            "propName": "value",
            "methodName": "watchValue"
        }]; }
}
