import { Fragment, Host, h } from "@stencil/core";
import { Icon } from "../internal-component/icon";
import { messagesStore, selectedChatStore } from "../../store/store";
import { getMessageMedia } from "../../api";
import { downloadFileMessage, getFileNameFromUrl, getFileTypeAndMimeFromUrl, getFileTypeFromMime } from "../../utils/func";
import { blobCache } from "../../utils/blob-cache";
import { MediaSkeleton } from "../internal-component/media-skeleton";
import { useTranslation } from "../../utils/utils";
import { media as MediaIcon, unsupportedMessageIcon as UnsupportedMessageIcon } from "../../utils/icon-svg";
import { initSocket, joinRoom, leaveRoom } from "../../utils/socket";
const FILE_SOCKET_NAMESPACE = '/file';
const FILE_SOCKET_TIMEOUT_MS = 30_000;
export class MessageMedia {
    item;
    messageMedia = null;
    showDialog = { open: false };
    hasError = false;
    isLoaded = false;
    uploadedFileIds = new Set();
    fileSocketJoinedRooms = [];
    onFileUpdateMap = new Map();
    fileSocketTimeoutMap = new Map();
    handleOpenDialog = ({ url, type }) => {
        this.showDialog = { open: true, url, type };
    };
    handleCloseDialog = () => {
        this.showDialog = { open: false };
    };
    handleError = () => {
        this.hasError = true;
    };
    handleLoad = () => {
        this.isLoaded = true;
    };
    handleGetMessageMedia = async () => {
        const { channel, id } = selectedChatStore.get('selectedChat');
        if (!this.item.id)
            return;
        const result = await getMessageMedia({
            channel: channel,
            sessionId: id,
            messageId: this.item.id,
            file: this.item.file
        });
        if (result) {
            this.messageMedia = result;
            return;
        }
        else {
            this.hasError = true;
        }
    };
    handleGetStickerUrl = (stickerId) => {
        this.messageMedia = {
            url: `https://stickershop.line-scdn.net/stickershop/v1/sticker/${stickerId}/android/sticker.png`,
            type: { type: 'image' }
        };
    };
    handleFileSocketUpload = () => {
        // Collect all files that are uploading
        const uploadingFiles = [];
        if (this.item.file && this.item.file.status === 'uploading') {
            uploadingFiles.push(this.item.file);
        }
        if (this.item.files) {
            for (const f of this.item.files) {
                if (f.status === 'uploading') {
                    uploadingFiles.push(f);
                }
            }
        }
        if (uploadingFiles.length === 0)
            return;
        const fileSocket = initSocket(FILE_SOCKET_NAMESPACE);
        for (const file of uploadingFiles) {
            const fileId = file.id;
            joinRoom(fileId, FILE_SOCKET_NAMESPACE);
            this.fileSocketJoinedRooms.push(fileId);
            const handler = (data) => {
                console.log(`[socket][${FILE_SOCKET_NAMESPACE}] File update received for ${fileId}:`, data);
                // Update the file status in messagesStore
                const messages = messagesStore.get('messages');
                const updatedMessages = messages.map(msg => {
                    if (msg.file?.id === fileId) {
                        return {
                            ...msg,
                            file: {
                                ...msg.file,
                                status: data.status,
                            },
                        };
                    }
                    if (msg.files?.some(f => f.id === fileId)) {
                        return {
                            ...msg,
                            files: msg.files.map(f => f.id === fileId
                                ? { ...f, status: data.status }
                                : f),
                        };
                    }
                    return msg;
                });
                messagesStore.set('messages', updatedMessages);
                // Clean up this specific file's socket resources
                this.cleanupFileSocketForId(fileId);
                // Re-fetch media if file is now uploaded
                if (data.status === 'uploaded' && data.is_active) {
                    // For single file messages, re-fetch media through the API
                    if (this.item.file?.id === fileId) {
                        this.handleGetMessageMedia();
                    }
                    // For files[] messages, update local state to trigger re-render
                    if (this.item.files?.some(f => f.id === fileId)) {
                        this.uploadedFileIds = new Set([...this.uploadedFileIds, fileId]);
                    }
                }
            };
            this.onFileUpdateMap.set(fileId, handler);
            fileSocket.on('update', handler);
            // Timeout: if no response within 30s, assume uploaded and re-fetch
            const timeoutId = setTimeout(() => {
                console.log(`[socket][${FILE_SOCKET_NAMESPACE}] Timeout for file ${fileId}, assuming uploaded`);
                handler({ status: 'uploaded', is_active: true });
            }, FILE_SOCKET_TIMEOUT_MS);
            this.fileSocketTimeoutMap.set(fileId, timeoutId);
        }
    };
    cleanupFileSocketForId = (fileId) => {
        const timeoutId = this.fileSocketTimeoutMap.get(fileId);
        if (timeoutId) {
            clearTimeout(timeoutId);
            this.fileSocketTimeoutMap.delete(fileId);
        }
        leaveRoom(fileId, FILE_SOCKET_NAMESPACE);
        const handler = this.onFileUpdateMap.get(fileId);
        if (handler) {
            const fileSocket = initSocket(FILE_SOCKET_NAMESPACE);
            fileSocket.off('update', handler);
            this.onFileUpdateMap.delete(fileId);
        }
        this.fileSocketJoinedRooms = this.fileSocketJoinedRooms.filter(id => id !== fileId);
    };
    cleanupFileSocket = () => {
        // Clean up all joined rooms
        for (const fileId of [...this.fileSocketJoinedRooms]) {
            this.cleanupFileSocketForId(fileId);
        }
    };
    componentWillLoad() {
        const { type, sticker } = this.item;
        if (['image', 'file', 'audio', 'video'].includes(type)) {
            if (this.item.file?.status === 'uploading') {
                this.handleFileSocketUpload();
            }
            else {
                this.handleGetMessageMedia();
            }
        }
        if (type === 'files') {
            const hasUploading = this.item.files?.some(f => f.status === 'uploading');
            if (hasUploading) {
                this.handleFileSocketUpload();
            }
        }
        if (type === 'sticker') {
            if (sticker && sticker.url) {
                this.messageMedia = {
                    url: sticker.url,
                    type: { type: 'image' },
                };
            }
            else if (this.item.stickerId) {
                this.handleGetStickerUrl(this.item.stickerId);
            }
        }
    }
    disconnectedCallback() {
        this.cleanupFileSocket();
        const chatInfo = selectedChatStore.get('selectedChat');
        if (chatInfo && this.item.id && ['image', 'file', 'files', 'audio', 'video'].includes(this.item.type)) {
            blobCache.release(chatInfo.channel, chatInfo.id, this.item.id);
        }
    }
    render() {
        const { type, attachments, file } = this.item;
        const _attachments = [];
        let isError = this.hasError;
        if (['image', 'sticker', 'file', 'audio', 'video'].includes(type) && this.messageMedia) {
            _attachments.push({
                type: (type === 'file' && ['image', 'audio', 'video'].includes(this.messageMedia.type.type)
                    ? this.messageMedia.type.type
                    : type),
                payload: {
                    url: this.messageMedia.url,
                    icon: this.messageMedia.type.icon,
                    fileType: this.messageMedia.type.type,
                    mimeType: this.messageMedia.type.mime,
                    extension: this.messageMedia.type.extension
                },
                file
            });
        }
        if (type === 'imagemap') {
            if (this.item.baseUrl) {
                _attachments.push({
                    type: 'image',
                    payload: {
                        url: this.item.baseUrl,
                        fileType: 'image'
                    }
                });
            }
            else {
                isError = true;
            }
        }
        if (type === 'attachments') {
            if (attachments && attachments.length > 0) {
                _attachments.push(...attachments);
            }
            else {
                isError = true;
            }
        }
        if (type === 'files') {
            if (this.item.files && this.item.files.length > 0) {
                this.item.files.forEach((file) => {
                    const fileType = getFileTypeFromMime(file.mime_type);
                    const isUploading = file.status === 'uploading' && !this.uploadedFileIds.has(file.id);
                    _attachments.push({
                        type: (['image', 'audio', 'video'].includes(fileType.type)
                            ? fileType.type
                            : 'file'),
                        payload: {
                            url: isUploading ? undefined : file.url,
                            icon: fileType.icon,
                            fileType: fileType.type,
                            mimeType: file.mime_type,
                            extension: fileType.extension
                        },
                        file
                    });
                });
            }
            else {
                isError = true;
            }
        }
        if (type === 'media_expired') {
            const t = useTranslation();
            return (h(Host, null, h("div", { class: "message-media-expired-wrapper" }, h("div", { class: "message-media-expired-icon" }, h(MediaIcon, null)), h("span", { class: "message-media-expired-text" }, t('chat_tab.media_expired')))));
        }
        if (type === 'unsupported') {
            const t = useTranslation();
            return (h(Host, null, h("div", { class: "message-media-unsupported-wrapper" }, h("div", { class: "message-media-unsupported-icon" }, h(UnsupportedMessageIcon, null)), h("span", { class: "message-media-unsupported-text" }, t('chat_tab.unsupported')))));
        }
        return (h(Host, null, h(Fragment, null, isError ? (h("div", { class: "message-media-error-wrapper bg-paper" }, h("p", { class: "text-sm text-theme-gray" }, "Media not available"), h(Icon, { name: "ImageOff", addClass: "message-media-icon" }))) : (h("div", { class: "message-media" }, _attachments.length > 0
            ? _attachments.map((attachment, index) => {
                const { payload } = attachment;
                if (!(payload && payload.url)) {
                    return (h("div", { class: `message-media-attachment-loading-wrapper ${attachment.type === 'file' ? 'h-20 w-42' : 'size-42'} bg-paper` }, h(Icon, { name: "LoaderCircle", addClass: `message-media-attachment-loading text-theme-gray` })));
                }
                if (['image', 'sticker', 'share'].includes(attachment.type)) {
                    //Image/Sticker from URL
                    let wrapperStyle = {};
                    let imgStyle = {};
                    if (this.item.type === 'imagemap' && this.item.baseSize) {
                        const { width, height } = this.item.baseSize;
                        wrapperStyle = {
                            width: `${width}px`,
                            height: 'auto',
                            maxWidth: '100%',
                            aspectRatio: `${width} / ${height}`
                        };
                        imgStyle = {
                            width: '100%',
                            height: '100%',
                        };
                    }
                    return (h("div", { class: "message-media-image-wrapper", style: wrapperStyle }, !this.isLoaded && h(MediaSkeleton, { addClass: "rounded-md" }), h("img", { key: index, src: payload.url, alt: "message-image", class: "message-media-card", style: imgStyle, onClick: () => this.handleOpenDialog({
                            url: payload.url,
                            type: attachment.type,
                        }), onError: this.handleError, onLoad: this.handleLoad, loading: "lazy" })));
                }
                if (['video', 'ig_reel', 'story_mention'].includes(attachment.type)) {
                    //Video from URL
                    return (h("video", { key: index, controls: true, muted: true, playsinline: true, src: payload.url, id: "message-video", class: "message-media-card", onClick: () => this.handleOpenDialog({
                            url: payload.url,
                            type: attachment.type,
                        }), onError: this.handleError }));
                }
                if (['audio'].includes(attachment.type)) {
                    //Audio from URL
                    return (h("audio", { key: index, controls: true, src: payload.url, preload: "metadata", id: "message-audio", class: "message-media-audio", onClick: () => this.handleOpenDialog({
                            url: payload.url,
                            type: attachment.type,
                        }), onError: this.handleError }));
                }
                if (attachment.type === 'file') {
                    //File from URL
                    let fileObject = { type: 'unknown', mime: 'application/octet-stream' };
                    if (attachment.payload && attachment.payload.fileType) {
                        fileObject = {
                            type: attachment.payload.fileType,
                            mime: attachment.payload.mimeType,
                            extension: attachment.payload.extension,
                            icon: attachment.payload.icon
                        };
                    }
                    else if (attachment.payload && attachment.payload.url) {
                        fileObject = getFileTypeAndMimeFromUrl(attachment.payload.url);
                        if (attachment.payload.icon) {
                            fileObject.icon = attachment.payload.icon;
                        }
                    }
                    const title = attachment.file ? attachment.file.name : getFileNameFromUrl(payload.url);
                    return (h("div", { class: "message-media-file-outer" }, h(MediaSkeleton, { addClass: "rounded-md" }), h("div", { class: "message-media-file-link", onClick: (e) => {
                            e.preventDefault();
                            downloadFileMessage({ url: payload.url, name: title });
                        } }, h("div", { class: "message-media-file-wrapper" }, fileObject.icon ? h("img", { src: `https://zwizai-platform.s3.ap-southeast-1.amazonaws.com/zignal-package/${fileObject.icon}.png`, alt: "file-icon", class: "message-media-file-icon" }) : h(Icon, { name: "File", addClass: "message-media-icon" }), h("span", { class: "message-media-file-title", title: title }, title)))));
                }
                return null;
            })
            : h("div", { class: "h-5 w-54" }, h(MediaSkeleton, { addClass: "rounded-md" })))), this.showDialog.open && (h("div", { class: "dialog-backdrop" }, h("dialog-preview-media", { dialogType: this.showDialog.type, url: this.showDialog.url || '', onClose: this.handleCloseDialog }))))));
    }
    static get is() { return "message-media"; }
    static get originalStyleUrls() {
        return {
            "$": ["message-media.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["message-media.css"]
        };
    }
    static get properties() {
        return {
            "item": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "ChatMessageItem",
                    "resolved": "{ id?: string; message_id?: string; sender: ChatSender; created_at: Date; updated_at: Date; message_at: Date; text: string; type?: MessageType; event_type?: MessageType; stickerId?: string; reply_message?: ChatMessageItem; attachments?: MessageAttachment[]; template?: ChatMessageTemplate; elements?: MessageElement; altText?: string; baseUrl?: string; baseSize?: { width: number; height: number; }; contents?: any; error_data?: string | MessageError; action?: \"remove\" | \"add\" | \"change\"; item?: ActivityLogItem; from?: ActivityLogItem; to?: ActivityLogItem; translatedText?: string; isSending?: boolean; menu_list?: QuickMessageTemplateMenuListItem[]; buttons?: QuickMessageTemplateButton[]; event_name?: BillingItemEvent; value?: string | number; currency?: string; file?: FileMessage; files?: FileMessage[]; isTranslateFromInput?: boolean; interactive?: InteractivePayload; sticker?: ChatSticker; referral?: TReferral; feed?: TFeed; location?: TLocation; mention?: TMention; follow?: { isUnblocked: boolean; }; postback?: { data: string; }; }",
                    "references": {
                        "ChatMessageItem": {
                            "location": "import",
                            "path": "../../store/type",
                            "id": "src/store/type.ts::ChatMessageItem",
                            "referenceLocation": "ChatMessageItem"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false
            }
        };
    }
    static get states() {
        return {
            "messageMedia": {},
            "showDialog": {},
            "hasError": {},
            "isLoaded": {},
            "uploadedFileIds": {}
        };
    }
}
