import { getChat, getChats, getUserStatuses, getUserTags, getChatFilters, createChatFilter, updateChatFilter, deleteChatFilter, getChatFilterConfig, getChatByUserId } from "../api";
import { CHAT_PAGE_LIMIT } from "../utils/constant";
import { getCachedChats, persistChats, persistChat, updateChatSyncState, getCachedMetadata, persistMetadata } from "../utils/cache";
import { handleError } from "./dialog";
import { chatsStore, configStore, filterChatsStore, statusesStore, tagsStore, customFiltersStore, selectedChatStore } from "./store";
export async function handleGetChats(params) {
    const { start, spam, ignoreCache, ...rest } = params;
    const openChatByFilter = configStore.get('openChatByFilter');
    if (openChatByFilter && openChatByFilter.user_id) {
        const _chat = await handleGetChatByUserId(openChatByFilter.user_id);
        if (!_chat)
            return;
        configStore.set('openChatByFilter', null);
        selectedChatStore.set('selectedChat', _chat);
        return;
    }
    const loadedKeys = chatsStore.get('loadedKeys');
    if (start && loadedKeys.has(start))
        return;
    if (!start && !ignoreCache) {
        const cachedChats = await getCachedChats();
        if (cachedChats.length > 0 && chatsStore.get('chats').length === 0) {
            chatsStore.set('chats', cachedChats);
            updateChatFilterConfig(cachedChats);
        }
    }
    const { chats, next: nextKey } = await getChats({
        limit: CHAT_PAGE_LIMIT,
        start,
        ...rest,
        spam: spam ? spam : false,
    });
    let uniqueChats = [];
    if (start || !ignoreCache) {
        const chatMap = new Map();
        const existingChats = chatsStore.get('chats');
        for (const c of existingChats) {
            chatMap.set(c.id, c);
        }
        for (const c of chats) {
            chatMap.set(c.id, c);
        }
        uniqueChats = Array.from(chatMap.values());
    }
    else {
        uniqueChats = chats;
    }
    // Sort chats: pinned first, then last_message_at descending
    uniqueChats.sort((a, b) => {
        if (a.pin !== b.pin) {
            return a.pin ? -1 : 1;
        }
        const aTime = a.last_message_at ? new Date(a.last_message_at).getTime() : 0;
        const bTime = b.last_message_at ? new Date(b.last_message_at).getTime() : 0;
        return bTime - aTime;
    });
    chatsStore.set('chats', uniqueChats);
    chatsStore.set('next', nextKey);
    updateChatFilterConfig(uniqueChats);
    // if (openChatByFilter && uniqueChats.length > 0) {
    //   configStore.set('openChatByFilter', null);
    //   selectedChatStore.set('selectedChat', uniqueChats[0])
    // }
    if (start) {
        chatsStore.set('loadedKeys', new Set([...loadedKeys, start]));
    }
    persistChats(uniqueChats).then(() => updateChatSyncState());
}
export async function processGetChat(chat, from) {
    const filterChat = filterChatsStore.get('filterChat');
    let shouldRemove = false;
    if (filterChat?.tagIds && filterChat.tagIds.length > 0) {
        const hasMatchingTag = chat.tags?.some(tag => filterChat.tagIds.includes(tag.id));
        if (!hasMatchingTag) {
            shouldRemove = true;
        }
    }
    if (from === 'read') {
        if (filterChat?.read === false && (!chat.is_unread || !chat.mark_as_unread)) {
            shouldRemove = true;
        }
    }
    if (shouldRemove) {
        const _chats = structuredClone(chatsStore.get('chats')).filter(item => item.id !== chat.id);
        chatsStore.set('chats', _chats);
        persistChats(_chats).then(() => updateChatSyncState());
        if (_chats.length <= 5) {
            const nextKey = chatsStore.get('next');
            if (nextKey) {
                handleGetChats({ start: nextKey, ...filterChat });
            }
        }
        return;
    }
    if (chat.spam) {
        const filterChat = filterChatsStore.get('filterChat');
        if (!filterChat?.spam)
            return;
    }
    let _chats = structuredClone(chatsStore.get('chats'));
    const existChatIndex = _chats.findIndex(item => item.id === chat.id);
    if (existChatIndex !== -1 && _chats[existChatIndex].pin === chat.pin && _chats[existChatIndex].last_message_at === chat.last_message_at) {
        _chats[existChatIndex] = chat;
        chatsStore.set('chats', _chats);
        persistChat(chat);
        return chat;
    }
    if (existChatIndex !== -1) {
        _chats = _chats.filter((_, index) => index !== existChatIndex);
    }
    const chatTime = chat.last_message_at ? new Date(chat.last_message_at).getTime() : 0;
    let insertIndex = _chats.length;
    for (let i = 0; i < _chats.length; i++) {
        const currentChat = _chats[i];
        if (chat.pin && !currentChat.pin) {
            insertIndex = i;
            break;
        }
        if (!chat.pin && currentChat.pin) {
            continue;
        }
        const currentTime = currentChat.last_message_at ? new Date(currentChat.last_message_at).getTime() : 0;
        if (chatTime > currentTime) {
            insertIndex = i;
            break;
        }
    }
    _chats.splice(insertIndex, 0, chat);
    chatsStore.set('chats', _chats);
    updateChatFilterConfig(_chats);
    persistChat(chat);
    return chat;
}
export async function handleGetChatByUserId(userId) {
    try {
        const { chat } = await getChatByUserId({ userId });
        return processGetChat(chat);
    }
    catch (error) {
        handleError(error, 'Failed to load Chat by user id');
    }
}
export async function handleGetChat(sessionId, from) {
    try {
        const { chat } = await getChat({ sessionId });
        return processGetChat(chat, from);
    }
    catch (error) {
        handleError(error, 'Failed to load Chat');
    }
}
export async function handleGetChatWithFilter(sessionId) {
    try {
        const filterChat = filterChatsStore.get('filterChat');
        const { chats } = await getChats({
            ...filterChat,
            sessionId,
            limit: CHAT_PAGE_LIMIT,
            ignoreCache: true,
        });
        const chat = chats.find(item => item.id === sessionId);
        if (!chat)
            return;
        return processGetChat(chat);
    }
    catch (error) {
        handleError(error, 'Failed to load Chat with filter');
    }
}
export async function handleChatSocket(chatEvent) {
    const { sessionId, from, ...chat } = chatEvent;
    const isChatExist = chatsStore.get('chats').find(item => item.id === sessionId);
    if (isChatExist) {
        if (from === 'read') {
            handleGetChat(sessionId, from);
        }
        else {
            processGetChat(chat, from);
        }
    }
    else if (from !== 'read') {
        if (chat) {
            processGetChat(chat, from);
        }
        else {
            handleGetChatWithFilter(sessionId);
        }
    }
}
export async function handleGetUserStatuses(params) {
    try {
        if (params && (params.limit !== undefined || params.offset !== undefined || params.search !== undefined)) {
            const res = await getUserStatuses();
            // Assume getUserStatuses doesn't accept pagination yet or we just return it
            return res;
        }
        const cachedStatuses = await getCachedMetadata('statuses');
        if (cachedStatuses && statusesStore.get('statuses').length === 0) {
            statusesStore.set('statuses', cachedStatuses);
        }
        const { statuses } = await getUserStatuses();
        statusesStore.set('statuses', statuses);
        persistMetadata('statuses', statuses);
        return statuses;
    }
    catch (error) {
        if (statusesStore.get('statuses').length === 0) {
            handleError(error, 'Failed to load UserStatuses');
        }
    }
}
export async function handleGetUserTags(params) {
    try {
        if (params && (params.limit !== undefined || params.offset !== undefined || params.search !== undefined)) {
            const res = await getUserTags(params);
            return res;
        }
        const cachedTags = await getCachedMetadata('tags');
        if (cachedTags && tagsStore.get('tags').length === 0) {
            tagsStore.set('tags', cachedTags);
        }
        let allTags = [];
        let currentOffset = 0;
        const fetchLimit = 500;
        let hasMore = true;
        while (hasMore) {
            const { tags, total } = await getUserTags({ limit: fetchLimit, offset: currentOffset });
            allTags = allTags.concat(tags);
            if (allTags.length >= total || tags.length < fetchLimit) {
                hasMore = false;
            }
            else {
                currentOffset += fetchLimit;
            }
        }
        tagsStore.set('tags', allTags);
        persistMetadata('tags', allTags);
        return allTags;
    }
    catch (error) {
        if (tagsStore.get('tags').length === 0) {
            handleError(error, 'Failed to load UserTags');
        }
    }
}
// Custom Filter Handlers
export async function handleGetChatFilters() {
    try {
        customFiltersStore.set('loading', true);
        const { filters } = await getChatFilters();
        customFiltersStore.set('filters', filters);
        return filters;
    }
    catch (error) {
        handleError(error, 'Failed to load ChatFilters');
    }
    finally {
        customFiltersStore.set('loading', false);
    }
}
export async function handleCreateChatFilter(params) {
    try {
        const filter = await createChatFilter(params);
        const currentFilters = customFiltersStore.get('filters');
        customFiltersStore.set('filters', [...currentFilters, filter.filter]);
        return filter.filter;
    }
    catch (error) {
        handleError(error, 'Failed to create ChatFilter');
    }
}
export async function handleUpdateChatFilter(params) {
    try {
        const updatedFilter = await updateChatFilter(params);
        const currentFilters = customFiltersStore.get('filters');
        const updatedFilters = currentFilters.map(filter => filter.id === params.id ? updatedFilter.filter : filter);
        customFiltersStore.set('filters', updatedFilters);
        // Update selected filter if it's the one being updated
        const selectedFilter = customFiltersStore.get('selectedFilter');
        if (selectedFilter && selectedFilter.id === params.id) {
            customFiltersStore.set('selectedFilter', updatedFilter.filter);
            handleSelectChatFilter(updatedFilter.filter);
        }
        return updatedFilter.filter;
    }
    catch (error) {
        handleError(error, 'Failed to update ChatFilter');
    }
}
export async function handleDeleteChatFilter(id) {
    try {
        await deleteChatFilter({ id });
        const currentFilters = customFiltersStore.get('filters');
        const remainingFilters = currentFilters.filter(filter => filter.id !== id);
        customFiltersStore.set('filters', remainingFilters);
        // Clear selected filter if it was deleted
        const selectedFilter = customFiltersStore.get('selectedFilter');
        if (selectedFilter && selectedFilter.id === id) {
            customFiltersStore.set('selectedFilter', null);
            handleSelectChatFilter(null);
        }
        return remainingFilters;
    }
    catch (error) {
        handleError(error, 'Failed to delete ChatFilter');
    }
}
export function handleSelectChatFilter(filter) {
    customFiltersStore.set('selectedFilter', filter);
    if (filter) {
        // Apply filter to filterChatsStore
        filterChatsStore.set('filterChat', {
            ...filterChatsStore.get('filterChat'),
            search: filter.search,
            read: filter.read,
            type: filter.type,
            connections: filter.connections,
            lastAnswerByIds: filter.last_answer_by_ids,
            statusIds: filter.status_ids,
            tagIds: filter.tag_ids,
        });
        filterChatsStore.set('filterType', 'custom');
    }
    else {
        resetChatFilter();
    }
}
export function isUnread(chat) {
    return /*chat.unread_count > 0*/ chat.is_unread || chat.mark_as_unread;
}
export function getChatName(chatInfo) {
    if (!chatInfo)
        return '';
    if (chatInfo.type === 'user') {
        return chatInfo.user ? (chatInfo.user.nickname || chatInfo.user.name || '') : '';
    }
    if (chatInfo.type === 'group') {
        return chatInfo.group ? (chatInfo.group.nickname || chatInfo.group.name || '') : '';
    }
    return '';
}
export function getChatUserInfo(chatInfo) {
    if (!chatInfo)
        return '';
    if (chatInfo.type === 'user') {
        return chatInfo.user ? (chatInfo.user[chatInfo.field] || '') : '';
    }
    if (chatInfo.type === 'group') {
        return chatInfo.group ? (chatInfo.group[chatInfo.field] || '') : '';
    }
    return '';
}
export function getChatPicture(chatInfo) {
    if (!chatInfo)
        return '';
    if (chatInfo.type === 'user') {
        return chatInfo.user ? (chatInfo.user.picture_url || '') : '';
    }
    if (chatInfo.type === 'group') {
        return chatInfo.group ? (chatInfo.group.picture_url || '') : '';
    }
    return '';
}
export function getChatChannelPictureUrl(chatInfo) {
    if (!chatInfo)
        return '';
    let image = '';
    if (chatInfo.channel === 'zignal') {
        const theme = configStore.get('theme');
        image = `${theme}-zignal`;
    }
    else if (chatInfo.type === 'group') {
        image = 'line';
    }
    else {
        image = chatInfo.channel;
    }
    return `https://zwizai-platform.s3.ap-southeast-1.amazonaws.com/zignal-package/${image}.png`;
}
export function haveConnectionFromZwiz() {
    const connections = configStore.get('connectionList');
    return connections.some(connection => connection.type === 'zwiz');
}
export function haveConnectionFromZwizSME() {
    const connections = configStore.get('connectionList');
    return connections.some(connection => connection.type === 'zwiz' && connection.platform === 'sme');
}
export function haveConnectionFromZwizEnterprise() {
    const connections = configStore.get('connectionList');
    return connections.some(connection => connection.type === 'zwiz' && connection.platform === 'enterprise');
}
export function resetChatFilter() {
    const allValues = configStore.get('connectionList').flatMap(connection => connection.type === 'zwiz'
        ? connection.channels?.map(channel => channel.id) ?? []
        : [connection.id]);
    const connections = formatFilterConnection(allValues);
    filterChatsStore.set('filterChat', {
        ...filterChatsStore.get('filterChat'),
        search: null,
        read: null,
        type: null,
        connections: connections,
        lastAnswerByIds: null,
        statusIds: null,
        tagIds: null,
        userIds: null,
        zrmzCustomerIds: null,
        verifySlip: null,
        verifySlipValue: null,
        zrmz: null,
        zerva: null
    });
    filterChatsStore.set('filterType', 'quick');
    customFiltersStore.set('selectedFilter', null);
}
export async function handleGetChatFilterConfig() {
    const config = await getChatFilterConfig();
    filterChatsStore.set('filterConfig', config);
    return config;
}
export function updateChatFilterConfig(chats) {
    const haveGroupType = chats.some(chat => chat.type === 'group');
    if (haveGroupType) {
        const filterConfig = filterChatsStore.get('filterConfig');
        if (filterConfig) {
            filterChatsStore.set('filterConfig', {
                ...filterConfig,
                config: {
                    ...filterConfig.config,
                    isShowFilterType: true,
                }
            });
        }
    }
}
export function formatFilterConnection(connectionIds) {
    const connectionMap = new Map();
    for (const connectionId of connectionIds) {
        const connection = configStore.get('connectionList').find(conn => conn.type === 'zwiz'
            ? conn.channels.find(channel => channel.id === connectionId)
            : conn.id === connectionId);
        if (!connection)
            continue;
        if (connection.type === 'zwiz') {
            const selectedChannel = connection.channels.find(ch => ch.id === connectionId);
            if (selectedChannel) {
                const existing = connectionMap.get(selectedChannel.id) || [];
                connectionMap.set(selectedChannel.id, [...existing, selectedChannel.channel]);
            }
        }
        else {
            connectionMap.set(connection.id, [connection.type]);
        }
    }
    const connections = Array.from(connectionMap.entries()).map(([id, channels]) => ({
        id,
        channel: channels,
    }));
    return connections;
}
