package dev.meloda.fast.messageshistory

import android.content.Context
import android.os.Bundle
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.conena.nanokt.collections.indexOfFirstOrNull
import dev.meloda.fast.common.extensions.getParcelableCompat
import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.common.provider.ResourceProvider
import dev.meloda.fast.datastore.AppSettings
import dev.meloda.fast.domain.ConvoUseCase
import dev.meloda.fast.domain.GetMessageReadPeersUseCase
import dev.meloda.fast.domain.LongPollUpdatesParser
import dev.meloda.fast.domain.MessagesUseCase
import dev.meloda.fast.messageshistory.model.ActionMode
import dev.meloda.fast.messageshistory.model.MessageDialog
import dev.meloda.fast.messageshistory.model.MessageNavigation
import dev.meloda.fast.messageshistory.model.MessageOption
import dev.meloda.fast.messageshistory.model.MessagesHistoryScreenState
import dev.meloda.fast.messageshistory.navigation.MessagesHistory
import dev.meloda.fast.model.BaseError
import dev.meloda.fast.model.api.domain.VkMessage
import dev.meloda.fast.ui.model.vk.MessageUiItem
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

class MessagesHistoryViewModelImpl(
    private val applicationContext: Context,
    private val messagesUseCase: MessagesUseCase,
    private val convoUseCase: ConvoUseCase,
    private val resourceProvider: ResourceProvider,
    private val getMessageReadPeersUseCase: GetMessageReadPeersUseCase,
    updatesParser: LongPollUpdatesParser,
    savedStateHandle: SavedStateHandle
) : MessagesHistoryViewModel, ViewModel() {

    override val screenState = MutableStateFlow(MessagesHistoryScreenState.EMPTY)
    override val navigation = MutableStateFlow<MessageNavigation?>(null)
    override val dialog = MutableStateFlow<MessageDialog?>(null)
    override val selectedMessages = MutableStateFlow<List<VkMessage>>(emptyList())

    override val showKeyboard = MutableStateFlow(false)

    override val isNeedToScrollToIndex = MutableStateFlow<Int?>(null)

    override val baseError = MutableStateFlow<BaseError?>(null)
    override val imagesToPreload = MutableStateFlow<List<String>>(emptyList())

    override val currentOffset = MutableStateFlow(0)

    override val canPaginate = MutableStateFlow(false)

    override val messages = MutableStateFlow<List<VkMessage>>(emptyList())
    override val uiMessages = MutableStateFlow<List<MessageUiItem>>(emptyList())

    private val pinnedMessageHandler = MessagesHistoryPinnedMessageHandler(
        screenState = screenState
    )

    private val messageActions = MessagesHistoryMessageActions(
        applicationContext = applicationContext,
        viewModelScope = viewModelScope,
        messagesUseCase = messagesUseCase,
        resourceProvider = resourceProvider,
        screenState = screenState,
        messages = messages,
        baseError = baseError,
        showKeyboard = showKeyboard,
        dialog = dialog,
        syncUiMessages = ::syncUiMessages,
        onPinnedMessageChanged = pinnedMessageHandler::update
    )

    private val loaders = MessagesHistoryLoaders(
        convoUseCase = convoUseCase,
        messagesUseCase = messagesUseCase,
        resourceProvider = resourceProvider,
        screenState = screenState,
        messages = messages,
        imagesToPreload = imagesToPreload,
        canPaginate = canPaginate,
        baseError = baseError,
        scope = viewModelScope,
        syncUiMessages = ::syncUiMessages,
        onPinnedMessage = pinnedMessageHandler::update
    )

    private val longPollEventHandler = MessagesHistoryLongPollEventHandler(
        screenState = screenState,
        messages = messages
    ) {
        syncUiMessages()
    }

    init {
        val arguments = MessagesHistory.from(savedStateHandle).arguments

        screenState.setValue { old -> old.copy(convoId = arguments.convoId) }

        loaders.loadConvo()
        loaders.loadMessagesHistory(currentOffset.value)

        updatesParser.onNewMessage(longPollEventHandler::onNewMessage)
        updatesParser.onMessageEdited(longPollEventHandler::onMessageEdited)
        updatesParser.onMessageIncomingRead(longPollEventHandler::onReadIncoming)
        updatesParser.onMessageOutgoingRead(longPollEventHandler::onReadOutgoing)
        updatesParser.onMessageDeleted(longPollEventHandler::onMessageDeleted)
        updatesParser.onMessageRestored(longPollEventHandler::onMessageRestored)
        updatesParser.onMessageMarkedAsImportant(longPollEventHandler::onMessageMarkedAsImportant)
        updatesParser.onMessageMarkedAsSpam(longPollEventHandler::onMessageMarkedAsSpam)
        updatesParser.onMessageMarkedAsNotSpam(longPollEventHandler::onMessageMarkedAsNotSpam)
    }

    override fun onNavigationConsumed() {
        navigation.setValue { null }
    }

    override fun onTopBarClicked() {
        val cmId = messages.value.firstOrNull()?.cmId ?: return

        navigation.setValue {
            MessageNavigation.ChatMaterials(
                peerId = screenState.value.convoId,
                cmId = cmId
            )
        }
    }

    override fun onDialogConfirmed(dialog: MessageDialog, bundle: Bundle) {
        onDialogDismissed(dialog)

        when (dialog) {
            is MessageDialog.MessageOptions -> Unit

            is MessageDialog.MessageDelete -> {
                val deleteForEveryone = bundle.getBoolean("everyone")

                if (dialog.message.id <= 0) {
                    val newMessages = messages.value.toMutableList()
                    newMessages.remove(dialog.message)
                    messages.setValue { newMessages }
                    syncUiMessages()
                    return
                }

                messageActions.deleteMessage(
                    messageIds = listOf(dialog.message.id),
                    deleteForAll = deleteForEveryone
                )
            }

            is MessageDialog.MessagesDelete -> {
                val deleteForEveryone = bundle.getBoolean("everyone")

                val failedMessages = dialog.messages.filter { it.id <= 0 }
                val messageIdsToDelete =
                    dialog.messages
                        .filter { it.id > 0 }
                        .map(VkMessage::id)

                messageActions.deleteMessage(
                    messageIds = messageIdsToDelete,
                    deleteForAll = deleteForEveryone,
                    onSuccess = {
                        val newMessages = messages.value.toMutableList()
                        newMessages.removeAll(failedMessages)
                        messages.setValue { newMessages }
                        selectedMessages.setValue { emptyList() }
                        syncUiMessages()
                    }
                )
            }

            is MessageDialog.MessagePin -> {
                messageActions.pinMessage(dialog.messageId)
            }

            is MessageDialog.MessageUnpin -> {
                messageActions.unpinMessage(dialog.messageId)
            }

            is MessageDialog.MessageMarkImportance -> {
                messageActions.markAsImportant(
                    messageIds = listOf(dialog.message.id),
                    important = dialog.isImportant
                )
            }

            is MessageDialog.MessageSpam -> {
                if (dialog.isSpam) {
                    messageActions.deleteMessage(
                        messageIds = listOf(dialog.message.id),
                        spam = true
                    )
                } else {
                    // TODO: 29-Mar-25, Danil Nikolaev: report as not spam
                }
            }
        }
    }

    override fun onDialogDismissed(dialog: MessageDialog) {
        this.dialog.setValue { null }
    }

    override fun onDialogItemPicked(dialog: MessageDialog, bundle: Bundle) {
        when (dialog) {
            is MessageDialog.MessageOptions -> {
//                val messageId = bundle.getLong("messageId")
                val cmId = bundle.getLong("cmId")

                when (val option = bundle.getParcelableCompat("option", MessageOption::class)) {
                    null -> Unit

                    MessageOption.Retry -> {
                        // TODO: 28-Mar-25, Danil Nikolaev: retry sending
                    }

                    MessageOption.Reply -> messageActions.replyToMessage(cmId)

                    MessageOption.ForwardHere -> {

                    }

                    MessageOption.Forward -> {

                    }

                    MessageOption.Pin -> {
                        this.dialog.setValue {
                            MessageDialog.MessagePin(dialog.message.id)
                        }
                    }

                    MessageOption.Unpin -> {
                        this.dialog.setValue {
                            MessageDialog.MessageUnpin(dialog.message.id)
                        }
                    }

                    MessageOption.Read -> {
                        messageActions.readMessage(dialog.message)
                    }

                    MessageOption.Copy -> {
                        messageActions.copyMessage(dialog.message)
                    }

                    MessageOption.MarkAsImportant,
                    MessageOption.UnmarkAsImportant -> {
                        this.dialog.setValue {
                            MessageDialog.MessageMarkImportance(
                                message = dialog.message,
                                isImportant = option is MessageOption.MarkAsImportant
                            )
                        }
                    }

                    MessageOption.MarkAsSpam,
                    MessageOption.UnmarkAsSpam -> {
                        this.dialog.setValue {
                            MessageDialog.MessageSpam(
                                message = dialog.message,
                                isSpam = option is MessageOption.MarkAsSpam
                            )
                        }
                    }

                    MessageOption.Edit -> {
                        messageActions.editMessage(cmId)
                        syncUiMessages()
                    }

                    MessageOption.Delete -> {
                        this.dialog.setValue {
                            MessageDialog.MessageDelete(dialog.message)
                        }
                    }
                }
            }

            is MessageDialog.MessageDelete -> Unit
            is MessageDialog.MessageUnpin -> Unit
            is MessageDialog.MessageMarkImportance -> Unit
            is MessageDialog.MessageSpam -> Unit
            is MessageDialog.MessagePin -> Unit
            is MessageDialog.MessagesDelete -> Unit
        }
    }

    override fun onScrolledToIndex() {
        isNeedToScrollToIndex.setValue { null }
    }

    override fun onCloseButtonClicked() {
        if (selectedMessages.value.isNotEmpty()) {
            selectedMessages.setValue { emptyList() }
        }

        if (screenState.value.editCmId != null) {
            messageActions.stopEditMessage()
        }

        syncUiMessages()
    }

    override fun onRefresh() {
        loaders.loadMessagesHistory(offset = 0)
    }

    override fun onAttachmentButtonClicked() {

    }

    override fun onMessageInputChanged(newText: TextFieldValue) {
        screenState.setValue { old ->
            old.copy(
                message = newText,
                actionMode =
                    when {
                        screenState.value.editCmId != null -> {
                            // TODO: 13/03/2026, Danil Nikolaev: also check if attachments is empty
                            if (newText.text.trim().isEmpty()) {
                                ActionMode.DELETE
                            } else {
                                ActionMode.EDIT
                            }
                        }

                        newText.text.trim().isEmpty() -> ActionMode.RECORD_AUDIO
                        else -> ActionMode.SEND
                    }
            )
        }
        updateStyles()
    }

    override fun onEmojiButtonLongClicked() {
        AppSettings.Features.fastText.takeIf { it.isNotBlank() }?.let { text ->
            val newText = "${screenState.value.message.text}$text"
            onMessageInputChanged(
                TextFieldValue(text = newText, selection = TextRange(newText.length))
            )
        }
    }

    override fun onActionButtonClicked() {
        when (screenState.value.actionMode) {
            ActionMode.DELETE -> messageActions.confirmDeleteCurrentEditMessage()

            ActionMode.EDIT -> messageActions.editCurrentEditMessage()

            ActionMode.RECORD_AUDIO -> {
                screenState.setValue { it.copy(actionMode = ActionMode.RECORD_VIDEO) }
            }

            ActionMode.RECORD_VIDEO -> {
                screenState.setValue { it.copy(actionMode = ActionMode.RECORD_AUDIO) }
            }

            ActionMode.SEND -> messageActions.sendMessage()
        }
    }

    override fun onPaginationConditionsMet() {
        currentOffset.update { messages.value.size }
        loaders.loadMessagesHistory(currentOffset.value)
    }

    override fun onMessageClicked(messageId: Long) {
        val currentMessage = messages.value.firstOrNull { it.id == messageId } ?: return

        if (selectedMessages.value.isNotEmpty()) {
            val isSelected = selectedMessages.value.contains(currentMessage)

            selectedMessages.setValue { old ->
                old.toMutableList().also {
                    if (isSelected) {
                        it.remove(currentMessage)
                    } else {
                        it.add(currentMessage)
                    }
                }
            }
            syncUiMessages()
        } else {
            dialog.setValue {
                MessageDialog.MessageOptions(currentMessage)
            }
        }
    }

    override fun onMessageLongClicked(messageId: Long) {
        val currentMessage = messages.value.firstOrNull { it.id == messageId } ?: return

        val isSelected = selectedMessages.value.contains(currentMessage)
        if (isSelected) return

        selectedMessages.setValue { old ->
            old.toMutableList().also {
                it.add(currentMessage)
            }
        }
        syncUiMessages()
    }

    override fun onPinnedMessageClicked(messageId: Long) {
        val uiMessages = uiMessages.value
        val messageIndex = uiMessages.indexOfFirstOrNull {
            it is MessageUiItem.Message && it.id == messageId
        }

        if (messageIndex == null) { // сообщения нет в списке
            // pizdets
        } else {
            isNeedToScrollToIndex.setValue { messageIndex }
        }
    }

    override fun onUnpinMessageClicked() {
        val pinnedMessageId = screenState.value.pinnedMessage?.id ?: return
        dialog.setValue {
            MessageDialog.MessageUnpin(pinnedMessageId)
        }
    }

    override fun onEditSelectedMessageClicked() {
        val cmId = selectedMessages.value.firstOrNull()?.cmId ?: return

        selectedMessages.setValue { emptyList() }

        messageActions.editMessage(cmId)

        syncUiMessages()
    }

    override fun onDeleteSelectedMessagesClicked() {
        dialog.setValue {
            MessageDialog.MessagesDelete(selectedMessages.value)
        }
    }

    override fun onBoldClicked() {
        messageActions.onBoldClicked()
    }

    override fun onItalicClicked() {
        messageActions.onItalicClicked()
    }

    override fun onUnderlineClicked() {
        messageActions.onUnderlineClicked()
    }

    override fun onLinkClicked() {

    }

    override fun onRegularClicked() {
        messageActions.onRegularClicked()
    }

    override fun onReplyCloseClicked() {
        messageActions.onReplyCloseClicked()
    }

    override fun onRequestReplyToMessage(cmId: Long) {
        messageActions.replyToMessage(cmId)
    }

    override fun onKeyboardShown() {
        showKeyboard.setValue { false }
    }

    override suspend fun loadMessageReadPeers(peerId: Long, cmId: Long): Int =
        suspendCancellableCoroutine {
            viewModelScope.launch {
                getMessageReadPeersUseCase
                    .invoke(peerId = peerId, cmId = cmId)
                    .listenValue(viewModelScope) { state ->
                        state.processState(
                            error = { error ->
                                it.resume(-1)
                            },
                            success = { count ->
                                it.resume(count)
                            }
                        )
                    }
            }
        }

    private fun syncUiMessages(): List<MessageUiItem> {
        val newUiMessages = buildMessagesHistoryUiMessages(
            messages = messages.value,
            selectedMessages = selectedMessages.value,
            screenState = screenState.value,
            resourceProvider = resourceProvider
        )
        uiMessages.setValue { newUiMessages }

        return newUiMessages
    }

    companion object {
        const val MESSAGES_LOAD_COUNT = 30
    }
}


