package ru.forbion.f7cloud.feature.tasks

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import ru.forbion.f7cloud.core.auth.AuthSession
import ru.forbion.f7cloud.core.network.UnauthorizedException
import java.time.LocalDate

data class TasksUiState(
    val loading: Boolean = false,
    val saving: Boolean = false,
    val deletingCompleted: Boolean = false,
    val lists: List<TaskListItem> = emptyList(),
    val selectedListHref: String? = null,
    val defaultListHref: String? = null,
    val tasks: List<TaskItem> = emptyList(),
    val hideCompleted: Boolean = true,
    val completedExpanded: Boolean = false,
    val searchQuery: String = "",
    val sortAscending: Boolean = true,
    val groupByDate: Boolean = true,
    val createInputExpanded: Boolean = false,
    val createInputText: String = "",
    val settingsOpen: Boolean = false,
    val error: String? = null,
    val unauthorized: Boolean = false,
    val detailTask: TaskItem? = null,
) {
    val selectedList: TaskListItem?
        get() = lists.firstOrNull { it.href == selectedListHref }

    private fun matchesSearch(task: TaskItem): Boolean {
        val q = searchQuery.trim()
        return q.isEmpty() ||
            task.summary.contains(q, ignoreCase = true) ||
            task.description.contains(q, ignoreCase = true)
    }

    val activeTasks: List<TaskItem>
        get() = tasks.filter { !it.isCompleted && matchesSearch(it) }

    val completedTasks: List<TaskItem>
        get() = tasks.filter { it.isCompleted && matchesSearch(it) }

    val visibleActiveGroups: List<TaskGroup>
        get() {
            val active = activeTasks
            return if (groupByDate) {
                TasksGrouping.groupByDue(active, sortAscending)
            } else {
                val sorted = if (sortAscending) {
                    active.sortedBy { it.summary.lowercase() }
                } else {
                    active.sortedByDescending { it.summary.lowercase() }
                }
                TasksGrouping.singleListGroup(selectedList?.displayName ?: "Список", sorted)
            }
        }

    val showEmptyState: Boolean
        get() = !loading && activeTasks.isEmpty() && (hideCompleted || completedTasks.isEmpty())
}

