@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.viewmodel

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.gaudian.translator.model.Language
import eu.gaudian.translator.model.repository.LanguageListType
import eu.gaudian.translator.model.repository.LanguageRepository
import eu.gaudian.translator.utils.Log
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import javax.inject.Inject

/**
 * LanguageViewModel - Hilt-enabled ViewModel for language management
 *
 * This ViewModel uses Hilt for dependency injection and manages language-related state
 * including selected languages, language lists, and language preferences.
 */
@HiltViewModel
class LanguageViewModel @Inject constructor(
    application: Application,
    private val languageRepository: LanguageRepository
) : AndroidViewModel(application) {

    private val languageSwitchMutex = Mutex()

    // Enabled languages (visible across the app)
    val allLanguages: StateFlow<List<Language>> = languageRepository.loadLanguages(LanguageListType.ALL)
        .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())

    // Master catalog (DEFAULT + CUSTOM), used by LanguageOptionsScreen to toggle visibility
    val masterLanguages: StateFlow<List<Language>> = languageRepository.loadMasterLanguages()
        .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())

    val favoriteLanguages: StateFlow<List<Language>> = languageRepository.loadLanguages(LanguageListType.FAVORITE)
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

    val languageHistory: StateFlow<List<Language>> = languageRepository.loadLanguages(LanguageListType.HISTORY)
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

    val selectedSourceLanguage: StateFlow<Language?> = languageRepository.loadSelectedSourceLanguage()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)

    val selectedTargetLanguage: StateFlow<Language?> = languageRepository.loadSelectedTargetLanguage()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)

    val selectedDictionaryLanguage: StateFlow<Language?> = languageRepository.loadSelectedDictionaryLanguage()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)

    val isAllSelected: StateFlow<Boolean> = kotlinx.coroutines.flow.combine(masterLanguages, allLanguages) { master, enabled ->
        val masterIds = master.map { it.nameResId }.toSet()
        val enabledIds = enabled.map { it.nameResId }.toSet()
        masterIds.isNotEmpty() && enabledIds.containsAll(masterIds)
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)


    suspend fun getLanguageById(id: Int): Language {
        val languages = allLanguages.first { it.isNotEmpty() }

        val language = languages.find { it.nameResId == id }

        if (language == null) {
            Log.e("LanguageViewModel", "Language with ID $id not found, returning dummy language.")
            return Language(
                code = "error",
                region = "error",
                nameResId = 0,
                name = "Error",
                englishName = "Error",
                isCustom = false,
                isSelected = false
            )
        }

        return language
    }

    fun getLanguageByIdFlow(id: Int?): Flow<Language?> {
        return allLanguages.map { languages ->
            languages.find { it.nameResId == id }
        }
    }

    fun switchLanguages() {
        viewModelScope.launch {
            languageSwitchMutex.withLock {
                val source = selectedSourceLanguage.value
                val target = selectedTargetLanguage.value
                languageRepository.saveSelectedSourceLanguage(target)
                languageRepository.saveSelectedTargetLanguage(source)
            }
        }
    }

    fun setSelectedSourceLanguage(languageId: Int?) {
        viewModelScope.launch {
            if (languageId == 0 || languageId == null) {
                languageRepository.saveSelectedSourceLanguage(null)
                return@launch
            }
            val language = getLanguageById(languageId)
            languageRepository.saveSelectedSourceLanguage(language)
        }
    }

    fun setSelectedTargetLanguage(languageId: Int?) {
        viewModelScope.launch {
            val language = if (languageId != null) getLanguageById(languageId) else null
            languageRepository.saveSelectedTargetLanguage(language)
        }
    }

    fun setSelectedSourceLanguage(language: Language?) {
        viewModelScope.launch {
            languageRepository.saveSelectedSourceLanguage(language)
        }
    }

    fun setSelectedTargetLanguage(language: Language?) {
        viewModelScope.launch {
            languageRepository.saveSelectedTargetLanguage(language)
        }
    }

    fun setSelectedDictionaryLanguage(language: Language?) {
        viewModelScope.launch {
            languageRepository.saveSelectedDictionaryLanguage(language)
        }
    }

    fun updateFavoriteLanguages(languages: List<Language>) {
        viewModelScope.launch {
            languageRepository.saveLanguages(LanguageListType.FAVORITE, languages)
        }
    }

    fun updateLanguageHistory(languages: List<Language>) {
        viewModelScope.launch {
            languageRepository.saveLanguages(LanguageListType.HISTORY, languages)
        }
    }

    fun addCustomLanguage(language: Language) {
        viewModelScope.launch {
            languageRepository.addCustomLanguage(language)
            // No need to re-observe. The 'allLanguages' and 'customLanguages' StateFlows will update automatically.
        }
    }

    fun removeCustomLanguage(languageToRemove: Language) {
        viewModelScope.launch {
            languageRepository.deleteCustomLanguage(languageToRemove)
            // No need to re-observe. Flows will update automatically.
        }
    }

    fun selectAllLanguages(isSelected: Boolean) {
        viewModelScope.launch {
            val masterIds = masterLanguages.value.map { it.nameResId }
            languageRepository.setEnabledLanguagesByIds(if (isSelected) masterIds else emptyList())
        }
    }

    fun toggleLanguageSelection(languageToToggle: Language) {
        viewModelScope.launch {
            val enabledIds = allLanguages.value.map { it.nameResId }.toMutableSet()
            if (enabledIds.contains(languageToToggle.nameResId)) {
                enabledIds.remove(languageToToggle.nameResId)
            } else {
                enabledIds.add(languageToToggle.nameResId)
            }
            languageRepository.setEnabledLanguagesByIds(enabledIds.toList())
        }
    }

    fun editLanguage(languageId: Int, newName: String, newCode: String, newRegion: String) {
        viewModelScope.launch {
            languageRepository.editCustomLanguage(languageId, newName, newCode, newRegion)
        }
    }
}
