/*!
 * Built by ShiftSoftware
 * Copyright (c)
 */
import { Host, h } from "@stencil/core";
import cn from "../../global/lib/cn";
import { getInputLocalization } from "../../features/form-hook/index";
import { FormInputLabel } from "./components/form-input-label";
import { FormErrorMessage } from "./components/form-error-message";
import { LoaderIcon } from "../../global/assets/loader-icon";
import { TickIcon } from "../../global/assets/tick-icon";
import { mixed } from "yup";
import { meta, format, size, require, max } from "../forms/defaults/validation";
const partKeyPrefix = 'form-file-';
export class FormFile {
    constructor() {
        this.maxUpload = 1;
        this.signMethod = 'POST';
        this.localization = {};
        this.fileName = '';
        this.uploadState = 'idle';
        this.failedText = '';
        this.sasFiles = [];
        this.controlsFormLoading = false;
        this.wasFormLoading = false;
        this.openFilePicker = () => {
            if (!this.fileInput)
                return;
            this.reset(); // clears old file + state
            this.fileInput.click();
        };
        this.handleFileChange = async (event) => {
            const target = event.target;
            const fileList = Array.from((target === null || target === void 0 ? void 0 : target.files) || []);
            if (!fileList.length)
                return;
            const limited = typeof this.maxUpload === 'number' && this.maxUpload > 0 ? fileList.slice(0, this.maxUpload) : fileList;
            this.fileName = limited.map(f => f.name).join(', ');
            this.failedText = '';
            this.uploadState = 'uploading';
            this.startGlobalLoading();
            const dataTransfer = new DataTransfer();
            try {
                if (this.signUrl) {
                    const signedFiles = await this.requestSignedUpload(limited);
                    this.form.pendingRequests[this.name] = async () => await this.uploadToSignedUrl(limited, signedFiles);
                }
                this.uploadState = 'success';
                this.syncValue([...limited]);
                limited.forEach(file => dataTransfer.items.add(file));
                target.files = dataTransfer.files;
            }
            catch (error) {
                this.sasFiles = [];
                console.error(error);
                target.files = dataTransfer.files;
                const [locale, language] = this.form.getFormLocale();
                this.uploadState = 'error';
                this.failedText = this.getFailureText(locale, language);
                this.syncValue();
                // @ts-ignore
                if (this.fileInput)
                    this.fileInput.value = [];
            }
            finally {
                this.stopGlobalLoading();
            }
        };
        this.validate = () => {
            let validation = mixed().meta(meta(this.name));
            if (this.required) {
                validation = validation.test(require(this.name), require(this.name), (value) => {
                    if (!Array.isArray(value))
                        return false;
                    const count = value.length;
                    return count > 0;
                });
            }
            else {
                validation = validation.optional();
            }
            if (this.maxUpload && this.maxUpload > 0) {
                validation = validation.test(max(this.name), max(this.name), (value) => {
                    if (!Array.isArray(value))
                        return true;
                    const count = value.length;
                    return count <= this.maxUpload;
                });
            }
            if (this.maxSize) {
                validation = validation.test(size(this.name), size(this.name), (value) => {
                    if (!Array.isArray(value))
                        return true;
                    if (!value.length)
                        return true;
                    const maxSizeInBytes = this.maxSize * 1024 * 1024;
                    return value.every(f => f.size <= maxSizeInBytes);
                });
            }
            if (this.accept) {
                validation = validation.test(format(this.name), format(this.name), (value) => {
                    if (!Array.isArray(value))
                        return true;
                    if (!value.length)
                        return true;
                    return value.every(f => this.matchesAccept(f));
                });
            }
            return validation;
        };
    }
    async componentWillLoad() {
        this.form.subscribe(this.name, this);
    }
    componentDidLoad() {
        this.fileInput = this.el.querySelector(`.${partKeyPrefix}${this.name}-input`);
    }
    async disconnectedCallback() {
        this.stopGlobalLoading();
        this.form.unsubscribe(this.name);
    }
    reset() {
        this.stopGlobalLoading();
        if (this.fileInput)
            this.fileInput.value = '';
        this.fileName = '';
        this.uploadState = 'idle';
    }
    startGlobalLoading() {
        var _a, _b, _c, _d;
        if (!((_b = (_a = this.form) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.setIsLoading) || this.controlsFormLoading)
            return;
        this.wasFormLoading = !!((_d = (_c = this.form) === null || _c === void 0 ? void 0 : _c.context) === null || _d === void 0 ? void 0 : _d.isLoading);
        this.controlsFormLoading = true;
        this.form.context.setIsLoading(true);
    }
    stopGlobalLoading() {
        var _a, _b;
        if (!this.controlsFormLoading || !((_b = (_a = this.form) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.setIsLoading))
            return;
        this.form.context.setIsLoading(this.wasFormLoading);
        this.controlsFormLoading = false;
    }
    getLoadingText(locale, language) {
        var _a, _b, _c;
        return ((_b = (_a = this.localization) === null || _a === void 0 ? void 0 : _a[language]) === null || _b === void 0 ? void 0 : _b.uploading) || ((_c = locale === null || locale === void 0 ? void 0 : locale.sharedFormLocales) === null || _c === void 0 ? void 0 : _c.loading) || 'Uploading...';
    }
    getUploadText(locale, language, placeholder) {
        var _a, _b, _c;
        return ((_b = (_a = this.localization) === null || _a === void 0 ? void 0 : _a[language]) === null || _b === void 0 ? void 0 : _b.upload) || placeholder || ((_c = locale === null || locale === void 0 ? void 0 : locale.sharedFormLocales) === null || _c === void 0 ? void 0 : _c.uploadLabel) || 'Upload file';
    }
    getFailureText(locale, language) {
        var _a, _b, _c, _d;
        return ((_b = (_a = this.localization) === null || _a === void 0 ? void 0 : _a[language]) === null || _b === void 0 ? void 0 : _b.failure) || ((_d = (_c = locale === null || locale === void 0 ? void 0 : locale.sharedFormLocales) === null || _c === void 0 ? void 0 : _c.errors) === null || _d === void 0 ? void 0 : _d.wildCard) || 'Upload failed. Please try again.';
    }
    matchesAccept(value) {
        var _a;
        if (!this.accept)
            return true;
        const rules = this.accept
            .split(',')
            .map(rule => rule.trim())
            .filter(Boolean)
            .map(rule => rule.toLowerCase());
        if (!rules.length)
            return true;
        const fileName = typeof value === 'string' ? value : (value === null || value === void 0 ? void 0 : value.name) || '';
        const mime = typeof value === 'string' ? '' : ((_a = value === null || value === void 0 ? void 0 : value.type) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
        const ext = fileName.includes('.') ? fileName.slice(fileName.lastIndexOf('.')).toLowerCase() : '';
        return rules.some(rule => {
            if (rule === '*/*')
                return true;
            if (rule.endsWith('/*'))
                return mime ? mime.startsWith(rule.replace('/*', '/')) : false;
            if (rule.startsWith('.'))
                return ext === rule;
            if (rule.includes('/'))
                return mime ? mime === rule : false;
            return true;
        });
    }
    syncValue(value) {
        var _a, _b;
        const resolved = (value === null || value === void 0 ? void 0 : value[0]) || '';
        this.fileName = typeof resolved === 'string' ? resolved : resolved === null || resolved === void 0 ? void 0 : resolved.name;
        // @ts-ignore
        (_a = this.form) === null || _a === void 0 ? void 0 : _a.validateForm(this.name, !!value ? value : [], false);
        (_b = this.form) === null || _b === void 0 ? void 0 : _b.rerender({ inputName: this.name, rerenderForm: true });
    }
    async requestSignedUpload(files) {
        var _a, _b, _c;
        const formHeaders = { 'Content-Type': 'application/json' };
        const recaptchaKey = (_c = (_b = (_a = this.form) === null || _a === void 0 ? void 0 : _a.context.structure) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.recaptchaKey;
        if (grecaptcha && recaptchaKey) {
            const token = await grecaptcha.execute(recaptchaKey, { action: 'submit' });
            formHeaders['Recaptcha-Token'] = token;
        }
        const payload = files === null || files === void 0 ? void 0 : files.map(file => ({
            name: file.name,
            blob: this.signPrefix ? `${this.signPrefix}${file.name}` : file.name,
            accountName: this.accountName,
            containerName: this.containerName,
            contentType: null,
            size: file === null || file === void 0 ? void 0 : file.size,
            width: null,
            height: null,
        }));
        const response = await fetch(this.signUrl, {
            headers: formHeaders,
            body: JSON.stringify(payload),
            method: this.signMethod || 'POST',
        });
        if (!response.ok)
            throw new Error('Failed to get signed upload URL');
        const json = await response.json();
        const list = (json === null || json === void 0 ? void 0 : json.entity) || (json === null || json === void 0 ? void 0 : json.Entity) || json;
        const arr = Array.isArray(list) ? list : Array.isArray(json) ? json : [];
        const signedFiles = arr.map((file, idx) => {
            var _a;
            // @ts-ignore
            files[idx].blob = (file === null || file === void 0 ? void 0 : file.Blob) || (file === null || file === void 0 ? void 0 : file.blob);
            // @ts-ignore
            files[idx].contentType = (_a = files[idx]) === null || _a === void 0 ? void 0 : _a.type;
            // @ts-ignore
            files[idx].url = file.Url || file.url;
            return {
                uploadUrl: file.url || file.Url || file.uploadUrl || file.UploadUrl,
                headers: file.headers || file.Headers || {},
                key: file.blob || file.Blob || file.path || file.Path || file.key || file.Key || (file === null || file === void 0 ? void 0 : file.name),
            };
        });
        this.sasFiles = arr;
        return signedFiles;
    }
    async uploadToSignedUrl(files, signedFiles) {
        files === null || files === void 0 ? void 0 : files.forEach(async (file, idx) => {
            var _a, _b;
            try {
                const response = await fetch((_a = signedFiles === null || signedFiles === void 0 ? void 0 : signedFiles[idx]) === null || _a === void 0 ? void 0 : _a.uploadUrl, {
                    method: 'PUT',
                    headers: Object.assign({ 'Content-Type': file.type || 'application/octet-stream', 'x-ms-blob-type': 'BlockBlob' }, (_b = signedFiles === null || signedFiles === void 0 ? void 0 : signedFiles[idx]) === null || _b === void 0 ? void 0 : _b.headers),
                    body: file,
                });
                if (!response.ok)
                    console.error(response);
            }
            catch (error) {
                console.error(error);
            }
        });
    }
    render() {
        const { disabled, isRequired, meta, isError, errorMessage } = this.form.getInputState(this.name);
        const [locale, language] = this.form.getFormLocale();
        const { label, placeholder, errorTextMessage } = getInputLocalization(this, meta, errorMessage);
        const disableInput = disabled || this.isLoading || this.uploadState === 'uploading' || this.isDisabled;
        const showSpinner = this.uploadState === 'uploading';
        const displayText = this.uploadState === 'success' && this.fileName ? this.fileName : this.getUploadText(locale, language, placeholder || (meta === null || meta === void 0 ? void 0 : meta.placeholder));
        const isErrorState = this.uploadState !== 'uploading' && (!!this.failedText || isError);
        // @ts-ignore
        window === null || window === void 0 ? void 0 : window.s = this.form;
        return (h(Host, { key: '01a336807102ac05f2d56b86fba4ffc07b7204bb', translate: "no" }, h("label", { key: 'c0dc4c48ffa9e536accbdc6bc4620e6a2c4ef4a9', part: `form-file ${this.name}`, id: this.wrapperId, class: cn('form-input-label-container', this.wrapperClass, { disabled: disableInput }) }, h(FormInputLabel, { key: '757b0effce444d8df8993404a7a62a75cef3996e', name: this.name, isRequired: isRequired, label: label }), h("div", { key: 'b5d63a30ccd687d0ff7e79da1968a9d0a2324cf7', part: `${this.name}-container form-input-container`, class: cn('form-input-container') }, h("input", { key: 'f80697792482c72df360cdcd1e0b82a0ffbe0dfb', type: "file", name: this.name, accept: this.accept, disabled: disableInput, multiple: this.maxUpload > 1, onChange: this.handleFileChange, part: `${this.name}-file-input form-file-input`, class: cn('form-file-input', `${partKeyPrefix}${this.name}-input`) }), h("button", { key: '92b1a144940f796246a6c9a61fd71d68ef565bf0', type: "button", disabled: disableInput, onClick: this.openFilePicker, part: `${this.name}-file-trigger form-file-trigger form-input`, title: showSpinner ? this.getLoadingText(locale, language) : displayText, class: cn('form-file-trigger form-input-style', {
                'form-input-error-style': isErrorState,
                'form-file-trigger-loading': showSpinner,
                'form-file-trigger-success': this.uploadState === 'success',
            }) }, h("span", { key: 'd3c43e9a9cc883cea8db1c229097764807f2f92d', part: `${this.name}-file-text form-file-text`, class: "form-file-text" }, showSpinner ? this.getLoadingText(locale, language) : displayText), h("span", { key: 'fe69569c57c3597260d256f95f9e163aca239046', part: `${this.name}-file-icon form-file-icon`, class: "form-file-icon" }, showSpinner && h(LoaderIcon, { key: 'c93782e7a6057e02e43b013a6609a122724af446', class: "form-file-spinner" }), !showSpinner && this.uploadState === 'success' && h(TickIcon, { key: 'dba3e6c5d0767007fb011b33e9f6c262041d6bcc', class: "form-file-success-icon" })))), h(FormErrorMessage, { key: 'c70a8614a3d2b1c9416caee665007f33bc530e50', name: this.name, isError: isErrorState, errorMessage: this.failedText || errorTextMessage }))));
    }
    static get is() { return "form-file"; }
    static get originalStyleUrls() {
        return {
            "$": ["form-inputs.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["form-inputs.css"]
        };
    }
    static get properties() {
        return {
            "name": {
                "type": "string",
                "attribute": "name",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "wrapperId": {
                "type": "string",
                "attribute": "wrapper-id",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "form": {
                "type": "unknown",
                "attribute": "form",
                "mutable": false,
                "complexType": {
                    "original": "FormHook<any>",
                    "resolved": "FormHook<any>",
                    "references": {
                        "FormHook": {
                            "location": "import",
                            "path": "~features/form-hook",
                            "id": "src/features/form-hook/index.ts::FormHook"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false
            },
            "isLoading": {
                "type": "boolean",
                "attribute": "is-loading",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "wrapperClass": {
                "type": "string",
                "attribute": "wrapper-class",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "isDisabled": {
                "type": "boolean",
                "attribute": "is-disabled",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "accept": {
                "type": "string",
                "attribute": "accept",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "maxSize": {
                "type": "number",
                "attribute": "max-size",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "required": {
                "type": "boolean",
                "attribute": "required",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "signUrl": {
                "type": "string",
                "attribute": "sign-url",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "maxUpload": {
                "type": "number",
                "attribute": "max-upload",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "1"
            },
            "signMethod": {
                "type": "string",
                "attribute": "sign-method",
                "mutable": false,
                "complexType": {
                    "original": "'POST' | 'PUT'",
                    "resolved": "\"POST\" | \"PUT\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "'POST'"
            },
            "signPrefix": {
                "type": "string",
                "attribute": "sign-prefix",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "accountName": {
                "type": "string",
                "attribute": "account-name",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "containerName": {
                "type": "string",
                "attribute": "container-name",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "localization": {
                "type": "unknown",
                "attribute": "localization",
                "mutable": false,
                "complexType": {
                    "original": "FormInputLocalization<{\n    uploading?: string;\n    upload?: string;\n    failure?: string;\n    success?: string;\n  }>",
                    "resolved": "{ [lang: string]: { label?: string; placeholder?: string; require?: string; format?: string; minMessage: string; maxMessage: string; betweenMessage: string; } & { uploading?: string; upload?: string; failure?: string; success?: string; }; }",
                    "references": {
                        "FormInputLocalization": {
                            "location": "import",
                            "path": "~features/form-hook",
                            "id": "src/features/form-hook/index.ts::FormInputLocalization"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "defaultValue": "{}"
            }
        };
    }
    static get states() {
        return {
            "fileName": {},
            "uploadState": {},
            "failedText": {}
        };
    }
    static get elementRef() { return "el"; }
}
