package com.seven.ikar.kotlin.feature.stories

import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.seven.ikar.kotlin.app.AppContainer
import com.seven.ikar.kotlin.core.local.TransferQueueEntity
import com.seven.ikar.kotlin.core.model.StoryDto
import com.seven.ikar.kotlin.core.model.StoryVisibility
import com.seven.ikar.kotlin.feature.chat.LocalAttachmentFile
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

data class StoryMediaPreviewUiState(
    val fileName: String,
    val contentType: String,
    val fileSizeBytes: Long,
    val localPath: String
)

data class StoryTransferUiState(
    val groupId: String,
    val title: String,
    val status: String,
    val progressPercent: Int,
    val errorMessage: String?
)

data class StoriesUiState(
    val accessToken: String? = null,
    val currentUserId: String? = null,
    val stories: List<StoryDto> = emptyList(),
    val draftText: String = "",
    val visibility: StoryVisibility = StoryVisibility.Everyone,
    val hasProtectedContent: Boolean = false,
    val ttlSeconds: Int = 86_400,
    val pendingMedia: List<StoryMediaPreviewUiState> = emptyList(),
    val activeTransfers: List<StoryTransferUiState> = emptyList(),
    val isLoading: Boolean = false,
    val isSaving: Boolean = false,
    val isImportingMedia: Boolean = false,
    val errorMessage: String? = null,
    val createdStoryId: String? = null,
    val selectedStory: StoryDto? = null
)

class StoriesViewModel(private val container: AppContainer) : ViewModel() {
    private val _uiState = MutableStateFlow(StoriesUiState())
    val uiState: StateFlow<StoriesUiState> = _uiState.asStateFlow()
    private var pendingMediaFiles: List<LocalAttachmentFile> = emptyList()
    private var hadActiveStoryTransfers = false

    init {
        attachStoryTransferState()
        refresh()
    }

