import { Model } from '../core/Model.js';
import { exponentialBackoffDelay, shouldRetryApiError, retry } from './retry_logic.js';
import { fromError } from '../exceptions/builder.js';
import { LiveData } from '../reactive/LiveData.js';
import { filesSortFunction } from '../lib/files/Utils.js';
var ModelState;
(function (ModelState) {
    /**
     * Not doing anything.
     */
    ModelState[ModelState["idle"] = 0] = "idle";
    /**
     * Currently querying for file data.
     */
    ModelState[ModelState["reading"] = 1] = "reading";
    /**
     * Data was received and the result yielded no results or less than the limit.
     */
    ModelState[ModelState["ended"] = 2] = "ended";
})(ModelState || (ModelState = {}));
export default class FilesModel extends Model {
    oid;
    sdk;
    source = 'own';
    /**
     * The pagination cursor for files to use with the next query.
     */
    cursor;
    /**
     * The current state of the model.
     */
    state = ModelState.idle;
    /**
     * The list of file kinds to list.
     * Folders are always included.
     */
    kinds;
    /**
     * The variable parent folder key.
     * This is set when interacting with the UI or when the `folder` attribute change.
     */
    parent;
    get value() {
        return this.raw;
    }
    constructor(oid, sdk, source = 'own') {
        super();
        this.oid = oid;
        this.sdk = sdk;
        this.source = source;
        this.raw = new LiveData([]);
    }
    resetListState() {
        this.value.set([]);
        this.cursor = undefined;
        this.state = ModelState.idle;
    }
    scheduleQuery() {
        this.debounce(this.#query);
    }
    /**
     * Sets a parent and makes the query.
     * It does nothing if the parent is already set.
     *
     * @param key The key of the parent to query. Empty for root folder.
     */
    selectFolder(key) {
        if (this.parent === key) {
            return;
        }
        this.parent = key;
        this.resetListState();
        this.scheduleQuery();
    }
    /**
     * Finds a file by the key.
     * @param key The key of the file to find
     * @returns The file, if any
     */
    getFile(key) {
        return this.value.value.find((i) => i.key === key);
    }
    replaceFile(file) {
        const files = this.value.value;
        const index = files.findIndex((i) => i.key === file.key);
        if (index === -1) {
            files.push(file);
        }
        else {
            files[index] = file;
        }
        files.sort(filesSortFunction);
    }
    addFile(file) {
        const files = this.value.value;
        files.push(file);
        files.sort(filesSortFunction);
    }
    removeFile(key) {
        const files = this.value.value;
        const index = files.findIndex((i) => i.key === key);
        if (index === -1) {
            return;
        }
        files.splice(index, 1);
    }
    removeFiles(keys) {
        this.value.set(this.value.value.filter((file) => !keys.includes(file.key)));
    }
    async #query() {
        if (this.state !== ModelState.idle) {
            return;
        }
        this.state = ModelState.reading;
        try {
            const result = await this.listFiles();
            this.#processFileResults(result);
        }
        catch (e) {
            const err = fromError(e);
            this.notifyError(new Error(`Unable to load files list. ${err.message}`));
            this.state = ModelState.idle;
        }
        this.dispatchEvent(new Event('querycomplete'));
    }
    #processFileResults(result) {
        const { items, cursor } = result;
        if (cursor) {
            this.cursor = cursor;
        }
        if (!items.length) {
            this.state = ModelState.ended;
            return;
        }
        if (!this.value.value.length) {
            // we only sort the first page as later the user scrolls and sorting would change the order.
            items.sort(filesSortFunction);
        }
        this.value.set(this.value.value.concat(items));
        this.state = ModelState.idle;
    }
    async listFiles() {
        const operation = async () => {
            const opts = this.getPageQueryOptions();
            if (this.source === 'shared' && !this.parent) {
                return this.sdk.shared.list(this.oid, opts);
            }
            return this.sdk.file.list(this.oid, opts);
        };
        const retryOptions = {
            retries: this.retryCount,
            delayMs: exponentialBackoffDelay,
            shouldRetry: shouldRetryApiError,
        };
        return retry(operation, retryOptions);
    }
    getPageQueryOptions() {
        const { cursor: filesCursor, parent, limit, kinds } = this;
        const opts = {
        // descending: true,
        };
        if (filesCursor) {
            opts.cursor = filesCursor;
        }
        if (parent) {
            opts.parent = parent;
        }
        if (typeof limit === 'number' && limit) {
            opts.limit = limit;
        }
        if (Array.isArray(kinds) && kinds.length) {
            opts.filter = {
                op: 'OR',
                filters: kinds.map((kind) => ({
                    field: 'kind',
                    operator: 'eq',
                    value: kind,
                })),
            };
        }
        return opts;
    }
    async deleteFiles(keys) {
        if (!keys.length) {
            return;
        }
        const operation = async () => {
            await this.sdk.file.deleteBulk(this.oid, keys);
        };
        const retryOptions = {
            delayMs: exponentialBackoffDelay,
            shouldRetry: shouldRetryApiError,
            retries: this.retryCount,
        };
        try {
            await retry(operation, retryOptions);
            this.removeFiles(keys);
        }
        catch (e) {
            const err = fromError(e);
            this.notifyError(err);
        }
    }
}
//# sourceMappingURL=FilesModel.js.map