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.ContractorSummary
import com.tt.honeyDue.models.MyResidencesResponse
import com.tt.honeyDue.models.Residence
import com.tt.honeyDue.models.ResidenceCreateRequest
import com.tt.honeyDue.models.TaskColumnsResponse
import com.tt.honeyDue.models.TotalSummary
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

/**
 * ResidenceViewModel — read-state derived from [IDataManager].
 *
 * All list/detail reads (`residencesState`, `myResidencesState`,
 * `summaryState`, `residenceTasksState`, `residenceContractorsState`)
 * are reactive projections of [IDataManager] StateFlows. Mutation
 * feedback (create/update/delete/join/cancel/uncancel/updateTask/
 * generateReport) remains owned by the VM as one-shot [ApiResult]
 * fields — they track API operation outcomes, not cached data.
 */
class ResidenceViewModel(
    private val dataManager: IDataManager = DataManager,
) : ViewModel() {

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

    val residencesState: StateFlow<ApiResult<List<Residence>>> =
        dataManager.residences
            .map { list -> if (list.isNotEmpty()) ApiResult.Success(list) else ApiResult.Idle }
            .stateIn(
                viewModelScope,
                SharingStarted.Eagerly,
                dataManager.residences.value
                    .takeIf { it.isNotEmpty() }
                    ?.let { ApiResult.Success(it) } ?: ApiResult.Idle,
            )

    val myResidencesState: StateFlow<ApiResult<MyResidencesResponse>> =
        dataManager.myResidences
            .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle }
            .stateIn(
                viewModelScope,
                SharingStarted.Eagerly,
                dataManager.myResidences.value
                    ?.let { ApiResult.Success(it) } ?: ApiResult.Idle,
            )

    val summaryState: StateFlow<ApiResult<TotalSummary>> =
        dataManager.totalSummary
            .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle }
            .stateIn(
                viewModelScope,
                SharingStarted.Eagerly,
                dataManager.totalSummary.value
                    ?.let { ApiResult.Success(it) } ?: ApiResult.Idle,
            )

    /** Drives the residence-scoped projections. */
    private val _selectedResidenceId = MutableStateFlow<Int?>(null)

    val residenceTasksState: 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,
        )

    val residenceContractorsState: StateFlow<ApiResult<List<ContractorSummary>>> =
        combine(_selectedResidenceId, dataManager.contractorsByResidence) { 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.contractorsByResidence.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 (one-shot, owned by VM) ----------

    private val _createResidenceState = MutableStateFlow<ApiResult<Residence>>(ApiResult.Idle)
    val createResidenceState: StateFlow<ApiResult<Residence>> = _createResidenceState

    private val _updateResidenceState = MutableStateFlow<ApiResult<Residence>>(ApiResult.Idle)
    val updateResidenceState: StateFlow<ApiResult<Residence>> = _updateResidenceState

    private val _deleteResidenceState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val deleteResidenceState: StateFlow<ApiResult<Unit>> = _deleteResidenceState

    private val _joinResidenceState = MutableStateFlow<ApiResult<com.tt.honeyDue.models.JoinResidenceResponse>>(ApiResult.Idle)
    val joinResidenceState: StateFlow<ApiResult<com.tt.honeyDue.models.JoinResidenceResponse>> = _joinResidenceState

    private val _cancelTaskState = MutableStateFlow<ApiResult<com.tt.honeyDue.models.CustomTask>>(ApiResult.Idle)
    val cancelTaskState: StateFlow<ApiResult<com.tt.honeyDue.models.CustomTask>> = _cancelTaskState

    private val _uncancelTaskState = MutableStateFlow<ApiResult<com.tt.honeyDue.models.CustomTask>>(ApiResult.Idle)
    val uncancelTaskState: StateFlow<ApiResult<com.tt.honeyDue.models.CustomTask>> = _uncancelTaskState

    private val _updateTaskState = MutableStateFlow<ApiResult<com.tt.honeyDue.models.CustomTask>>(ApiResult.Idle)
    val updateTaskState: StateFlow<ApiResult<com.tt.honeyDue.models.CustomTask>> = _updateTaskState

    private val _generateReportState = MutableStateFlow<ApiResult<com.tt.honeyDue.network.GenerateReportResponse>>(ApiResult.Idle)
    val generateReportState: StateFlow<ApiResult<com.tt.honeyDue.network.GenerateReportResponse>> = _generateReportState

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

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

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

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

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

    fun getResidence(id: Int, onResult: (ApiResult<Residence>) -> Unit) {
        viewModelScope.launch {
            onResult(APILayer.getResidence(id))
        }
    }

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

    fun loadResidenceTasks(residenceId: Int) {
        viewModelScope.launch {
            _selectedResidenceId.value = residenceId
            _isLoading.value = true
            _loadError.value = null
            _loadError.value = (APILayer.getTasksByResidence(residenceId) as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun loadResidenceContractors(residenceId: Int) {
        viewModelScope.launch {
            _selectedResidenceId.value = residenceId
            _isLoading.value = true
            _loadError.value = null
            _loadError.value = (APILayer.getContractorsByResidence(residenceId) as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun resetResidenceTasksState() {
        _selectedResidenceId.value = null
    }

    fun resetResidenceContractorsState() {
        _selectedResidenceId.value = null
    }

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

    fun createResidence(request: ResidenceCreateRequest) {
        viewModelScope.launch {
            _createResidenceState.value = ApiResult.Loading
            _createResidenceState.value = APILayer.createResidence(request)
        }
    }

    fun updateResidence(residenceId: Int, request: ResidenceCreateRequest) {
        viewModelScope.launch {
            _updateResidenceState.value = ApiResult.Loading
            _updateResidenceState.value = APILayer.updateResidence(residenceId, request)
        }
    }

    fun resetCreateState() { _createResidenceState.value = ApiResult.Idle }
    fun resetUpdateState() { _updateResidenceState.value = ApiResult.Idle }

    fun cancelTask(taskId: Int) {
        viewModelScope.launch {
            _cancelTaskState.value = ApiResult.Loading
            _cancelTaskState.value = APILayer.cancelTask(taskId)
        }
    }

    fun uncancelTask(taskId: Int) {
        viewModelScope.launch {
            _uncancelTaskState.value = ApiResult.Loading
            _uncancelTaskState.value = APILayer.uncancelTask(taskId)
        }
    }

    fun updateTask(taskId: Int, request: com.tt.honeyDue.models.TaskCreateRequest) {
        viewModelScope.launch {
            _updateTaskState.value = ApiResult.Loading
            _updateTaskState.value = APILayer.updateTask(taskId, request)
        }
    }

    fun resetCancelTaskState() { _cancelTaskState.value = ApiResult.Idle }
    fun resetUncancelTaskState() { _uncancelTaskState.value = ApiResult.Idle }
    fun resetUpdateTaskState() { _updateTaskState.value = ApiResult.Idle }

    fun generateTasksReport(residenceId: Int, email: String? = null) {
        viewModelScope.launch {
            _generateReportState.value = ApiResult.Loading
            _generateReportState.value = APILayer.generateTasksReport(residenceId, email)
        }
    }

    fun resetGenerateReportState() { _generateReportState.value = ApiResult.Idle }

    fun deleteResidence(residenceId: Int) {
        viewModelScope.launch {
            _deleteResidenceState.value = ApiResult.Loading
            _deleteResidenceState.value = APILayer.deleteResidence(residenceId)
        }
    }

    fun resetDeleteResidenceState() { _deleteResidenceState.value = ApiResult.Idle }

    fun joinWithCode(code: String) {
        viewModelScope.launch {
            _joinResidenceState.value = ApiResult.Loading
            _joinResidenceState.value = APILayer.joinWithCode(code)
        }
    }

    fun resetJoinResidenceState() { _joinResidenceState.value = ApiResult.Idle }
}
