import { UmbFileDropzoneItemStatus } from './constants.js';
import { TemporaryFileStatus, UmbTemporaryFileManager, } from '../../core/temporary-file/index.js';
import { UmbArrayState, UmbObjectState } from '../../../libs/observable-api/index.js';
import { UmbControllerBase } from '../../../libs/class-api/index.js';
import { UmbId } from '../../core/id/index.js';
/**
 * Manages the dropzone and uploads folders and files to the server.
 * @function createMediaItems - Upload files and folders to the server and creates the items using corresponding media type.
 * @function createTemporaryFiles - Upload the files as temporary files and returns the data.
 * @observable progress - Emits the number of completed items and total items.
 * @observable progressItems - Emits the items with their current status.
 */
export class UmbDropzoneManager extends UmbControllerBase {
    constructor() {
        super(...arguments);
        this._tempFileManager = new UmbTemporaryFileManager(this);
        this.#progress = new UmbObjectState({ total: 0, completed: 0 });
        this.progress = this.#progress.asObservable();
        this.#progressItems = new UmbArrayState([], (x) => x.unique);
        this.progressItems = this.#progressItems.asObservable();
        this.#prepareItemsAsUploadable = ({ folders, files }, parentUnique) => {
            const items = [];
            for (const file of files) {
                const temporaryFile = {
                    file,
                    temporaryUnique: UmbId.new(),
                    abortController: new AbortController(),
                    onProgress: (progress) => this.#updateProgress(uploadableItem, progress),
                };
                const uploadableItem = {
                    unique: UmbId.new(),
                    parentUnique,
                    status: UmbFileDropzoneItemStatus.WAITING,
                    progress: 0,
                    temporaryFile,
                };
                temporaryFile.abortController?.signal.addEventListener('abort', () => {
                    this._updateStatus(uploadableItem, UmbFileDropzoneItemStatus.CANCELLED);
                });
                items.push(uploadableItem);
            }
            for (const subfolder of folders) {
                const unique = UmbId.new();
                items.push({
                    unique,
                    parentUnique,
                    status: UmbFileDropzoneItemStatus.WAITING,
                    progress: 100, // Folders are created instantly.
                    folder: { name: subfolder.folderName },
                });
                items.push(...this.#prepareItemsAsUploadable({ folders: subfolder.folders, files: subfolder.files }, unique));
            }
            return items;
        };
    }
    #progress;
    #progressItems;
    /**
     * Uploads the files as temporary files and returns the data.
     * @param { File[] } files - The files to upload.
     * @returns {Promise<Array<UmbUploadableItem>>} - Files as temporary files.
     */
    async createTemporaryFiles(files) {
        const uploadableItems = this._setupProgress({ files, folders: [] }, null);
        const uploadedItems = [];
        for (const item of uploadableItems) {
            // Upload as temp file
            const uploaded = await this._tempFileManager.uploadOne(item.temporaryFile);
            // Update progress
            if (uploaded.status === TemporaryFileStatus.CANCELLED) {
                this._updateStatus(item, UmbFileDropzoneItemStatus.CANCELLED);
            }
            else if (uploaded.status === TemporaryFileStatus.SUCCESS) {
                this._updateStatus(item, UmbFileDropzoneItemStatus.COMPLETE);
            }
            else {
                this._updateStatus(item, UmbFileDropzoneItemStatus.ERROR);
            }
            // Add to return value
            uploadedItems.push(item);
        }
        return uploadedItems;
    }
    removeOne(item) {
        item.temporaryFile?.abortController?.abort();
        this.#progressItems.removeOne(item.unique);
        if (item.temporaryFile) {
            this._tempFileManager.removeOne(item.temporaryFile.temporaryUnique);
        }
    }
    remove(items) {
        const uniques = [];
        for (const item of items) {
            item.temporaryFile?.abortController?.abort();
            if (item.temporaryFile) {
                uniques.push(item.temporaryFile.temporaryUnique);
            }
        }
        this.#progressItems.remove(uniques);
        const temporaryUniques = items.map((x) => x.temporaryFile?.temporaryUnique).filter((x) => !!x);
        this._tempFileManager.remove(temporaryUniques);
    }
    removeAll() {
        for (const item of this.#progressItems.getValue()) {
            item.temporaryFile?.abortController?.abort();
        }
        this.#progressItems.setValue([]);
        this._tempFileManager.removeAll();
    }
    // Progress handling
    _setupProgress(items, parent) {
        const current = this.#progress.getValue();
        const currentItems = this.#progressItems.getValue();
        const uploadableItems = this.#prepareItemsAsUploadable({ folders: items.folders, files: items.files }, parent);
        this.#progressItems.setValue([...currentItems, ...uploadableItems]);
        this.#progress.setValue({ total: current.total + uploadableItems.length, completed: current.completed });
        return uploadableItems;
    }
    _updateStatus(item, status, statusMessage) {
        this.#progressItems.updateOne(item.unique, { status, statusMessage });
        const progress = this.#progress.getValue();
        this.#progress.update({ completed: progress.completed + 1 });
    }
    #updateProgress(item, progress) {
        this.#progressItems.updateOne(item.unique, { progress });
    }
    #prepareItemsAsUploadable;
    destroy() {
        this._tempFileManager.destroy();
        super.destroy();
    }
}