// TODO: 25.08.2023, Danil Nikolaev: this and down below - rewrite

//    suspend fun uploadPhoto(
//        peerid: Long,
//        photo: File,
//        name: String,
//    ) {
//        suspendCoroutine {
//            viewModelScope.launch {
//                val uploadServerUrl = getPhotoMessageUploadServer(peerId)
//                val uploadedFileInfo = uploadPhotoToServer(uploadServerUrl, photo, name)
//
//                val savedAttachment = saveMessagePhoto(
//                    uploadedFileInfo.first,
//                    uploadedFileInfo.second,
//                    uploadedFileInfo.third
//                )
//
//                it.resume(savedAttachment)
//            }
//        }
//    }

//    private suspend fun getPhotoMessageUploadServer(peerid: Long) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { photosRepository.getMessagesUploadServer(peerId) }
//                ).response?.let { response ->
//                    continuation.resume(response.uploadUrl)
//                }
//            }
//        }
//    }

//    private suspend fun uploadPhotoToServer(
//        uploadUrl: String,
//        photo: File,
//        name: String,
//    ) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                val requestBody = photo.asRequestBody("image/*".toMediaType())
//                val body = MultipartBody.Part.createFormData("photo", name, requestBody)

//            sendRequestNotNull(
//                onError = { exception ->
//                    continuation.resumeWithException(exception)
//                    true
//                },
//                request = { photosRepository.uploadPhoto(uploadUrl, body) }
//            ).let { response ->
//                continuation.resume(Triple(response.server, response.photo, response.hash))
//            }
//            }
//        }
//    }

