var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
import React from 'react';
import { ulid } from 'ulid';
import { useFileUploader } from '../../effects/useFileUploader';
import { useI18nContext } from '../../state/I18n';
import { addSubcomponents } from '../../utils/addSubcomponents';
import { FileExplorer } from './FileExplorer/FileExplorer';
import { GridSource } from './GridSource';
import { LocalSource } from './LocalSource';
import { TreeSource } from './TreeSource';
import { FileSelectDropzone } from './FileSelectDropzone';
import { StyledFileSelect, StyledFileTokenList } from './FileSelect.styles';
export var FileSelectLocalSourceId = 'FileSelectLocalSource';
var defaultGetTokenLabel = function (sourceId, sourceValueEntry) {
    return sourceValueEntry.name;
};
var defaultGetMethod = function () { return 'POST'; };
var defaultGetPayloadKey = function () { return 'file'; };
var defaultGetHeaders = function () { return ({}); };
var getValueTokenLabel = function (sourceId, entry, getTokenLabel) {
    var _a;
    if (getTokenLabel === void 0) { getTokenLabel = defaultGetTokenLabel; }
    var namePlaceholder = 'Untitled';
    var name = (_a = getTokenLabel(sourceId, entry)) !== null && _a !== void 0 ? _a : entry.name;
    if (!name) {
        console.warn("FileSelect: Couldn't derive the name of \"".concat(sourceId, "\" source value. Check the source or use \"getTokenLabel\" prop"));
    }
    return name !== null && name !== void 0 ? name : namePlaceholder;
};
var FileSelectBase = React.forwardRef(function (_a, ref) {
    var onAdd = _a.onAdd, _b = _a.beforeLocalFileUpload, beforeLocalFileUpload = _b === void 0 ? function () { return new Promise(function (resolve) { return resolve(true); }); } : _b, onRemove = _a.onRemove, onProgress = _a.onProgress, onUploadStateChange = _a.onUploadStateChange, onError = _a.onError, onFileTokenClick = _a.onFileTokenClick, dropzoneContentRenderer = _a.dropzoneContentRenderer, _c = _a.hideDropzone, hideDropzone = _c === void 0 ? false : _c, _d = _a.getTokenLabel, getTokenLabel = _d === void 0 ? defaultGetTokenLabel : _d, _e = _a.hideLocalSource, hideLocalSource = _e === void 0 ? false : _e, localSourceDropzoneContentRenderer = _a.localSourceDropzoneContentRenderer, _f = _a.maxFileNumber, maxFileNumber = _f === void 0 ? Infinity : _f, maxFileSize = _a.maxFileSize, minFileSize = _a.minFileSize, accept = _a.accept, getEndpoint = _a.getEndpoint, _g = _a.getMethod, getMethod = _g === void 0 ? defaultGetMethod : _g, _h = _a.getPayloadKey, getPayloadKey = _h === void 0 ? defaultGetPayloadKey : _h, getPayload = _a.getPayload, _j = _a.getHeaders, getHeaders = _j === void 0 ? defaultGetHeaders : _j, uploadFile = _a.uploadFile, children = _a.children, qa = _a.qa, props = __rest(_a, ["onAdd", "beforeLocalFileUpload", "onRemove", "onProgress", "onUploadStateChange", "onError", "onFileTokenClick", "dropzoneContentRenderer", "hideDropzone", "getTokenLabel", "hideLocalSource", "localSourceDropzoneContentRenderer", "maxFileNumber", "maxFileSize", "minFileSize", "accept", "getEndpoint", "getMethod", "getPayloadKey", "getPayload", "getHeaders", "uploadFile", "children", "qa"]);
    var _k = React.useState(false), isOpen = _k[0], setIsOpen = _k[1];
    var _l = React.useState(''), currentSource = _l[0], setCurrentSource = _l[1];
    var _m = React.useState([]), sources = _m[0], setSources = _m[1];
    var I18n = useI18nContext();
    var fileUploader = useFileUploader({
        getEndpoint: getEndpoint,
        getMethod: getMethod,
        getPayloadKey: getPayloadKey,
        getPayload: getPayload,
        getHeaders: getHeaders,
        uploadFile: uploadFile,
    });
    var _o = React.useState([]), value = _o[0], setValue = _o[1];
    var _p = React.useState({}), uploadProgress = _p[0], setUploadProgress = _p[1];
    var _q = React.useState(0), pendingUploadsCount = _q[0], setPendingUploadsCount = _q[1];
    var modalElRef = React.useRef(null);
    var rootElRef = React.useRef(null);
    var dropzoneRef = React.useRef(null);
    React.useEffect(function () {
        onUploadStateChange === null || onUploadStateChange === void 0 ? void 0 : onUploadStateChange(pendingUploadsCount > 0);
    }, [pendingUploadsCount]);
    React.useImperativeHandle(ref, function () { return ({
        setValue: setValue,
        open: function (sourceId) {
            var _a;
            setIsOpen(true);
            var newCurrentSource = sourceId !== null && sourceId !== void 0 ? sourceId : (_a = sources[0]) === null || _a === void 0 ? void 0 : _a.sourceId;
            if (newCurrentSource) {
                setCurrentSource(newCurrentSource);
            }
        },
        close: function () {
            setIsOpen(false);
        },
        modalEl: modalElRef,
        rootEl: rootElRef,
    }); });
    var uploadedValues = value.filter(function (entry) { return !entry.error; });
    var adjustedMaxFileNumber = maxFileNumber - uploadedValues.length;
    var hasReachedMaxFileNumber = adjustedMaxFileNumber < 1;
    var unsubmittedSourceValues = sources.flatMap(function (source) { return source.value; });
    var updateFile = function (fileId, payload) {
        setValue(function (prev) {
            return prev.map(function (v) {
                if (v.id === fileId) {
                    return __assign(__assign({}, v), payload);
                }
                return v;
            });
        });
    };
    function onProgressInternal(id, progress) {
        onProgress === null || onProgress === void 0 ? void 0 : onProgress(id, progress);
        setUploadProgress(function (prev) {
            var _a;
            return (__assign(__assign({}, prev), (_a = {}, _a[id] = Math.min(99, progress), _a)));
        });
    }
    function onErrorInternal(id, error) {
        updateFile(id, { error: I18n.t('core.fileSelect.uploadFailed') });
        onError === null || onError === void 0 ? void 0 : onError(id, error);
        setUploadProgress(function (prev) {
            var _a;
            return (__assign(__assign({}, prev), (_a = {}, _a[id] = 100, _a)));
        });
    }
    var uploadFiles = function (newFiles) {
        function onComplete(id, response) {
            var localFile = newFiles.find(function (entry) { return entry.id === id; });
            updateFile(id, { response: response });
            var uploadedFile = __assign(__assign({}, localFile), { sourceId: FileSelectLocalSourceId, response: response });
            onAdd === null || onAdd === void 0 ? void 0 : onAdd([uploadedFile]);
            setUploadProgress(function (prev) {
                var _a;
                return (__assign(__assign({}, prev), (_a = {}, _a[id] = 100, _a)));
            });
        }
        setPendingUploadsCount(function (prev) { return prev + 1; });
        fileUploader.uploadFiles(newFiles.map(function (entry) { return ({ id: entry.id, blob: entry.src }); }), {
            onComplete: onComplete,
            onProgress: onProgressInternal,
            onError: onErrorInternal,
            onCompleteAll: function () {
                setPendingUploadsCount(function (prev) { return prev - 1; });
            },
        });
    };
    var onDrop = function (acceptedFiles) { return __awaiter(void 0, void 0, void 0, function () {
        var newFiles, shouldAttach;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    newFiles = acceptedFiles
                        .slice(0, adjustedMaxFileNumber)
                        .map(function (file) { return ({
                        src: file,
                        id: ulid(),
                        name: file.name,
                        sourceId: FileSelectLocalSourceId,
                    }); });
                    return [4 /*yield*/, beforeLocalFileUpload(newFiles)];
                case 1:
                    shouldAttach = _a.sent();
                    if (!shouldAttach)
                        return [2 /*return*/];
                    setUploadProgress(function (prev) {
                        return newFiles.reduce(function (acc, item) {
                            acc[item.id] = 0;
                            return acc;
                        }, prev);
                    });
                    setValue(function (prev) { return __spreadArray(__spreadArray([], prev, true), newFiles.map(function (file) { return (__assign(__assign({}, file), { name: getValueTokenLabel(FileSelectLocalSourceId, file, getTokenLabel) })); }), true); });
                    uploadFiles(newFiles);
                    return [2 /*return*/];
            }
        });
    }); };
    var onModalSubmit = function () {
        var _a, _b, _c;
        setIsOpen(false);
        var values = sources.flatMap(function (source) {
            if (source.sourceId === FileSelectLocalSourceId) {
                return source.value.map(function (v) {
                    var name = getValueTokenLabel(source.sourceId, v, getTokenLabel);
                    return __assign(__assign({}, v), { name: name, sourceId: FileSelectLocalSourceId });
                });
            }
            return source.value.map(function (entry) {
                var name = getValueTokenLabel(source.sourceId, entry, getTokenLabel);
                return {
                    id: ulid(),
                    name: name,
                    sourceId: source.sourceId,
                    origin: entry,
                };
            });
        });
        setValue(function (prev) { return __spreadArray(__spreadArray([], prev, true), values, true); });
        onAdd === null || onAdd === void 0 ? void 0 : onAdd(values);
        clearErrors();
        resetListeners.current.forEach(function (resetListener) { return resetListener === null || resetListener === void 0 ? void 0 : resetListener(); });
        setCurrentSource((_a = sources[0]) === null || _a === void 0 ? void 0 : _a.sourceId);
        (_c = (_b = dropzoneRef.current) === null || _b === void 0 ? void 0 : _b.attachButton) === null || _c === void 0 ? void 0 : _c.focus();
    };
    var clearErrors = function () {
        var _a;
        (_a = dropzoneRef.current) === null || _a === void 0 ? void 0 : _a.clearErrors();
    };
    var handleFileRemoval = function (value) {
        setValue(function (prev) { return prev.filter(function (entry) { return entry.id !== value.id; }); });
        onRemove === null || onRemove === void 0 ? void 0 : onRemove(value);
        setUploadProgress(function (prev) {
            var _a;
            return (__assign(__assign({}, prev), (_a = {}, _a[value.id] = null, _a)));
        });
        clearErrors();
    };
    var updateSource = function (sourceId, props) {
        setSources(function (prev) {
            return prev.map(function (source) {
                if (source.sourceId === sourceId) {
                    return __assign(__assign({}, source), props);
                }
                return source;
            });
        });
    };
    var onAttachFromProject = function () {
        var _a;
        setIsOpen(true);
        if (!currentSource) {
            setCurrentSource((_a = sources[0]) === null || _a === void 0 ? void 0 : _a.sourceId);
        }
    };
    var resetListeners = React.useRef([]);
    return (React.createElement(StyledFileSelect, __assign({}, props, { ref: rootElRef }),
        React.createElement(FileExplorer, { ref: modalElRef, qa: { attachButton: qa === null || qa === void 0 ? void 0 : qa.attachButton }, unsubmittedValueCount: unsubmittedSourceValues.length, onModalVisibilityChange: function (isOpen) {
                var _a, _b;
                setIsOpen(isOpen);
                if (!isOpen) {
                    (_b = (_a = dropzoneRef.current) === null || _a === void 0 ? void 0 : _a.attachButton) === null || _b === void 0 ? void 0 : _b.focus();
                }
            }, sources: sources, currentSource: currentSource, onCurrentSourceChange: setCurrentSource, isOpen: isOpen, onSubmit: onModalSubmit },
            React.createElement(FileSelectContext.Provider, { value: {
                    register: function (sourceId, source) {
                        setSources(function (prev) { return __spreadArray(__spreadArray([], prev, true), [
                            __assign(__assign({ title: '', icon: '', isUploading: false, hasError: false, value: [] }, source), { sourceId: sourceId }),
                        ], false); });
                        return function () {
                            setSources(function (prev) {
                                return prev.filter(function (source) { return source.sourceId !== sourceId; });
                            });
                        };
                    },
                    currentSource: currentSource,
                    onChange: function (sourceId, value) {
                        updateSource(sourceId, { value: value });
                    },
                    onResetValue: function (listener) {
                        resetListeners.current = __spreadArray(__spreadArray([], resetListeners.current, true), [listener], false);
                        return function () {
                            resetListeners.current = resetListeners.current.filter(function (listenerEntry) { return listener !== listenerEntry; });
                        };
                    },
                    setIsUploading: function (sourceId, isUploading) {
                        updateSource(sourceId, { isUploading: isUploading });
                    },
                    setHasError: function (sourceId, hasError) {
                        updateSource(sourceId, { hasError: hasError });
                    },
                    isModalOpen: isOpen,
                    maxFileNumber: adjustedMaxFileNumber - unsubmittedSourceValues.length,
                } },
                !hideLocalSource ? (React.createElement(LocalSource, { beforeLocalFileUpload: beforeLocalFileUpload, dropzoneContentRenderer: localSourceDropzoneContentRenderer, sourceId: FileSelectLocalSourceId, getEndpoint: getEndpoint, getMethod: getMethod, getPayloadKey: getPayloadKey, getPayload: getPayload, getHeaders: getHeaders, uploadFile: uploadFile, accept: accept, maxFileSize: maxFileSize, minFileSize: minFileSize, qa: qa === null || qa === void 0 ? void 0 : qa.localSource })) : null,
                children)),
        React.createElement(FileSelectDropzone, { ref: dropzoneRef, hideDropzone: hideDropzone, tooltip: hasReachedMaxFileNumber
                ? I18n.t('core.fileSelect.maxNumberOfFilesSelected')
                : '', contentRenderer: dropzoneContentRenderer
                ? function (dropzoneProps) {
                    return dropzoneContentRenderer({
                        openFileExplorer: onAttachFromProject,
                        openLocalFiles: dropzoneProps.open,
                        disabled: dropzoneProps.disabled,
                        errorMessage: dropzoneProps.errorMessage,
                    });
                }
                : undefined, onAttachFromProject: onAttachFromProject, accept: accept, maxFileNumber: maxFileNumber, maxFileSize: maxFileSize, minFileSize: minFileSize, disabled: hasReachedMaxFileNumber, value: uploadedValues, onDrop: onDrop, multiple: true, noDrag: hideDropzone }),
        React.createElement(StyledFileTokenList, { tokens: value.map(function (v) {
                var _a;
                return (__assign(__assign({}, v), { progress: (_a = uploadProgress[v.id]) !== null && _a !== void 0 ? _a : 100 }));
            }), onClick: onFileTokenClick, onClose: handleFileRemoval, qa: { closeButton: qa === null || qa === void 0 ? void 0 : qa.removeEntry } })));
});
function noop() { }
export var FileSelectContext = React.createContext({
    register: function () { return noop; },
    currentSource: '',
    isModalOpen: false,
    onChange: noop,
    onResetValue: function () { return noop; },
    maxFileNumber: Infinity,
    setIsUploading: noop,
    setHasError: noop,
});
export var useFileSelectContext = function () {
    return React.useContext(FileSelectContext);
};
/**

 The file explorer enables users to select permitted files from various document
 sources in procore to attach to items.

 @since 10.19.0

 @see [Storybook](https://procore.github.io/core/latest/?path=/story/demos-fileselect--demo)

 @see [Design Guidelines](https://design.procore.com/file-select)

 */
export var FileSelect = addSubcomponents({
    LocalSource: LocalSource,
    GridSource: GridSource,
    TreeSource: TreeSource,
}, FileSelectBase);
//# sourceMappingURL=FileSelect.js.map