    fun refresh() {
        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    session.accessToken to container.apiClient.getStories(session.accessToken)
                }
            }.onSuccess { (accessToken, stories) ->
                _uiState.value = _uiState.value.copy(
                    accessToken = accessToken,
                    currentUserId = container.sessionStore.read()?.user?.id,
                    stories = stories.sortedByDescending { it.createdAt },
                    isLoading = false
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isLoading = false, errorMessage = error.message)
            }
        }
    }

    fun updateDraftText(value: String) {
        _uiState.value = _uiState.value.copy(draftText = value.take(500), errorMessage = null, createdStoryId = null)
    }

    fun setVisibility(visibility: StoryVisibility) {
        _uiState.value = _uiState.value.copy(visibility = visibility)
    }

    fun setProtectedContent(value: Boolean) {
        _uiState.value = _uiState.value.copy(hasProtectedContent = value)
    }

    fun setTtlSeconds(value: Int) {
        _uiState.value = _uiState.value.copy(ttlSeconds = value.coerceIn(300, 604_800))
    }

    fun consumeMediaUris(uris: List<Uri>) {
        if (uris.isEmpty()) {
            return
        }

        val availableSlots = MaxStoryMediaCount - pendingMediaFiles.size
        if (availableSlots <= 0) {
            _uiState.value = _uiState.value.copy(errorMessage = "В одной истории максимум $MaxStoryMediaCount файлов.")
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isImportingMedia = true, errorMessage = null)
            runCatching {
                uris.take(availableSlots).map { uri -> container.attachmentFileService.importFromUri(uri) }
            }.onSuccess { imported ->
                pendingMediaFiles = (pendingMediaFiles + imported).take(MaxStoryMediaCount)
                _uiState.value = _uiState.value.copy(
                    pendingMedia = pendingMediaFiles.toStoryMediaPreviewUiState(),
                    isImportingMedia = false
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isImportingMedia = false, errorMessage = error.message)
            }
        }
    }

    fun removePendingMedia(localPath: String) {
        pendingMediaFiles = pendingMediaFiles.filterNot { it.localPath == localPath }
        _uiState.value = _uiState.value.copy(pendingMedia = pendingMediaFiles.toStoryMediaPreviewUiState())
    }

    fun clearPendingMedia() {
        pendingMediaFiles = emptyList()
        _uiState.value = _uiState.value.copy(pendingMedia = emptyList())
    }

    fun createStory(onCreated: () -> Unit = {}) {
        val state = _uiState.value
        val text = state.draftText.trim()
        val mediaFiles = pendingMediaFiles
        if ((text.isBlank() && mediaFiles.isEmpty()) || state.isSaving) {
            _uiState.value = state.copy(errorMessage = "Добавьте текст или медиа.")
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isSaving = true, errorMessage = null)
            if (mediaFiles.isNotEmpty()) {
                runCatching {
                    container.transferQueueRepository.enqueueStoryUpload(
                        text = text.takeIf { it.isNotBlank() },
                        visibility = state.visibility,
                        hasProtectedContent = state.hasProtectedContent,
                        ttlSeconds = state.ttlSeconds,
                        files = mediaFiles
                    )
                }.onSuccess { groupId ->
                    pendingMediaFiles = emptyList()
                    _uiState.value = _uiState.value.copy(
                        draftText = "",
                        pendingMedia = emptyList(),
                        isSaving = false,
                        createdStoryId = groupId
                    )
                    onCreated()
                }.onFailure { error ->
                    _uiState.value = _uiState.value.copy(isSaving = false, errorMessage = error.message)
                }
                return@launch
            }

            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.createStory(
                        accessToken = session.accessToken,
                        text = text,
                        visibility = state.visibility,
                        hasProtectedContent = state.hasProtectedContent,
                        ttlSeconds = state.ttlSeconds
                    )
                }
            }.onSuccess { story ->
                _uiState.value = _uiState.value.copy(
                    stories = listOf(story) + _uiState.value.stories.filterNot { it.id == story.id },
                    draftText = "",
                    isSaving = false,
                    createdStoryId = story.id
                )
                onCreated()
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isSaving = false, errorMessage = error.message)
            }
        }
    }

    fun openStory(story: StoryDto) {
        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(selectedStory = story, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.getStory(session.accessToken, story.id)
                }
            }.onSuccess { viewedStory ->
                _uiState.value = _uiState.value.copy(
                    selectedStory = viewedStory,
                    stories = _uiState.value.stories.map { if (it.id == viewedStory.id) viewedStory else it }
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(errorMessage = error.message)
            }
        }
    }

    fun openStoryById(storyId: String) {
        val story = _uiState.value.stories.firstOrNull { it.id == storyId }
        if (story != null) {
            openStory(story)
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.getStory(session.accessToken, storyId)
                }
            }.onSuccess { storyFromServer ->
                _uiState.value = _uiState.value.copy(
                    selectedStory = storyFromServer,
                    stories = listOf(storyFromServer) + _uiState.value.stories.filterNot { it.id == storyFromServer.id },
                    isLoading = false
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isLoading = false, errorMessage = error.message)
            }
        }
    }

    fun openNextStory() {
        openRelativeStory(offset = 1)
    }

    fun openPreviousStory() {
        openRelativeStory(offset = -1)
    }

    fun closeStoryPreview() {
        _uiState.value = _uiState.value.copy(selectedStory = null)
    }

    fun deleteStory(story: StoryDto) {
        viewModelScope.launch {
            runCatching {
                container.executeAuthorized { session -> container.apiClient.deleteStory(session.accessToken, story.id) }
            }.onSuccess {
                _uiState.value = _uiState.value.copy(
                    stories = _uiState.value.stories.filterNot { it.id == story.id },
                    selectedStory = _uiState.value.selectedStory?.takeUnless { it.id == story.id }
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(errorMessage = error.message)
            }
        }
    }

    fun retryTransfer(groupId: String) {
        viewModelScope.launch {
            runCatching { container.transferQueueRepository.retry(groupId) }
                .onFailure { error -> _uiState.value = _uiState.value.copy(errorMessage = error.message) }
        }
    }

    fun cancelTransfer(groupId: String) {
        viewModelScope.launch {
            runCatching { container.transferQueueRepository.cancel(groupId) }
                .onFailure { error -> _uiState.value = _uiState.value.copy(errorMessage = error.message) }
        }
    }

    private fun attachStoryTransferState() {
        viewModelScope.launch {
            container.transferQueueRepository.observeActiveStoryUploads().collect { items ->
                val transfers = items.toStoryTransferUiState()
                if (hadActiveStoryTransfers && transfers.isEmpty()) {
                    refresh()
                }
                hadActiveStoryTransfers = transfers.isNotEmpty()
                _uiState.value = _uiState.value.copy(activeTransfers = transfers)
            }
        }
    }

    private fun openRelativeStory(offset: Int) {
        val state = _uiState.value
        val selected = state.selectedStory ?: return
        val stories = state.stories
        if (stories.isEmpty()) {
            return
        }
        val currentIndex = stories.indexOfFirst { it.id == selected.id }
        if (currentIndex < 0) {
            return
        }

        val nextIndex = (currentIndex + offset).coerceIn(0, stories.lastIndex)
        if (nextIndex != currentIndex) {
            openStory(stories[nextIndex])
        }
    }

    companion object {
        private const val MaxStoryMediaCount = 10
    }
}

private fun List<LocalAttachmentFile>.toStoryMediaPreviewUiState(): List<StoryMediaPreviewUiState> =
    map { file ->
        StoryMediaPreviewUiState(
            fileName = file.fileName,
            contentType = file.contentType,
            fileSizeBytes = file.fileSizeBytes,
            localPath = file.localPath
        )
    }

private fun List<TransferQueueEntity>.toStoryTransferUiState(): List<StoryTransferUiState> =
    groupBy { it.groupId }
        .map { (groupId, items) ->
            val ordered = items.sortedBy { it.sortOrder }
            val first = ordered.first()
            StoryTransferUiState(
                groupId = groupId,
                title = if (ordered.size == 1) first.fileName else "${ordered.size} файлов",
                status = first.status,
                progressPercent = ordered.maxOfOrNull { it.progressPercent } ?: 0,
                errorMessage = ordered.firstNotNullOfOrNull { it.errorMessage }
            )
        }
        .sortedBy { it.title }