//    private suspend fun saveMessagePhoto(
//        server: Int,
//        photo: String,
//        hash: String,
//    ) = suspendCoroutine<VkAttachment> { continuation ->
//        viewModelScope.launch {
//            sendRequestNotNull(
//                onError = { exception ->
//                    continuation.resumeWithException(exception)
//                    true
//                },
//                request = {
//                    photosRepository.saveMessagePhoto(
//                        PhotosSaveMessagePhotoRequest(photo, server, hash)
//                    )
//                }
//            ).response?.first()?.toDomain()?.let(continuation::resume)
//        }
//    }

//    suspend fun uploadVideo(
//        file: File,
//        name: String,
//    ) {
//        suspendCoroutine {
//            viewModelScope.launch {
//                val uploadInfo = getVideoMessageUploadServer()
//
//                uploadVideoToServer(
//                    uploadInfo.first,
//                    file,
//                    name
//                )
//
//                it.resume(uploadInfo.second)
//            }
//        }
//    }

//    private suspend fun getVideoMessageUploadServer() {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//            sendRequestNotNull(
//                onError = { exception ->
//                    continuation.resumeWithException(exception)
//                    true
//                },
//                request = { videosRepository.save() }
//            ).response?.let { response ->
//                val uploadUrl = response.uploadUrl
//                val video = VkVideoDomain(
//                    id = response.videoId,
//                    ownerId = response.ownerId,
//                    images = emptyList(),
//                    firstFrames = null,
//                    accessKey = response.accessKey,
//                    title = response.title
//                )
//
//                continuation.resume(uploadUrl to video)
//            }
//            }
//        }
//    }

