import type {
    ContextMenuItemHandlerProps,
    ConversationPreviewListId,
} from '~/app/ui/components/partials/conversation-nav/types';
import type {ConversationPreviewListProps} from '~/app/ui/components/partials/conversation-preview-list/props';
import {transformMessageSenderProps} from '~/app/ui/utils/sender';
import {ConversationCategory, ConversationVisibility} from '~/common/enum';
import {conversationCompareFn} from '~/common/model/utils/conversation';
import {tag, type u53} from '~/common/types';
import {unreachable} from '~/common/utils/assert';
import type {Remote} from '~/common/utils/endpoint';
import type {IQueryableStore} from '~/common/utils/store';
import {derive} from '~/common/utils/store/derived-store';
import type {RemoteSetStore} from '~/common/utils/store/set-store';
import type {ConversationListItemViewModelBundle} from '~/common/viewmodel/conversation/list/item';

/**
 * Transforms the `SetStore` of {@link ConversationListItemViewModelBundle}s, which is sent by the
 * ViewModel, to a new store compatible with the shape of props expected by
 * `ConversationPreviewList` component.
 */
export function conversationListItemSetStoreToConversationPreviewListPropsStore(
    conversationListItemSetStore: RemoteSetStore<Remote<ConversationListItemViewModelBundle>>,
): IQueryableStore<Pick<ConversationPreviewListProps<ContextMenuItemHandlerProps>, 'items'>> {
    return derive(
        [conversationListItemSetStore],
        ([{currentValue: conversationListItemSet}], getAndSubscribe) => ({
            items: [...conversationListItemSet]
                // Remove deleted / hidden conversations.
                .filter((conversation) => {
                    const receiver = conversation.viewModelStore.get().receiver;
                    return (
                        getAndSubscribe(conversation.viewModelStore, ['lastUpdate', 'visibility'])
                            .lastUpdate !== undefined &&
                        // This is a sanity check. When a contact is deleted, last updated is set to
                        // undefined anyway.
                        !(
                            receiver.type === 'contact' &&
                            receiver.acquaintanceLevel === 'group-or-deleted'
                        )
                    );
                })
                .sort((a, b) =>
                    conversationCompareFn(
                        getAndSubscribe(a.viewModelStore, ['lastUpdate', 'visibility']),
                        getAndSubscribe(b.viewModelStore, ['lastUpdate', 'visibility']),
                    ),
                )
                .map((viewModelBundle) =>
                    derive(
                        [viewModelBundle.viewModelStore],
                        ([{currentValue: viewModel}], getAndSubscribe_) => {
                            const lastMessageViewModelStore = viewModel.lastMessage?.viewModelStore;
                            const lastMessageViewModel =
                                lastMessageViewModelStore === undefined
                                    ? undefined
                                    : getAndSubscribe_(lastMessageViewModelStore);
                            let lastMessage: ReturnType<
                                ConversationPreviewListProps['items'][u53]['get']
                            >['lastMessage'] = undefined;
                            if (lastMessageViewModel !== undefined) {
                                switch (lastMessageViewModel.type) {
                                    case 'deleted-message':
                                        lastMessage = {
                                            sender: transformMessageSenderProps(
                                                lastMessageViewModel,
                                            ),
                                            status: lastMessageViewModel.status,
                                            direction: lastMessageViewModel.direction,
                                        };
                                        break;

                                    case 'regular-message':
                                        lastMessage = {
                                            file: lastMessageViewModel.file,
                                            sender: transformMessageSenderProps(
                                                lastMessageViewModel,
                                            ),
                                            status: lastMessageViewModel.status,
                                            text: lastMessageViewModel.text,
                                            direction: lastMessageViewModel.direction,
                                            pollData: lastMessageViewModel.pollData,
                                        };
                                        break;

                                    case 'status-message':
                                        throw new Error(
                                            'TODO(DESK-1517): Implement status messages in last message previews',
                                        );

                                    default:
                                        unreachable(lastMessageViewModel);
                                }
                            }

                            return {
                                call: viewModel.call,
                                handlerProps: {
                                    viewModelBundle,
                                },
                                id: tag<ConversationPreviewListId>(viewModel.id),
                                isArchived:
                                    viewModel.visibility === ConversationVisibility.ARCHIVED,
                                isPinned: viewModel.visibility === ConversationVisibility.PINNED,
                                isPrivate: viewModel.category === ConversationCategory.PROTECTED,
                                isTyping: viewModel.isTyping,
                                lastMessage,
                                receiver: viewModel.receiver,
                                totalMessageCount: viewModel.totalMessageCount,
                                unreadMessageCount: viewModel.unreadMessageCount,
                            };
                        },
                    ),
                ),
        }),
    );
}
