package com.tt.honeyDue.ui.screens.residence

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tt.honeyDue.analytics.AnalyticsEvents
import com.tt.honeyDue.analytics.PostHogAnalytics
import com.tt.honeyDue.models.JoinResidenceResponse
import com.tt.honeyDue.network.APILayer
import com.tt.honeyDue.network.ApiResult
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

/**
 * ViewModel for [JoinResidenceScreen] mirroring iOS JoinResidenceView.
 *
 * Holds the 6-character share code, validates it, drives the submit API
 * call through [joinWithCode], and surfaces inline error messages without
 * popping the screen. On success, [submitState] becomes
 * `ApiResult.Success(residenceId)` so the UI can navigate to the joined
 * residence's detail screen.
 *
 * [joinWithCode] and [analytics] are injected to keep the ViewModel unit
 * testable without hitting [APILayer] or PostHog singletons.
 */
class JoinResidenceViewModel(
    private val joinWithCode: suspend (String) -> ApiResult<JoinResidenceResponse> = { code ->
        APILayer.joinWithCode(code)
    },
    private val analytics: (String, Map<String, Any>) -> Unit = { name, props ->
        PostHogAnalytics.capture(name, props)
    }
) : ViewModel() {

    private val _code = MutableStateFlow("")
    val code: StateFlow<String> = _code.asStateFlow()

    private val _errorMessage = MutableStateFlow<String?>(null)
    val errorMessage: StateFlow<String?> = _errorMessage.asStateFlow()

    private val _submitState = MutableStateFlow<ApiResult<Int>>(ApiResult.Idle)
    /** Success carries the id of the joined residence. */
    val submitState: StateFlow<ApiResult<Int>> = _submitState.asStateFlow()

    /** True when the current code is exactly 6 chars and not already submitting. */
    val canSubmit: Boolean
        get() = _code.value.length == REQUIRED_LENGTH &&
            _submitState.value !is ApiResult.Loading

    /**
     * Uppercases input and truncates to [REQUIRED_LENGTH]. Matches the
     * iOS TextField onChange handler. Also clears any stale inline error so
     * the user can retry after a failure.
     */
    fun updateCode(raw: String) {
        val next = raw.uppercase().take(REQUIRED_LENGTH)
        _code.value = next
        if (_errorMessage.value != null) {
            _errorMessage.value = null
        }
    }

    /**
     * Validates length and dispatches the API call. On success fires
     * [AnalyticsEvents.RESIDENCE_JOINED] and sets [submitState] to
     * Success(residenceId). On error sets inline [errorMessage] and leaves
     * [submitState] as Error so the screen stays visible.
     */
    fun submit() {
        if (_code.value.length != REQUIRED_LENGTH) {
            _errorMessage.value = ERROR_LENGTH
            return
        }

        val code = _code.value
        viewModelScope.launch {
            _errorMessage.value = null
            _submitState.value = ApiResult.Loading

            when (val result = joinWithCode(code)) {
                is ApiResult.Success -> {
                    val residenceId = result.data.residence.id
                    analytics(
                        AnalyticsEvents.RESIDENCE_JOINED,
                        mapOf("residence_id" to residenceId)
                    )
                    _submitState.value = ApiResult.Success(residenceId)
                }
                is ApiResult.Error -> {
                    _errorMessage.value = result.message
                    _submitState.value = ApiResult.Error(result.message, result.code)
                }
                ApiResult.Loading -> {
                    _submitState.value = ApiResult.Loading
                }
                ApiResult.Idle -> {
                    _submitState.value = ApiResult.Idle
                }
            }
        }
    }

    /** Reset the transient submit state (e.g. when re-entering the screen). */
    fun resetSubmitState() {
        _submitState.value = ApiResult.Idle
    }

    companion object {
        const val REQUIRED_LENGTH = 6
        const val ERROR_LENGTH = "Share code must be 6 characters"
    }
}