//    private suspend fun uploadVideoToServer(
//        uploadUrl: String,
//        file: File,
//        name: String,
//    ) {
//        viewModelScope.launch {
//            val requestBody = file.asRequestBody()
//            val body = MultipartBody.Part.createFormData("video_file", name, requestBody)
//
//            sendRequest(
//                onError = { exception -> throw exception },
//                request = { videosRepository.upload(uploadUrl, body) }
//            )
//        }
//    }

//    suspend fun uploadAudio(
//        file: File,
//        name: String,
//    ) {
//        suspendCoroutine {
//            viewModelScope.launch {
//                val uploadUrl = getAudioUploadServer()
//                val uploadInfo = uploadAudioToServer(uploadUrl, file, name)
//                val saveInfo = saveMessageAudio(
//                    uploadInfo.first, uploadInfo.second, uploadInfo.third
//                )
//
//                it.resume(saveInfo)
//            }
//        }
//    }

//    private suspend fun getAudioUploadServer() {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { audiosRepository.getUploadServer() }
//                ).response?.uploadUrl?.let(continuation::resume)
//            }
//        }
//    }

//    private suspend fun uploadAudioToServer(
//        uploadUrl: String,
//        file: File,
//        name: String,
//    ) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                val requestBody = file.asRequestBody()
//                val body = MultipartBody.Part.createFormData("file", name, requestBody)
//
//                sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { audiosRepository.upload(uploadUrl, body) }
//                ).let { response ->
//                    response.error?.let { error -> throw ApiException(error = error) }
//
//                    continuation.resume(
//                        Triple(response.server, response.audio.notNull(), response.hash)
//                    )
//                }
//            }
//        }
//    }

