package com.tt.honeyDue.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tt.honeyDue.data.DataManager
import com.tt.honeyDue.data.IDataManager
import com.tt.honeyDue.models.CustomTask
import com.tt.honeyDue.models.TaskColumnsResponse
import com.tt.honeyDue.models.TaskCompletionResponse
import com.tt.honeyDue.models.TaskCreateRequest
import com.tt.honeyDue.network.APILayer
import com.tt.honeyDue.network.ApiResult
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

/**
 * TaskViewModel — derives all read-state from [IDataManager].
 *
 * The VM no longer owns `_tasksState` / `_tasksByResidenceState` /
 * `_taskCompletionsState` `MutableStateFlow` fields. Instead:
 *
 *  * [tasksState] is a derived flow over [IDataManager.allTasks] — whenever
 *    DataManager is updated (APILayer success write, fixture seed, etc.),
 *    the VM re-emits automatically. Screens rendering against the fixture
 *    in snapshot tests see populated data immediately.
 *  * [tasksByResidenceState] is parameterised by [selectedResidenceId]
 *    which callers set via [selectResidence]. The projection pulls the
 *    current selected-residence tasks out of [IDataManager.tasksByResidence].
 *  * [taskCompletionsState] is parameterised by [selectedTaskId].
 *
 * Loading / error state for the read-states is tracked separately on
 * [isLoading] and [loadError]. Mutation-feedback fields ([taskAddNewCustomTaskState])
 * remain owned by the VM — they track one-shot mutation outcomes, not
 * cached data.
 */
class TaskViewModel(
    private val dataManager: IDataManager = DataManager,
) : ViewModel() {

    // ---------- Read state (derived from DataManager) ----------

    /** All tasks kanban — mirrors [IDataManager.allTasks]. */
    val tasksState: StateFlow<ApiResult<TaskColumnsResponse>> =
        dataManager.allTasks
            .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle }
            .stateIn(
                viewModelScope,
                SharingStarted.Eagerly,
                dataManager.allTasks.value
                    ?.let { ApiResult.Success(it) } ?: ApiResult.Idle,
            )

    /** Drives the [tasksByResidenceState] projection key. */
    private val _selectedResidenceId = MutableStateFlow<Int?>(null)

    /** Per-residence kanban — mirrors [IDataManager.tasksByResidence][residenceId]. */
    val tasksByResidenceState: StateFlow<ApiResult<TaskColumnsResponse>> =
        combine(_selectedResidenceId, dataManager.tasksByResidence) { id, map ->
            if (id == null) ApiResult.Idle
            else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle
        }.stateIn(
            viewModelScope,
            SharingStarted.Eagerly,
            _selectedResidenceId.value?.let { id ->
                dataManager.tasksByResidence.value[id]?.let { ApiResult.Success(it) }
            } ?: ApiResult.Idle,
        )

    /** Drives the [taskCompletionsState] projection key. */
    private val _selectedTaskId = MutableStateFlow<Int?>(null)

    /** Task completions for the currently selected task — mirrors [IDataManager.taskCompletions]. */
    val taskCompletionsState: StateFlow<ApiResult<List<TaskCompletionResponse>>> =
        combine(_selectedTaskId, dataManager.taskCompletions) { id, map ->
            if (id == null) ApiResult.Idle
            else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle
        }.stateIn(
            viewModelScope,
            SharingStarted.Eagerly,
            _selectedTaskId.value?.let { id ->
                dataManager.taskCompletions.value[id]?.let { ApiResult.Success(it) }
            } ?: ApiResult.Idle,
        )

    // ---------- Loading / error feedback ----------

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading

    private val _loadError = MutableStateFlow<String?>(null)
    val loadError: StateFlow<String?> = _loadError

    // ---------- Mutation-feedback (independent, one-shot) ----------

    private val _taskAddNewCustomTaskState = MutableStateFlow<ApiResult<CustomTask>>(ApiResult.Idle)
    val taskAddNewCustomTaskState: StateFlow<ApiResult<CustomTask>> = _taskAddNewCustomTaskState

    // ---------- Projection selectors ----------

    fun selectResidence(residenceId: Int?) {
        _selectedResidenceId.value = residenceId
    }

    fun selectTask(taskId: Int?) {
        _selectedTaskId.value = taskId
    }

    // ---------- Load methods (write-through to DataManager) ----------

    fun loadTasks(forceRefresh: Boolean = false) {
        viewModelScope.launch {
            _isLoading.value = true
            _loadError.value = null
            val result = APILayer.getTasks(forceRefresh = forceRefresh)
            _loadError.value = (result as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun loadTasksByResidence(residenceId: Int, forceRefresh: Boolean = false) {
        viewModelScope.launch {
            _selectedResidenceId.value = residenceId
            _isLoading.value = true
            _loadError.value = null
            val result = APILayer.getTasksByResidence(
                residenceId = residenceId,
                forceRefresh = forceRefresh,
            )
            _loadError.value = (result as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun loadTaskCompletions(taskId: Int) {
        viewModelScope.launch {
            _selectedTaskId.value = taskId
            _isLoading.value = true
            _loadError.value = null
            val result = APILayer.getTaskCompletions(taskId)
            _loadError.value = (result as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun resetTaskCompletionsState() {
        _selectedTaskId.value = null
    }

    // ---------- Mutations ----------

    fun createNewTask(request: TaskCreateRequest) {
        viewModelScope.launch {
            _taskAddNewCustomTaskState.value = ApiResult.Loading
            _taskAddNewCustomTaskState.value = APILayer.createTask(request)
        }
    }

    fun resetAddTaskState() {
        _taskAddNewCustomTaskState.value = ApiResult.Idle
    }

    fun updateTask(taskId: Int, request: TaskCreateRequest, onComplete: (Boolean) -> Unit) {
        viewModelScope.launch {
            onComplete(APILayer.updateTask(taskId, request) is ApiResult.Success)
        }
    }

    fun cancelTask(taskId: Int, onComplete: (Boolean) -> Unit) {
        viewModelScope.launch {
            onComplete(APILayer.cancelTask(taskId) is ApiResult.Success)
        }
    }

    fun uncancelTask(taskId: Int, onComplete: (Boolean) -> Unit) {
        viewModelScope.launch {
            onComplete(APILayer.uncancelTask(taskId) is ApiResult.Success)
        }
    }

    fun markInProgress(taskId: Int, onComplete: (Boolean) -> Unit) {
        viewModelScope.launch {
            onComplete(APILayer.markInProgress(taskId) is ApiResult.Success)
        }
    }

    fun archiveTask(taskId: Int, onComplete: (Boolean) -> Unit) {
        viewModelScope.launch {
            onComplete(APILayer.archiveTask(taskId) is ApiResult.Success)
        }
    }

    fun unarchiveTask(taskId: Int, onComplete: (Boolean) -> Unit) {
        viewModelScope.launch {
            onComplete(APILayer.unarchiveTask(taskId) is ApiResult.Success)
        }
    }
}
