package com.seven.ikar.kotlin.feature.bots

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.seven.ikar.kotlin.app.AppContainer
import com.seven.ikar.kotlin.core.model.AuthSessionDto
import com.seven.ikar.kotlin.core.model.BotCommandDto
import com.seven.ikar.kotlin.core.model.BotSummaryDto
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

data class BotEditorUiState(
    val session: AuthSessionDto? = null,
    val botId: String? = null,
    val botUserId: String? = null,
    val displayName: String = "",
    val username: String = "",
    val about: String = "",
    val isEnabled: Boolean = true,
    val commandsText: String = "",
    val latestToken: String = "",
    val isLoading: Boolean = false,
    val isSaving: Boolean = false,
    val isDeleting: Boolean = false,
    val errorMessage: String? = null,
    val infoMessage: String? = null,
    val pendingChatId: String? = null,
    val deleteCompleted: Boolean = false
) {
    val isExistingBot: Boolean get() = !botId.isNullOrBlank()
}

class BotEditorViewModel(
    private val container: AppContainer,
    private val botId: String?
) : ViewModel() {
    private val _uiState = MutableStateFlow(BotEditorUiState(session = container.sessionStore.read(), botId = botId))
    val uiState: StateFlow<BotEditorUiState> = _uiState.asStateFlow()

    init {
        load()
    }

    fun updateDisplayName(value: String) {
        _uiState.value = _uiState.value.copy(displayName = value)
    }

    fun updateUsername(value: String) {
        _uiState.value = _uiState.value.copy(username = value)
    }

    fun updateAbout(value: String) {
        _uiState.value = _uiState.value.copy(about = value)
    }

    fun updateCommandsText(value: String) {
        _uiState.value = _uiState.value.copy(commandsText = value)
    }

    fun updateEnabled(value: Boolean) {
        _uiState.value = _uiState.value.copy(isEnabled = value)
    }

    fun load() {
        val existingBotId = botId ?: return
        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    session to container.apiClient.getBot(session.accessToken, existingBotId)
                }
            }.onSuccess { (session, bot) ->
                applyBot(session, bot, latestToken = "", infoMessage = null)
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isLoading = false, errorMessage = error.message)
            }
        }
    }

    fun save() {
        val state = _uiState.value
        if (state.displayName.isBlank()) {
            _uiState.value = state.copy(errorMessage = "Укажите отображаемое имя бота.")
            return
        }
        if (!state.isExistingBot && state.username.isBlank()) {
            _uiState.value = state.copy(errorMessage = "Укажите имя пользователя бота.")
            return
        }

        viewModelScope.launch {
            _uiState.value = state.copy(isSaving = true, errorMessage = null, infoMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    val parsedCommands = parseCommands(state.commandsText)
                    if (!state.isExistingBot) {
                        val created = container.apiClient.createBot(
                            accessToken = session.accessToken,
                            username = state.username.trim(),
                            displayName = state.displayName.trim(),
                            about = state.about.trim().ifBlank { null }
                        )
                        val updatedBot = if (parsedCommands.isNotEmpty()) {
                            container.apiClient.setBotCommands(session.accessToken, created.bot.id, parsedCommands)
                        } else {
                            created.bot
                        }
                        Triple(session, updatedBot, Pair(created.accessToken, "Бот создан."))
                    } else {
                        val updated = container.apiClient.updateBot(
                            accessToken = session.accessToken,
                            botId = state.botId.orEmpty(),
                            displayName = state.displayName.trim(),
                            about = state.about.trim().ifBlank { null },
                            isEnabled = state.isEnabled
                        )
                        val withCommands = container.apiClient.setBotCommands(
                            accessToken = session.accessToken,
                            botId = updated.id,
                            commands = parsedCommands
                        )
                        Triple(session, withCommands, Pair(state.latestToken, "Бот сохранён."))
                    }
                }
            }.onSuccess { result ->
                val (session, bot, extra) = result
                applyBot(session, bot, latestToken = extra.first, infoMessage = extra.second)
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isSaving = false, errorMessage = error.message)
            }
        }
    }

    fun regenerateToken() {
        val existingBotId = _uiState.value.botId ?: return
        viewModelScope.launch {
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.regenerateBotToken(session.accessToken, existingBotId)
                }
            }.onSuccess { response ->
                _uiState.value = _uiState.value.copy(latestToken = response.accessToken, infoMessage = "Токен обновлён.")
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(errorMessage = error.message)
            }
        }
    }

    fun deleteBot() {
        val existingBotId = _uiState.value.botId ?: return
        val state = _uiState.value
        if (state.isDeleting || state.isSaving) {
            return
        }

        viewModelScope.launch {
            _uiState.value = state.copy(isDeleting = true, errorMessage = null, infoMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.deleteBot(session.accessToken, existingBotId)
                }
            }.onSuccess {
                _uiState.value = _uiState.value.copy(isDeleting = false, deleteCompleted = true)
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isDeleting = false, errorMessage = error.message)
            }
        }
    }

    fun openChat() {
        val botUserId = _uiState.value.botUserId ?: return
        viewModelScope.launch {
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.createDirectChat(session.accessToken, botUserId)
                }
            }.onSuccess { chat ->
                _uiState.value = _uiState.value.copy(pendingChatId = chat.id)
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(errorMessage = error.message)
            }
        }
    }

    fun consumePendingChatNavigation() {
        _uiState.value = _uiState.value.copy(pendingChatId = null)
    }

    fun consumeDeleteCompleted() {
        _uiState.value = _uiState.value.copy(deleteCompleted = false)
    }

    private fun applyBot(session: AuthSessionDto, bot: BotSummaryDto, latestToken: String, infoMessage: String?) {
        _uiState.value = _uiState.value.copy(
            session = session,
            botId = bot.id,
            botUserId = bot.userId,
            displayName = bot.displayName,
            username = bot.username,
            about = bot.about.orEmpty(),
            isEnabled = bot.isEnabled,
            commandsText = formatCommands(bot.commands),
            latestToken = latestToken,
            isLoading = false,
            isSaving = false,
            isDeleting = false,
            errorMessage = null,
            infoMessage = infoMessage,
            deleteCompleted = false
        )
    }

    private fun parseCommands(source: String): List<BotCommandDto> =
        source
            .lines()
            .map { it.trim() }
            .filter { it.isNotBlank() }
            .mapNotNull { line ->
                val separatorIndex = line.indexOf(" - ").takeIf { it > 0 }
                    ?: line.indexOf(' ').takeIf { it > 0 }
                    ?: return@mapNotNull null
                val separatorLength = if (line.contains(" - ")) 3 else 1
                val command = line.substring(0, separatorIndex).trim().trimStart('/')
                val description = line.substring(separatorIndex + separatorLength).trim()
                if (command.isBlank() || description.isBlank()) {
                    null
                } else {
                    BotCommandDto(command = command, description = description)
                }
            }

    private fun formatCommands(commands: List<BotCommandDto>): String =
        commands.joinToString(separator = "\n") { "/${it.command} - ${it.description}" }
}