//    private suspend fun saveMessageAudio(
//        server: Int,
//        audio: String,
//        hash: String,
//    ) {
//        suspendCoroutine<VkAttachment> { continuation ->
//            viewModelScope.launch {
//                sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { audiosRepository.save(server, audio, hash) }
//                ).response?.toDomain()?.let(continuation::resume)
//            }
//        }
//    }

//    suspend fun uploadFile(
//        peerid: Long,
//        file: File,
//        name: String,
//        type: FilesRepository.FileType,
//    ) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                val uploadServerUrl = getFileMessageUploadServer(peerId, type)
//                val uploadedFileInfo = uploadFileToServer(uploadServerUrl, file, name)
//                val savedAttachmentPair = saveMessageFile(uploadedFileInfo)
//
//                continuation.resume(savedAttachmentPair.second)
//            }
//        }
//    }

//    private suspend fun getFileMessageUploadServer(
//        peerid: Long,
//        type: FilesRepository.FileType,
//    ) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                val uploadServerResponse = sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { filesRepository.getMessagesUploadServer(peerId, type) }
//                ).response.notNull()
//
//                continuation.resume(uploadServerResponse.uploadUrl)
//            }
//        }
//    }

//    private suspend fun uploadFileToServer(
//        uploadUrl: String,
//        file: File,
//        name: String,
//    ) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                val requestBody = file.asRequestBody()
//                val body = MultipartBody.Part.createFormData("file", name, requestBody)
//
//                sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { filesRepository.uploadFile(uploadUrl, body) }
//                ).let { response ->
//                    response.error?.let { error -> throw ApiException(error = error) }
//
//                    continuation.resume(response.file.notNull())
//                }
//            }
//        }
//    }

