package com.seven.ikar.kotlin.feature.archive

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.seven.ikar.kotlin.app.AppContainer
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.text.DecimalFormat

data class ArchiveExtractorUiState(
    val archive: PendingArchiveFile? = null,
    val openError: PendingArchiveOpenError? = null,
    val inspection: ArchiveInspectionResult? = null,
    val options: ArchiveExtractionOptions = ArchiveExtractionOptions(),
    val isInspecting: Boolean = false,
    val isExtracting: Boolean = false,
    val progress: ArchiveExtractionProgress? = null,
    val result: ArchiveExtractionResult? = null,
    val errorMessage: String? = null
) {
    val hasArchive: Boolean
        get() = archive != null
}

class ArchiveExtractorViewModel(
    private val container: AppContainer
) : ViewModel() {
    private val _uiState = MutableStateFlow(ArchiveExtractorUiState())
    val uiState: StateFlow<ArchiveExtractorUiState> = _uiState.asStateFlow()
    private var extractionJob: Job? = null

    init {
        viewModelScope.launch {
            container.incomingArchiveStore.pendingArchive.collectLatest { pending ->
                when (pending) {
                    is PendingArchiveFile -> loadArchive(pending)
                    is PendingArchiveOpenError -> {
                        extractionJob?.cancel()
                        _uiState.value = ArchiveExtractorUiState(openError = pending)
                    }
                    null -> {
                        extractionJob?.cancel()
                        _uiState.value = ArchiveExtractorUiState()
                    }
                }
            }
        }
    }

    fun setKeepFolders(enabled: Boolean) {
        val current = _uiState.value
        _uiState.value = current.copy(
            options = current.options.copy(keepFolders = enabled),
            result = null,
            errorMessage = null
        )
    }

    fun setOverwriteExisting(enabled: Boolean) {
        val current = _uiState.value
        _uiState.value = current.copy(
            options = current.options.copy(overwriteExisting = enabled),
            result = null,
            errorMessage = null
        )
    }

    fun extract() {
        val archive = _uiState.value.archive ?: return
        if (_uiState.value.isExtracting) {
            return
        }

        extractionJob = viewModelScope.launch {
            _uiState.value = _uiState.value.copy(
                isExtracting = true,
                progress = ArchiveExtractionProgress(
                    processedEntries = 0,
                    totalEntries = _uiState.value.inspection?.totalEntries ?: 0,
                    extractedFiles = 0,
                    writtenBytes = 0,
                    currentEntry = null
                ),
                result = null,
                errorMessage = null
            )
            runCatching {
                container.archiveFileService.extractZip(
                    archive = archive,
                    inspection = _uiState.value.inspection,
                    options = _uiState.value.options
                ) { progress ->
                    _uiState.value = _uiState.value.copy(progress = progress)
                }
            }.onSuccess { result ->
                _uiState.value = _uiState.value.copy(
                    isExtracting = false,
                    progress = null,
                    result = result,
                    errorMessage = null
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(
                    isExtracting = false,
                    progress = null,
                    result = null,
                    errorMessage = error.message ?: "Не удалось распаковать архив."
                )
            }
        }
    }

    fun cancelExtraction() {
        extractionJob?.cancel()
        extractionJob = null
        _uiState.value = _uiState.value.copy(
            isExtracting = false,
            progress = null,
            errorMessage = "Распаковка отменена."
        )
    }

    fun clearAndClose() {
        extractionJob?.cancel()
        container.incomingArchiveStore.clear()
    }

    private suspend fun loadArchive(archive: PendingArchiveFile) {
        extractionJob?.cancel()
        _uiState.value = ArchiveExtractorUiState(
            archive = archive,
            isInspecting = true
        )
        runCatching {
            container.archiveFileService.inspectZip(archive)
        }.onSuccess { inspection ->
            _uiState.value = _uiState.value.copy(
                isInspecting = false,
                inspection = inspection,
                errorMessage = null
            )
        }.onFailure { error ->
            _uiState.value = _uiState.value.copy(
                isInspecting = false,
                inspection = null,
                errorMessage = error.message ?: "Не удалось прочитать ZIP-архив."
            )
        }
    }
}

fun formatArchiveBytes(value: Long?): String {
    if (value == null || value < 0) {
        return "размер неизвестен"
    }
    if (value == 0L) {
        return "0 Б"
    }

    val units = listOf("Б", "КБ", "МБ", "ГБ")
    var size = value.toDouble()
    var unitIndex = 0
    while (size >= 1024 && unitIndex < units.lastIndex) {
        size /= 1024
        unitIndex += 1
    }
    return "${DecimalFormat("#,##0.#").format(size).replace(',', '.')} ${units[unitIndex]}"
}