class TasksViewModel(
    private val repository: TasksRepository = TasksRepository(),
) : ViewModel() {
    private val _state = MutableStateFlow(TasksUiState())
    val state: StateFlow<TasksUiState> = _state.asStateFlow()

    fun load(session: AuthSession) {
        viewModelScope.launch(Dispatchers.IO) {
            _state.update { it.copy(loading = it.lists.isEmpty(), error = null) }
            runCatching { repository.listTaskLists(session) }
                .onSuccess { lists ->
                    val selected = _state.value.selectedListHref
                        ?: _state.value.defaultListHref
                        ?: lists.firstOrNull()?.href
                    _state.update {
                        it.copy(
                            loading = false,
                            lists = lists,
                            selectedListHref = selected,
                            defaultListHref = it.defaultListHref ?: lists.firstOrNull()?.href,
                        )
                    }
                    selected?.let { loadTasks(session, it) }
                }
                .onFailure { t ->
                    _state.update {
                        it.copy(
                            loading = false,
                            error = t.message,
                            unauthorized = t is UnauthorizedException,
                        )
                    }
                }
        }
    }

    fun openList(session: AuthSession, listHref: String) {
        _state.update {
            it.copy(
                selectedListHref = listHref,
                searchQuery = "",
                detailTask = null,
                createInputExpanded = false,
                createInputText = "",
            )
        }
        loadTasks(session, listHref)
    }

    fun closeList() {
        _state.update {
            it.copy(
                selectedListHref = null,
                tasks = emptyList(),
                detailTask = null,
                createInputExpanded = false,
                createInputText = "",
            )
        }
    }

    fun openListBySlug(session: AuthSession, slug: String?) {
        val list = repository.findListBySlug(_state.value.lists, slug)
        if (list != null) {
            openList(session, list.href)
        }
    }

    fun setSearchQuery(query: String) {
        _state.update { it.copy(searchQuery = query) }
    }

    fun toggleHideCompleted() {
        _state.update { it.copy(hideCompleted = !it.hideCompleted) }
    }

    fun toggleCompletedExpanded() {
        _state.update { it.copy(completedExpanded = !it.completedExpanded) }
    }

    fun toggleSortOrder() {
        _state.update { it.copy(sortAscending = !it.sortAscending) }
    }

    fun expandCreateInput() {
        _state.update { it.copy(createInputExpanded = true, error = null) }
    }

    fun collapseCreateInput() {
        _state.update { it.copy(createInputExpanded = false, createInputText = "") }
    }

    fun setCreateInputText(text: String) {
        _state.update { it.copy(createInputText = text) }
    }

    fun openSettings() {
        _state.update { it.copy(settingsOpen = true) }
    }

    fun closeSettings() {
        _state.update { it.copy(settingsOpen = false) }
    }

    fun setDefaultList(href: String?) {
        _state.update { it.copy(defaultListHref = href) }
    }

    fun openDetail(task: TaskItem) {
        _state.update { it.copy(detailTask = task) }
    }

    fun closeDetail() {
        _state.update { it.copy(detailTask = null) }
    }

    fun submitCreateInput(session: AuthSession) {
        val summary = _state.value.createInputText.trim()
        if (summary.isBlank()) {
            collapseCreateInput()
            return
        }
        createTask(session, summary, "", 0)
    }

    fun createTask(
        session: AuthSession,
        summary: String,
        dueInput: String,
        priority: Int,
    ) {
        val listHref = _state.value.selectedListHref ?: return
        if (summary.isBlank()) {
            _state.update { it.copy(error = "Введите название задачи") }
            return
        }
        viewModelScope.launch(Dispatchers.IO) {
            _state.update { it.copy(saving = true, error = null) }
            runCatching {
                val dueRaw = TasksRepository.parseDueInput(dueInput)
                val dueDate = dueRaw.takeIf { it.length >= 8 }?.let {
                    runCatching {
                        LocalDate.parse(it.take(8), java.time.format.DateTimeFormatter.BASIC_ISO_DATE)
                    }.getOrNull()
                }
                repository.createTask(
                    session = session,
                    listHref = listHref,
                    summary = summary.trim(),
                    dueDate = dueDate,
                    priority = priority,
                )
            }.onSuccess {
                _state.update {
                    it.copy(
                        saving = false,
                        createInputExpanded = false,
                        createInputText = "",
                    )
                }
                loadTasks(session, listHref)
            }.onFailure { t ->
                _state.update {
                    it.copy(
                        saving = false,
                        error = t.message ?: "Не удалось создать задачу",
                        unauthorized = t is UnauthorizedException,
                    )
                }
            }
        }
    }

    fun toggleComplete(session: AuthSession, task: TaskItem) {
        viewModelScope.launch(Dispatchers.IO) {
            runCatching {
                repository.toggleComplete(session, task, !task.isCompleted)
            }.onSuccess {
                val listHref = _state.value.selectedListHref
                val detail = _state.value.detailTask
                if (detail?.uid == task.uid) {
                    _state.update {
                        it.copy(detailTask = detail.copy(
                            status = if (task.isCompleted) "NEEDS-ACTION" else "COMPLETED",
                            percentComplete = if (task.isCompleted) 0 else 100,
                        ))
                    }
                }
                listHref?.let { loadTasks(session, it) }
            }.onFailure { t ->
                _state.update {
                    it.copy(
                        error = t.message,
                        unauthorized = t is UnauthorizedException,
                    )
                }
            }
        }
    }

    fun saveDetail(
        session: AuthSession,
        summary: String,
        dueInput: String,
        priority: Int,
        description: String,
    ) {
        val task = _state.value.detailTask ?: return
        viewModelScope.launch(Dispatchers.IO) {
            _state.update { it.copy(saving = true, error = null) }
            runCatching {
                repository.updateTask(
                    session = session,
                    task = task,
                    summary = summary.trim().ifBlank { task.summary },
                    dueRaw = TasksRepository.parseDueInput(dueInput),
                    priority = priority,
                    description = description.trim(),
                )
            }.onSuccess {
                _state.update { it.copy(saving = false, detailTask = null) }
                _state.value.selectedListHref?.let { loadTasks(session, it) }
            }.onFailure { t ->
                _state.update {
                    it.copy(
                        saving = false,
                        error = t.message ?: "Не удалось сохранить",
                        unauthorized = t is UnauthorizedException,
                    )
                }
            }
        }
    }

    fun deleteDetail(session: AuthSession) {
        val task = _state.value.detailTask ?: return
        viewModelScope.launch(Dispatchers.IO) {
            _state.update { it.copy(saving = true, error = null) }
            runCatching { repository.deleteTask(session, task) }
                .onSuccess {
                    _state.update { it.copy(saving = false, detailTask = null) }
                    _state.value.selectedListHref?.let { loadTasks(session, it) }
                }
                .onFailure { t ->
                    _state.update {
                        it.copy(
                            saving = false,
                            error = t.message ?: "Не удалось удалить",
                            unauthorized = t is UnauthorizedException,
                        )
                    }
                }
        }
    }

    fun deleteCompletedTasks(session: AuthSession) {
        val listHref = _state.value.selectedListHref ?: return
        val completed = _state.value.completedTasks
        if (completed.isEmpty()) return
        viewModelScope.launch(Dispatchers.IO) {
            _state.update { it.copy(deletingCompleted = true, error = null) }
            runCatching { repository.deleteCompletedTasks(session, completed) }
                .onSuccess {
                    _state.update { it.copy(deletingCompleted = false, completedExpanded = false) }
                    loadTasks(session, listHref)
                }
                .onFailure { t ->
                    _state.update {
                        it.copy(
                            deletingCompleted = false,
                            error = t.message ?: "Не удалось удалить",
                            unauthorized = t is UnauthorizedException,
                        )
                    }
                }
        }
    }

    fun refreshTasks(session: AuthSession) {
        _state.value.selectedListHref?.let { loadTasks(session, it) }
            ?: load(session)
    }

    private fun loadTasks(session: AuthSession, listHref: String) {
        viewModelScope.launch(Dispatchers.IO) {
            _state.update { it.copy(loading = _state.value.tasks.isEmpty(), error = null) }
            runCatching { repository.loadTasks(session, listHref) }
                .onSuccess { tasks ->
                    _state.update { it.copy(loading = false, tasks = tasks) }
                }
                .onFailure { t ->
                    _state.update {
                        it.copy(
                            loading = false,
                            error = t.message,
                            unauthorized = t is UnauthorizedException,
                        )
                    }
                }
        }
    }
}