//    private suspend fun saveMessageFile(file: String) {
//        suspendCoroutine { continuation ->
//            viewModelScope.launch {
//                sendRequestNotNull(
//                    onError = { exception ->
//                        continuation.resumeWithException(exception)
//                        true
//                    },
//                    request = { filesRepository.saveMessageFile(file) }
//                ).response?.let { response ->
//                    val type = response.type
//                    val attachmentFile =
//                        response.file?.toDomain() ?: response.voiceMessage?.toDomain()
//
//                    continuation.resume(type to attachmentFile.notNull())
//                }
//            }
//        }
//    }
//}

//data class MessagesLoadedEvent(
//    val count: Int,
//    val conversations: HashMap<Int, VkConversationDomain>,
//    val messages: List<VkMessageDomain>,
//    val profiles: HashMap<Int, VkUserDomain>,
//    val groups: HashMap<Int, VkGroupDomain>,
//) : VkEvent()
//
//data class MessagesMarkAsImportantEvent(val messagesIds: List<Int>, val important: Boolean) :
//    VkEvent()
//
//data class MessagesPinEvent(val message: VkMessageDomain) : VkEvent()
//
//object MessagesUnpinEvent : VkEvent()
//
//data class MessagesDeleteEvent(val peerid: Long, val messagesIds: List<Int>) : VkEvent()
//
//data class MessagesEditEvent(val message: VkMessageDomain) : VkEvent()
//
//data class MessagesReadEvent(
//    val isOut: Boolean,
//    val peerid: Long,
//    val messageid: Long,
//) : VkEvent()
//
//data class MessagesNewEvent(
//    val message: VkMessageDomain,
//    val profiles: HashMap<Int, VkUserDomain>,
//    val groups: HashMap<Int, VkGroupDomain>,
//) : VkEvent()
