package app.closer.ui.pairing

import android.util.Log
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.closer.core.navigation.AppRoute
import app.closer.crypto.CoupleEncryptionManager
import app.closer.domain.repository.AuthRepository
import app.closer.domain.repository.InviteRepository
import app.closer.domain.repository.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
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 javax.inject.Inject

data class InviteConfirmUiState(
    val isLoading: Boolean = true,
    val inviterName: String? = null,
    val error: String? = null,
    val navigateTo: String? = null,
    val isConfirming: Boolean = false
)

@HiltViewModel
class InviteConfirmViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val authRepository: AuthRepository,
    private val inviteRepository: InviteRepository,
    private val encryptionManager: CoupleEncryptionManager,
    private val userRepository: UserRepository
) : ViewModel() {

    private val inviteCode: String = savedStateHandle["inviteCode"] ?: ""

    private val _uiState = MutableStateFlow(InviteConfirmUiState())
    val uiState: StateFlow<InviteConfirmUiState> = _uiState.asStateFlow()

    init {
        viewModelScope.launch {
            _uiState.update {
                it.copy(isLoading = false, inviterName = "your partner")
            }
        }
    }

    fun confirmPairing() {
        if (authRepository.currentUserId == null) {
            _uiState.update { it.copy(error = "Not signed in.") }
            return
        }
        _uiState.update { it.copy(isConfirming = true, error = null) }
        viewModelScope.launch {
            inviteRepository.acceptInvite(inviteCode)
                .onSuccess { result ->
                    val phrase = result.recoveryPhrase
                    if (phrase != null && result.wrappedKey.cipherB64.isNotBlank()) {
                        encryptionManager.unwrapAndStore(result.coupleId, result.wrappedKey, phrase)
                            .onSuccess {
                                navigateToPairingSuccess(result.coupleId)
                            }
                            .onFailure { e ->
                                _uiState.update { it.copy(isConfirming = false, error = recoveryErrorMessage(e)) }
                            }
                    } else {
                        navigateToPairingSuccess(result.coupleId)
                    }
                }
                .onFailure { e ->
                    _uiState.update { it.copy(isConfirming = false, error = callableErrorMessage(e)) }
                }
        }
    }

    private fun navigateToPairingSuccess(coupleId: String) {
        _uiState.update {
            it.copy(isConfirming = false, navigateTo = AppRoute.pairingSuccess(coupleId))
        }
    }

    fun onNavigated() = _uiState.update { it.copy(navigateTo = null) }
    fun dismissError() = _uiState.update { it.copy(error = null) }

    private fun recoveryErrorMessage(e: Throwable): String = when {
        (e.message ?: "").contains("AEADBadTag", ignoreCase = true) ||
        (e.message ?: "").contains("decryption", ignoreCase = true) ->
            "Couldn't unlock the couple key. Please try pairing again."
        else -> e.message ?: "Couldn't unlock the couple key. Please try again."
    }

    private fun callableErrorMessage(e: Throwable): String {
        val msg = e.message ?: ""
        return when {
            msg.contains("not-found", ignoreCase = true) -> "Code not found. Double-check with your partner."
            msg.contains("failed-precondition", ignoreCase = true) ->
                if (msg.contains("expired", ignoreCase = true)) "This code has expired. Ask your partner to create a new one."
                else if (msg.contains("already been used", ignoreCase = true)) "This code has already been used."
                else if (msg.contains("already paired", ignoreCase = true)) "You are already paired."
                else "Couldn't complete pairing. Please try again."
            msg.contains("permission-denied", ignoreCase = true) -> "You cannot accept your own invite."
            msg.contains("unauthenticated", ignoreCase = true) -> "Not signed in."
            else -> e.message ?: "Couldn't complete pairing. Please try again."
        }
    }

    companion object {
        private const val TAG = "InviteConfirmViewModel"
    }
}
