var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _MediaController_instances, _MediaController_host, _MediaController_setValidation, _MediaController_getRandomId, _MediaController_fireChangeEvent, _MediaController_handleImageResponse, _MediaController_handleImage, _MediaController_upload, _MediaController_createMediaItem, _MediaController_createImage, _MediaController_isVideo, _MediaController_dispatchAlert, _MediaController_filterValidFiles, _MediaController_getDefaultErrorMessage, _MediaController_handleError;
import { msg } from '@lit/localize';
import { customEvent } from '@reddit/faceplate/lib/custom-event.js';
import { ALLOWED_VIDEO_MIMETYPES, validateImageFile } from './validateMedia.js';
export var MediaStatus;
(function (MediaStatus) {
    MediaStatus["loading"] = "loading";
    MediaStatus["success"] = "success";
})(MediaStatus || (MediaStatus = {}));
export var PostType;
(function (PostType) {
    PostType["image"] = "image";
})(PostType || (PostType = {}));
export const MAX_FILE_COUNT = 20;
function getMediaUrl(mediaItem) {
    return mediaItem.value?.url || '';
}
export class MediaController {
    constructor(host, options) {
        _MediaController_instances.add(this);
        this.media = [];
        _MediaController_host.set(this, void 0);
        _MediaController_setValidation.set(this, void 0);
        __classPrivateFieldSet(this, _MediaController_host, host, "f");
        __classPrivateFieldSet(this, _MediaController_setValidation, options?.setValidation ?? (() => { }), "f");
    }
    getValue() {
        const validFiles = this.media.filter((media) => media.status === MediaStatus.success);
        if (validFiles.length === 0) {
            return '';
        }
        if (validFiles.length === 1) {
            return getMediaUrl(validFiles[0]);
        }
        return JSON.stringify(validFiles.map(getMediaUrl));
    }
    setValue(newValue) {
        const val = JSON.parse(newValue);
        this.media = val;
    }
    async handleMedia(files) {
        try {
            const seed = this.media.length;
            const validFiles = __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_filterValidFiles).call(this, files);
            if (validFiles.length > 0) {
                // marking the input as invalid during the upload
                // the message is not visible to the end user
                __classPrivateFieldGet(this, _MediaController_setValidation, "f").call(this, UPLOAD_IN_PROGRESS_VALIDATION_MESSAGE);
                const mediaItems = [];
                for (const file of validFiles) {
                    mediaItems.push(__classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_handleImage).call(this, file));
                }
                this.media = this.media.concat(mediaItems);
                __classPrivateFieldGet(this, _MediaController_host, "f").requestUpdate('mediaLength', seed);
                const mediaResponse = await Promise.all(mediaItems.map((item) => item.mediaResponse));
                // set validity when the upload is finished
                if (mediaResponse.every((response) => !response?.error && response?.url)) {
                    __classPrivateFieldGet(this, _MediaController_setValidation, "f").call(this, '');
                }
                else {
                    __classPrivateFieldGet(this, _MediaController_setValidation, "f").call(this, UPLOAD_ERROR_VALIDATION_MESSAGE);
                }
                __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_handleImageResponse).call(this, mediaResponse, seed);
                __classPrivateFieldGet(this, _MediaController_host, "f").requestUpdate();
            }
        }
        catch (error) {
            if (!(error instanceof Error)) {
                console.error(error);
                __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_handleError).call(this, msg('Something went wrong. Please try again later', {
                    desc: 'Unknown error uploading the file',
                }));
                return;
            }
            __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_handleError).call(this, error.message);
        }
    }
    getPostType() {
        return PostType.image;
    }
    hasLoadingMedia() {
        return this.media.some((media) => media.status === MediaStatus.loading);
    }
    removeMedia(index) {
        this.media.splice(index, 1);
    }
}
_MediaController_host = new WeakMap(), _MediaController_setValidation = new WeakMap(), _MediaController_instances = new WeakSet(), _MediaController_getRandomId = function _MediaController_getRandomId(filename) {
    // match all temporary media IDs with that filename
    // eslint-disable-next-line security/detect-non-literal-regexp
    const regex = new RegExp(`^${filename}-(?<id>\\d+)$`);
    // find the highest suffix and increment it by one
    const suffix = 1 +
        this.media.reduce((currSuffix, media) => {
            const match = media.id.match(regex);
            return match ? Math.max(currSuffix, parseInt(match.groups.id, 10)) : currSuffix;
        }, -1);
    return `${filename}-${suffix}`;
}, _MediaController_fireChangeEvent = function _MediaController_fireChangeEvent() {
    const event = new Event('change', { bubbles: true });
    __classPrivateFieldGet(this, _MediaController_host, "f").dispatchEvent(event);
}, _MediaController_handleImageResponse = function _MediaController_handleImageResponse(mediaResponses, seed) {
    let success = false;
    const failedItemsIndexes = [];
    for (const [i, mediaResponse] of mediaResponses.entries()) {
        const index = seed + i;
        const { url, mediaId, error = null } = mediaResponse ?? {};
        const media = this.media[index];
        if (url && mediaId) {
            const galleryItem = { mediaId, url };
            media.id = mediaId;
            media.value = galleryItem;
            media.status = MediaStatus.success;
            success = true;
        }
        else {
            __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_dispatchAlert).call(this, error);
            failedItemsIndexes.push(index);
        }
    }
    if (failedItemsIndexes.length > 0) {
        this.media = this.media.filter((_, index) => !failedItemsIndexes.includes(index));
    }
    if (success) {
        __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_fireChangeEvent).call(this);
    }
    else {
        __classPrivateFieldGet(this, _MediaController_host, "f").requestUpdate('mediaLength', this.media.length - 1);
    }
}, _MediaController_handleImage = function _MediaController_handleImage(file) {
    const IMAGE_UPLOAD_ERROR = msg('Unable to upload image', {
        desc: 'Error: unable to upload image file',
    });
    const mediaItem = __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_createImage).call(this, file);
    const validation = validateImageFile(file);
    if (!validation.valid) {
        mediaItem.mediaResponse = Promise.resolve({
            error: validation.error ?? IMAGE_UPLOAD_ERROR,
        });
    }
    else {
        mediaItem.mediaResponse = __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_upload).call(this, file);
    }
    return mediaItem;
}, _MediaController_upload = async function _MediaController_upload(blob) {
    // consumer is responsible for implementing the upload logic.
    // we send null here, but parent assigns a promise to the `uploadRequest` field
    // events are handled synchronously, so we can await this promise and get the upload result
    const imageUploadEvent = customEvent('devvit-image-upload', {
        blob,
        uploadRequest: null,
    });
    __classPrivateFieldGet(this, _MediaController_host, "f").dispatchEvent(imageUploadEvent);
    const response = await imageUploadEvent.detail.uploadRequest;
    if (!response) {
        return Promise.resolve({
            error: 'Image upload failed',
        });
    }
    return response;
}, _MediaController_createMediaItem = function _MediaController_createMediaItem(file) {
    const src = URL.createObjectURL(file);
    return {
        id: __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_getRandomId).call(this, file.name),
        file,
        src,
        status: MediaStatus.loading,
    };
}, _MediaController_createImage = function _MediaController_createImage(file) {
    return {
        ...__classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_createMediaItem).call(this, file),
        type: 'still',
    };
}, _MediaController_isVideo = function _MediaController_isVideo(file) {
    if (!file)
        return false;
    return ALLOWED_VIDEO_MIMETYPES.includes(file.type);
}, _MediaController_dispatchAlert = function _MediaController_dispatchAlert(message) {
    __classPrivateFieldGet(this, _MediaController_host, "f").dispatchEvent(customEvent('faceplate-alert', {
        level: 4, // warning
        message: message ?? __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_getDefaultErrorMessage).call(this),
    }));
}, _MediaController_filterValidFiles = function _MediaController_filterValidFiles(files) {
    let mediaFiles = files;
    const hasVideoInSelectedFiles = files.some((file) => __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_isVideo).call(this, file));
    const isMultipleSelection = files.length > 1;
    const isValidMediaPresent = this.media.length > 0;
    if (isMultipleSelection || isValidMediaPresent) {
        const GALLERY_NOT_ALLOWED_ERROR = msg(`Only one file can be used for the image input`, {
            desc: 'Error: Multiple files cannot be added to image input',
        });
        __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_dispatchAlert).call(this, GALLERY_NOT_ALLOWED_ERROR);
        return [];
    }
    if (hasVideoInSelectedFiles && (isValidMediaPresent || isMultipleSelection)) {
        const GALLERY_CONTAIN_VIDEO_ERROR = msg('Image input can only contain images', {
            desc: 'Error when users upload non-image media files to image input',
        });
        __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_dispatchAlert).call(this, GALLERY_CONTAIN_VIDEO_ERROR);
        mediaFiles = files.filter((file) => !__classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_isVideo).call(this, file));
    }
    return mediaFiles;
}, _MediaController_getDefaultErrorMessage = function _MediaController_getDefaultErrorMessage() {
    return msg('There was an error uploading the file', {
        desc: 'Generic error message when file upload fails',
        id: 'generic-error-message-for-uploading-file',
    });
}, _MediaController_handleError = function _MediaController_handleError(err) {
    const error = err || __classPrivateFieldGet(this, _MediaController_instances, "m", _MediaController_getDefaultErrorMessage).call(this);
    __classPrivateFieldGet(this, _MediaController_setValidation, "f").call(this, error);
};
// should be used for validation message only
export const UPLOAD_ERROR_VALIDATION_MESSAGE = 'Media upload failed';
export const UPLOAD_IN_PROGRESS_VALIDATION_MESSAGE = 'Image upload is in progress';
//# sourceMappingURL=media-controller.js.map