@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.viewmodel

import android.app.Activity
import android.app.Application
import android.content.Intent
import android.net.Uri
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.gaudian.translator.model.CardSet
import eu.gaudian.translator.model.Language
import eu.gaudian.translator.model.VocabularyCategory
import eu.gaudian.translator.model.VocabularyGrammarDetails
import eu.gaudian.translator.model.VocabularyItem
import eu.gaudian.translator.model.VocabularyStage
import eu.gaudian.translator.model.jsonParser
import eu.gaudian.translator.model.repository.LanguageConfigRepository
import eu.gaudian.translator.model.repository.LanguageListType
import eu.gaudian.translator.model.repository.LanguageRepository
import eu.gaudian.translator.model.repository.VocabularyFileSaver
import eu.gaudian.translator.model.repository.VocabularyRepository
import eu.gaudian.translator.utils.Log
import eu.gaudian.translator.utils.StatusAction
import eu.gaudian.translator.utils.StatusMessageId
import eu.gaudian.translator.utils.StatusMessageService
import eu.gaudian.translator.utils.StringHelper
import eu.gaudian.translator.utils.VocabularyService
import eu.gaudian.translator.utils.dictionary.DictionaryService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import javax.inject.Inject
import kotlin.system.measureTimeMillis
import kotlin.time.ExperimentalTime

@HiltViewModel
class VocabularyViewModel @Inject constructor(
    application: Application,
    private val vocabularyRepository: VocabularyRepository,
    private val languageRepository: LanguageRepository,
    private val languageConfigRepository: LanguageConfigRepository,
    private val vocabularyItemService: VocabularyService,
    private val dictionaryService: DictionaryService,
    private val statusService: StatusMessageService,
) : AndroidViewModel(application) {
    fun extractUniqueWords(text: String): List<String> {
        if (text.isBlank()) return emptyList()
        val words = text.lowercase()
            .replace("\n", " ")
            .split(Regex("""[^\p{L}\p{Nd}']+"""))
            .map { it.trim('"', '\'', '(', ')', '[', ']', '{', '}', '.', ',', '!', '?', ';', ':') }
            .filter { it.isNotBlank() }
        return words.distinct()
    }

    fun generateVocabularyFromText(text: String) {
        viewModelScope.launch {
            try {
                val src = languageRepository.loadSelectedSourceLanguage().first()
                val tgt = languageRepository.loadSelectedTargetLanguage().first()
                if (src == null || tgt == null) {
                    statusService.showErrorMessage("Source and target languages must be selected.")
                    return@launch
                }
                val words = extractUniqueWords(text)
                if (words.isEmpty()) {
                    statusService.showErrorMessage("No words found in the provided text.")
                    return@launch
                }
                _isGenerating.value = true
                statusService.showLoadingMessage("Translating ${words.size} words…")
                val result = vocabularyItemService.translateWordsBatch(words, src, tgt)
                result.onSuccess { items ->
                    _generatedVocabularyItems.value = items
                    statusService.trigger(StatusAction.CancelLoadingOperation)
                }.onFailure { ex ->
                    statusService.showErrorMessage("Failed to translate words: ${ex.message}")
                }
            } catch (e: Exception) {
                statusService.showErrorMessage("Unexpected error: ${e.message}")
            } finally {
                _isGenerating.value = false
            }
        }
    }


    @Suppress("PrivatePropertyName")
    private val TAG = "VocabularyViewModel"

    val vocabularyItems: StateFlow<List<VocabularyItem>> = vocabularyRepository.getAllVocabularyItemsFlow()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

    val categories: StateFlow<List<VocabularyCategory>> = vocabularyRepository.getAllCategoriesFlow()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

    val dueTodayItems: StateFlow<List<VocabularyItem>> = vocabularyRepository.getDueTodayItemsFlow()
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.Eagerly,
            initialValue = emptyList()
        )
    val languagesPresent: StateFlow<Set<Int?>> = vocabularyItems
        .map { items ->
            items.flatMap { listOf(it.languageFirstId, it.languageSecondId) }.toSet()
        }
        .distinctUntilChanged()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptySet())



    val stageStats: StateFlow<List<StageStats>> = vocabularyItems.map {
        vocabularyRepository.calculateStageStatistics()
    }
        .flowOn(Dispatchers.Default)
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )

    val stageMapping: StateFlow<Map<Int, VocabularyStage>> = vocabularyRepository.loadStageMapping()
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyMap())

    private val _cardSet = MutableStateFlow<CardSet?>(null)
    val cardSet: StateFlow<CardSet?> = _cardSet.asStateFlow()

    private val fileSaver = VocabularyFileSaver(application, vocabularyRepository)
    private val _saveStatus = MutableLiveData<String?>()
    private lateinit var saveFileLauncher: ActivityResultLauncher<Intent>

    private val _isGenerating = MutableStateFlow(false)
    val isGenerating: StateFlow<Boolean> = _isGenerating.asStateFlow()

    private val _generationResult = MutableSharedFlow<String>()


    private val _generatedVocabularyItems = MutableStateFlow<List<VocabularyItem>>(emptyList())
    val generatedVocabularyItems: StateFlow<List<VocabularyItem>> = _generatedVocabularyItems.asStateFlow()

    private val _idFilter = MutableStateFlow<Set<Int>?>(null)

    // Navigation state for VocabularyCardHost
    private val _currentNavigationItems = MutableStateFlow<List<VocabularyItem>>(emptyList())
    val currentNavigationItems: StateFlow<List<VocabularyItem>> = _currentNavigationItems.asStateFlow()

    private val _currentNavigationPosition = MutableStateFlow(0)
    val currentNavigationPosition: StateFlow<Int> = _currentNavigationPosition.asStateFlow()

    val newItemsCount: StateFlow<Int> = combine(vocabularyItems, stageMapping) { items, stageMap ->
        if (stageMap.isEmpty() && items.isNotEmpty()) {
            items.size
        } else {
            items.count { (stageMap[it.id] ?: VocabularyStage.NEW) == VocabularyStage.NEW }
        }
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0)

    /**
     * A flow that contains a list of all vocabulary items that have at least one duplicate in the database.
     * Duplicates are determined by comparing words and languages, ignoring order. This serves as the primary
     * function to find all duplicates.
     */
    val allDuplicateItems: StateFlow<List<VocabularyItem>> = vocabularyItems
        .map { items ->
            // Group items by their content (words and languages, order-independent)
            items.groupBy {
                // The key for grouping is a pair of sets: one for words, one for language IDs.
                Pair(
                    setOf(it.wordFirst.lowercase(), it.wordSecond.lowercase()),
                    setOf(it.languageFirstId, it.languageSecondId)
                )
            }
                .values // We only need the groups of items, not the keys
                .filter { group -> group.size > 1 } // A group with more than one item signifies duplicates
                .flatten() // Convert the list of duplicate groups into a single list of all duplicate items
        }
        .flowOn(Dispatchers.Default) // Perform this potentially heavy computation on a background thread
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )

    /**
     * A flow that provides the total count of duplicate vocabulary items.
     * This is derived from the `allDuplicateItems` flow.
     */
    val duplicateItemsCount: StateFlow<Int> = allDuplicateItems
        .map { it.size }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = 0
        )

    var categoryVocabularyItemDelete: Int = 0

    init {
        Log.d(TAG, "Initializing VocabularyViewModel")

        viewModelScope.launch {
            val duration = measureTimeMillis {
                vocabularyRepository.initializeRepository()
            }
            Log.d(TAG, "init: Repositories initialized in ${duration}ms")

            val stageMap = stageMapping.first()
            val itemCount = vocabularyItems.first().size
            Log.d(TAG, "DEBUG: After init - Items: $itemCount, Stage mappings: ${stageMap.size}")
        }
    }

    /**
     * Returns a Flow that emits a single VocabularyItem, updating only when that specific item changes.
     * This is more efficient than observing the entire list for changes to a single item.
     *
     * @param id The ID of the vocabulary item to observe.
     * @return A Flow that emits the VocabularyItem with the given ID, or null if it doesn't exist.
     */
    fun getVocabularyItemFlow(id: Int): Flow<VocabularyItem?> {
        Log.d(TAG, "Setting up a flow for item ID $id")
        return vocabularyItems
            .map { items ->
                items.find { it.id == id }
            }
            .distinctUntilChanged()
    }

    fun clearCardSet() {
        _cardSet.value = null
    }

    fun filterByIds(ids: List<Int>) {
        _idFilter.value = ids.toSet()
    }
    fun clearFilter() {
        _idFilter.value = null
    }


    fun addVocabularyItemToCategory(vocabularyItems: List<VocabularyItem>, categoryId: Int) {
        Log.d(TAG, "Adding ${vocabularyItems.size} vocabulary items to category $categoryId")
        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    vocabularyItems.forEach { item ->
                        vocabularyRepository.addVocabularyItemToList(item.id, categoryId)
                    }
                }
                Log.d(TAG, "Successfully added vocabulary items to category in ${duration}ms")
            } catch (e: Exception) {
                statusService.showErrorMessage("Error in addVocabularyItemToCategory: ${e.message}")
                Log.e(TAG, "Error in addVocabularyItemToCategory: ${e.message}")
            }
        }
    }
    fun addVocabularyItemToCategories(vocabularyItems: List<VocabularyItem>, categoryIds: List<Int>) {
        Log.d("Adding vocabulary item to categories: $categoryIds")
        for (categoryId in categoryIds) {
            addVocabularyItemToCategory(vocabularyItems, categoryId)
        }
    }

    fun removeVocabularyItemsFromCategory(items: List<VocabularyItem>, categoryId: Int) {
        Log.d(TAG, "Removing ${items.size} vocabulary items from category $categoryId")
        if (items.isEmpty()) return

        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    items.forEach { item ->
                        vocabularyRepository.removeVocabularyItemFromList(item.id, categoryId)
                    }
                }
                Log.d(TAG, "Successfully removed vocabulary items from category in ${duration}ms")
            } catch (e: Exception) {
                statusService.showErrorMessage("Error removing items from category: ${e.message}")
                Log.e(TAG, "Error in removeVocabularyItemsFromCategory: ${e.message}")
            }
        }
    }

    fun addVocabularyItemToStage(vocabularyItems: List<VocabularyItem>, stage: VocabularyStage) {
        Log.d(TAG, "Adding ${vocabularyItems.size} vocabulary items to stage $stage")
        viewModelScope.launch {
            try {

                vocabularyRepository.changeVocabularyItemsStage(vocabularyItems, stage)
            } catch (e: Exception) {
                statusService.showErrorMessage("Error in addVocabularyItemToStage: ${e.message}")
                Log.e(TAG, "Error in addVocabularyItemToStage: ${e.message}")
            }
        }
    }

    fun addVocabularyItems(items: List<VocabularyItem>, categoryIds: List<Int> = emptyList()) {
        Log.d(TAG, "Adding ${items.size} new vocabulary items, categories: $categoryIds")
        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    vocabularyRepository.introduceVocabularyItems(items, categoryIds)
                }
                Log.d(
                    TAG,
                    "Successfully added ${items.size} new vocabulary items in ${duration}ms"
                )
            } catch (e: Exception) {
                statusService.showErrorMessage("Error adding items: ${e.message}")
                Log.e(TAG, "Error adding items: ${e.message}")
            }
        }
    }



    fun deleteVocabularyItemsById(list: List<Int>) {
        Log.d(TAG, "Deleting vocabulary items with IDs: $list")
        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    vocabularyRepository.deleteVocabularyItemsByIds(list)
                }
                Log.d(TAG, "Successfully deleted vocabulary items in ${duration}ms")
            } catch (e: Exception) {
                statusService.showErrorMessage("Error deleting items: ${e.message}")
                Log.e(TAG, "Error deleting item: ${e.message}")
            }
        }
    }

    suspend fun editVocabularyItem(vocabularyItem: VocabularyItem) {
        val itemWithNewFrequency = fetchAndUpdateZipfFrequency(vocabularyItem)

        Log.d(TAG, "Editing vocabulary item: ${vocabularyItem.id}")
        try {
            val duration = measureTimeMillis {
                vocabularyRepository.editVocabularyItem(itemWithNewFrequency)
            }
            Log.d(TAG, "Successfully edited vocabulary item in ${duration}ms")
        } catch (e: Exception) {
            statusService.showErrorMessage("Error in editVocabularyItem: ${e.message}")
            Log.e(TAG, "Error in editVocabularyItem: ${e.message}")
        }
    }


    suspend fun findDuplicates(items: List<VocabularyItem>): List<Boolean> {
        val allItems = vocabularyRepository.getAllVocabularyItems()
        val results = items.map { item ->
            val duplicateItem = allItems.find { existingItem -> item.isDuplicate(existingItem) }
            duplicateItem != null
        }
        results.count { it }
        return results
    }

    /**
     * Creates a flow to perform a quick check if a single vocabulary item has any duplicates.
     *
     * @param itemId The ID of the item to check.
     * @return A Flow that emits `true` if a duplicate exists, `false` otherwise.
     */
    fun isDuplicateFlow(itemId: Int): Flow<Boolean> = vocabularyItems.map { allItems ->
        val currentItem = allItems.find { it.id == itemId }
        if (currentItem != null) {
            // Check if there is any *other* item that is a duplicate of the current one.
            allItems.any { otherItem ->
                otherItem.id != currentItem.id && currentItem.isDuplicate(otherItem)
            }
        } else {
            false // Item not found, so it can't have a duplicate.
        }
    }.distinctUntilChanged()

    /**
     * Finds all items in the repository that are duplicates of the given item, excluding the item itself.
     */
    fun getDuplicatesOf(item: VocabularyItem): Flow<List<VocabularyItem>> {
        return vocabularyItems.map { allItems ->
            allItems.filter { otherItem ->
                item.id != otherItem.id && item.isDuplicate(otherItem)
            }
        }
    }

    /**
     * Handles the merging of two duplicate vocabulary items.
     * Placeholder logic: Deletes the new item, effectively keeping the original.
     * A full implementation would merge properties like stage, categories, and features.
     */
    fun mergeDuplicateItems(newItem: VocabularyItem, existingItem: VocabularyItem) {
        Log.d(TAG, "mergeDuplicateItems: Merging ${newItem.id} into ${existingItem.id}. (Placeholder logic)")
        //TODO
        // Placeholder: For now, this just deletes the new item.
        // A full implementation would merge stages, categories, etc., and update the existing item based on the rules.
        viewModelScope.launch {
            statusService.showSuccessMessage("Items merged!", 2)
            deleteVocabularyItemsById(listOf(newItem.id))
        }
    }


    fun deleteData(type: DeleteType, id: Int? = null, item: VocabularyItem? = null, items: List<VocabularyItem>? = null, categoryId: Int? = null) {
        Log.d(TAG, "Deleting data of type $type")
        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    when (type) {
                        DeleteType.VOCABULARY_ITEM_BY_ID -> id?.let { vocabularyRepository.deleteVocabularyItemById(it) }
                        DeleteType.VOCABULARY_ITEM -> item?.let { vocabularyRepository.deleteVocabularyItemById(it.id) }
                        DeleteType.VOCABULARY_ITEMS -> items?.map { it.id }?.let { vocabularyRepository.deleteVocabularyItemsByIds(it) }
                        DeleteType.REMOVE_FROM_CATEGORY -> {
                            if (id != null && categoryId != null) {
                                vocabularyRepository.removeVocabularyItemFromList(id, categoryId)
                            }
                        }
                    }
                }
                Log.d(TAG, "deleteData of type $type completed in ${duration}ms")
            } catch (e: Exception) {
                statusService.showErrorMessage("Error in deleteData: ${e.message}")
                Log.e(TAG, "Error in deleteData: ${e.message}")
            }
        }
    }

    @Deprecated("use the new filterVocabularyItems")
    fun filterVocabularyItems(languageFirst: Language?, languageSecond: Language?, query: String?, categoryId: Int?, stage: VocabularyStage?): Flow<List<VocabularyItem>> {
        Log.d(TAG, "[DEPRECATED] filterVocabularyItems called.")
        val languages = listOfNotNull(languageFirst, languageSecond).ifEmpty { null }?.map { it.nameResId }
        return filterVocabularyItems(languages = languages, query = query, categoryId = categoryId, stage = stage, sortOrder = SortOrder.NEWEST_FIRST)
    }

    fun filterVocabularyItems(
        languages: List<Int>?,
        query: String?,
        categoryId: Int?, // Accepts a single category ID
        stage: VocabularyStage?,
        wordClass: String? = null,
        dueTodayOnly: Boolean = false,
        sortOrder: SortOrder
    ): Flow<List<VocabularyItem>> {
        Log.d(TAG, "[DEPRECATED] filterVocabularyItems called. with args: " +
                "languages=$languages, query=$query, categoryId=$categoryId, stage=$stage, " +
                "wordClass=$wordClass, dueTodayOnly=$dueTodayOnly, sortOrder=$sortOrder")

        return filterVocabularyItems(
            languages = languages,
            query = query,
            categoryIds = categoryId?.let { listOf(it) },
            stage = stage,
            wordClass = wordClass,
            dueTodayOnly = dueTodayOnly,
            sortOrder = sortOrder
        )
    }




    /**
     * Filters vocabulary items based on multiple criteria, including a list of category IDs and a specific word class.
     *
     * @param languages A list of language resource IDs to filter by.
     * @param query A search string to match against the words.
     * @param categoryIds A list of category IDs to filter by.
     * @param stage The vocabulary stage to filter by.
     * @param wordClass The grammatical word class (e.g., "noun", "verb") to filter by.
     * @param dueTodayOnly If true, only includes items due for review today.
     * @param sortOrder The order to sort the final list.
     * @return A Flow emitting the filtered and sorted list of VocabularyItems.
     */
    fun filterVocabularyItems(
        languages: List<Int>?,
        query: String?,
        categoryIds: List<Int>?,
        stage: VocabularyStage?,
        wordClass: String? = null,
        dueTodayOnly: Boolean = false,
        sortOrder: SortOrder
    ): Flow<List<VocabularyItem>> {
        Log.d(TAG, "Setting up filterVocabularyItems Flow with categoryIds: $categoryIds, stage: $stage, wordClass: $wordClass, dueToday: $dueTodayOnly, sort: $sortOrder")

        val categoryItemsFlow: Flow<Set<Int>?> = if (categoryIds.isNullOrEmpty() || categoryIds.contains(0)) {
            Log.d(TAG, "Category filter: DISABLED (null/empty/contains 0)")
            flowOf(null)
        } else {
            Log.d(TAG, "Category filter: ENABLED for categories $categoryIds")
            vocabularyRepository.getCategoryMappingsFlow().map { mappings ->
                mappings.filter { it.categoryId in categoryIds }
                    .map { it.vocabularyItemId }
                    .toSet()
            }
        }

        return combine(
            vocabularyItems,
            dueTodayItems,
            _idFilter,
            categoryItemsFlow,
            if (stage == null) flowOf(null) else stageMapping.map { it } // Pass the full stage mapping instead of pre-filtering
        ) { allItems, dueItems, idFilterSet, categoryItemsSet, stageMappingMap ->

            if (allItems.isEmpty()) {
                Log.d(TAG, "filterVocabularyItems: Waiting for vocabulary items to load...")
                return@combine emptyList()
            }

            if (stage != null && stageMappingMap.isNullOrEmpty()) {
                Log.d(TAG, "filterVocabularyItems: Items loaded (${allItems.size}) but stage mapping empty, triggering initialization...")
                viewModelScope.launch {
                    vocabularyRepository.actualizeVocabularyStageMappings()
                }
                return@combine emptyList()
            }

            val preFilteredItems = if (idFilterSet != null) {
                allItems.filter { it.id in idFilterSet }
            } else {
                allItems
            }

            Log.d(TAG, "--- Starting Filter ---")
            Log.d(TAG, "Items to filter: ${preFilteredItems.size}")
            Log.d(TAG, "Filter criteria: wordClass='$wordClass'")

            var filteredList: List<VocabularyItem>
            val duration = measureTimeMillis {
                val dueItemsSet = if (dueTodayOnly) dueItems.map { it.id }.toSet() else emptySet()
                val languageIdSet = languages?.takeIf { it.isNotEmpty() }?.toSet()

                filteredList = preFilteredItems.filter { item ->
                    val languageMatch = languageIdSet.isNullOrEmpty() ||
                            item.languageFirstId in languageIdSet || item.languageSecondId in languageIdSet
                    val queryMatch = query.isNullOrEmpty() ||
                            item.wordFirst.contains(query, ignoreCase = true) || item.wordSecond.contains(query, ignoreCase = true)
                    val categoryMatch = categoryItemsSet == null || item.id in categoryItemsSet

                    val stageMatch = if (stage == null) {
                        true
                    } else if (stageMappingMap.isNullOrEmpty()) {
                        stage == VocabularyStage.NEW
                    } else {
                        (stageMappingMap[item.id] ?: VocabularyStage.NEW) == stage
                    }

                    val dueTodayMatch = !dueTodayOnly || item.id in dueItemsSet

                    // Expanded word class filtering with detailed logs
                    val wordClassMatch = if (wordClass.isNullOrBlank()) {
                        true // No filter applied, always true
                    } else {
                        if (item.features.isNullOrBlank()) {
                            false
                        } else {
                            try {
                                // Corrected class name to VocabularyFeatures
                                val features = jsonParser.decodeFromString<VocabularyGrammarDetails>(item.features)
                                val firstClass = features.first?.wordClass
                                val secondClass = features.second?.wordClass

                                // Log the parsed values from the JSON
                                Log.d(TAG, "Item #${item.id} ('${item.wordFirst}') -> Parsed classes: first='${firstClass}', second='${secondClass}'")

                                val isMatch = firstClass.equals(wordClass, ignoreCase = true) ||
                                        secondClass.equals(wordClass, ignoreCase = true)

                                // Log the final comparison result for this item
                                Log.d(TAG, "Item #${item.id} ('${item.wordFirst}') -> Comparing with '$wordClass'. Match result: $isMatch")
                                isMatch
                            } catch (e: Exception) {
                                // Log any errors during JSON parsing, which is a common failure point
                                Log.e(TAG, "Item #${item.id} ('${item.wordFirst}') -> FAILED JSON PARSING: ${e.message}. JSON: ${item.features}")
                                false
                            }
                        }
                    }

                    val finalMatch = languageMatch && queryMatch && categoryMatch && stageMatch && dueTodayMatch && wordClassMatch

                    finalMatch
                }

                filteredList = when (sortOrder) {
                    SortOrder.NEWEST_FIRST -> filteredList.sortedByDescending { it.id }
                    SortOrder.OLDEST_FIRST -> filteredList.sortedBy { it.id }
                    SortOrder.ALPHABETICAL -> filteredList.sortedBy { it.wordFirst }
                    SortOrder.LANGUAGE -> filteredList.sortedWith(compareBy({ it.languageFirstId }, { it.languageSecondId }))
                }
            }
            Log.d(TAG, "--- Filter Complete ---")
            Log.d(TAG, "Filtering & Sorting took ${duration}ms, result size: ${filteredList.size}")
            filteredList
        }
    }

    fun filterVocabularyItemsByPairs(
        languagePairs: List<Pair<Int, Int>>?,
        query: String?,
        categoryIds: List<Int>?,
        stages: List<VocabularyStage>?,
        wordClass: String? = null,
        dueTodayOnly: Boolean = false,
        sortOrder: SortOrder
    ): Flow<List<VocabularyItem>> {
        val baseFlow = filterVocabularyItems(
            languages = null,
            query = query,
            categoryIds = categoryIds,
            stage = null,
            wordClass = wordClass,
            dueTodayOnly = dueTodayOnly,
            sortOrder = sortOrder
        )

        val normalizedPairs = languagePairs
            ?.map { pair -> if (pair.first < pair.second) pair else pair.second to pair.first }
            ?.toSet()

        return combine(baseFlow, stageMapping) { items, stageMap ->
            var filteredItems = items

            if (!normalizedPairs.isNullOrEmpty()) {
                filteredItems = filteredItems.filter { item ->
                    val firstId = item.languageFirstId
                    val secondId = item.languageSecondId
                    if (firstId == null || secondId == null) {
                        false
                    } else {
                        val normalizedPair = if (firstId < secondId) firstId to secondId else secondId to firstId
                        normalizedPairs.contains(normalizedPair)
                    }
                }
            }

            if (!stages.isNullOrEmpty()) {
                filteredItems = filteredItems.filter { item ->
                    val stage = stageMap[item.id] ?: VocabularyStage.NEW
                    stage in stages
                }
            }

            filteredItems
        }
    }

    suspend fun generateVocabularyItems(category: String, amount: Int) {
        val selectedSourceLanguage = languageRepository.loadSelectedSourceLanguage().first()
        val selectedTargetLanguage = languageRepository.loadSelectedTargetLanguage().first()

        if (selectedSourceLanguage == null || selectedTargetLanguage == null) {
            _generationResult.emit("Source and target languages must be selected.")
            return
        }

        _isGenerating.value = true
        Log.d(TAG, "Generating $amount vocabulary items for category '$category'")
        try {
            var result: Result<List<VocabularyItem>>
            val duration = measureTimeMillis {
                result = vocabularyRepository.generateVocabularyItems(category, selectedSourceLanguage, selectedTargetLanguage, amount)
            }
            Log.d(TAG, "Vocabulary generation process took ${duration}ms")
            result.onSuccess {
                _generatedVocabularyItems.value = it
                _generationResult.emit("Generation completed")
            }.onFailure { exception ->
                _generationResult.emit("Error generating vocabulary items: ${exception.message}")
            }
        } catch (e: Exception) {
            _generationResult.emit("Error generating vocabulary items: ${e.message}")
        } finally {
            _isGenerating.value = false
        }
    }

    suspend fun getVocabularyItemById(id: Int): VocabularyItem? {
        Log.d(TAG, "getVocabularyItemById: Fetching item $id")
        var item: VocabularyItem?
        val duration = measureTimeMillis {
            item = vocabularyRepository.getVocabularyItemById(id)
        }
        Log.d(TAG, "getVocabularyItemById: Fetched item $id in ${duration}ms")
        return item
    }


    fun prepareExercise(
        categoryIdsAsJson: String?,
        stageNamesAsJson: String?,
        languageIdsAsJson: String?,
        dailyOnly: Boolean = false
    ) {
        Log.d("VocabularyVM", "prepareExercise: categories=$categoryIdsAsJson, stages=$stageNamesAsJson, languages=$languageIdsAsJson, dailyOnly=$dailyOnly")
        viewModelScope.launch {
            val categoryList = categoryIdsAsJson?.takeIf { it.isNotBlank() }
                ?.split(",")
                ?.mapNotNull { it.toIntOrNull() }
                ?.let { ids ->
                    ids.mapNotNull { id -> vocabularyRepository.getCategoryById(id) }
                } ?: emptyList()

            val stageList = stageNamesAsJson?.takeIf { it.isNotBlank() }?.split(",")
                ?.mapNotNull { try { VocabularyStage.valueOf(it) } catch (_: Exception) { null } } ?: emptyList()

            val languageList = languageIdsAsJson?.takeIf { it.isNotBlank() }?.split(",")
                ?.mapNotNull { it.toIntOrNull() }
                ?.let { ids ->
                    val allLangs = languageRepository.loadLanguages(LanguageListType.ALL).first()
                    allLangs.filter { it.nameResId in ids }
                } ?: emptyList()

            Log.d("VocabularyVM", "prepareExercise parsed: categories=${categoryList.size}, stages=${stageList.size}, languages=${languageList.size}")
            loadCardSet(categoryList, stageList, languageList, dailyOnly)
        }
    }


    fun loadCardSet(
        categories: List<VocabularyCategory>? = null,
        stages: List<VocabularyStage>? = null,
        languages: List<Language>? = null,
        dailyOnly: Boolean = false
    ) {
        Log.d(TAG, "loadCardSet invoked: categories=${categories?.size ?: 0}, stages=${stages?.size ?: 0}, languages=${languages?.map { it.nameResId }}, dailyOnly=$dailyOnly")
        Log.d(TAG, "Loading card set with languages: $languages, categories: ${categories?.size}, stages: ${stages?.size}")
        viewModelScope.launch {
            statusService.showLoadingMessage("Loading card set")

            try {
                // Step 1: Wait for vocabulary items to be loaded
                Log.d(TAG, "loadCardSet: Waiting for vocabulary items to load...")
                val allItems = vocabularyItems.first { it.isNotEmpty() }
                Log.d(TAG, "loadCardSet: Vocabulary items loaded (${allItems.size} items)")

                // Step 2: If we need stage filtering, ensure stage mappings are initialized
                if (!stages.isNullOrEmpty()) {
                    Log.d(TAG, "loadCardSet: Stage filtering required, checking stage mappings...")
                    var stageMappingMap = stageMapping.first()

                    // If stage mapping is empty, but we have items, initialize it
                    if (stageMappingMap.isEmpty() && allItems.isNotEmpty()) {
                        Log.d(TAG, "loadCardSet: Stage mapping empty, initializing...")
                        vocabularyRepository.actualizeVocabularyStageMappings()

                        // Wait for stage mapping to be populated (with timeout)
                        var attempts = 0
                        val maxAttempts = 10
                        while (stageMappingMap.isEmpty() && attempts < maxAttempts) {
                            delay(100) // Wait 100ms between attempts
                            stageMappingMap = stageMapping.first()
                            attempts++
                            Log.d(TAG, "loadCardSet: Waiting for stage mapping... attempt $attempts, size: ${stageMappingMap.size}")
                        }

                        if (stageMappingMap.isEmpty()) {
                            Log.w(TAG, "loadCardSet: Stage mapping still empty after $maxAttempts attempts")
                            statusService.showErrorMessage("Failed to initialize stage mappings")
                            _cardSet.value = null
                            return@launch
                        } else {
                            Log.d(TAG, "loadCardSet: Stage mapping ready with ${stageMappingMap.size} mappings")
                        }
                    }
                }

                // Step 3: If we need category filtering, ensure category mappings are ready
                if (!categories.isNullOrEmpty()) {
                    Log.d(TAG, "loadCardSet: Category filtering required, checking category mappings...")
                    val categoryMappings = vocabularyRepository.getCategoryMappings()
                    Log.d(TAG, "loadCardSet: Category mappings loaded (${categoryMappings.size} mappings)")
                }

                // Step 4: Now perform the actual filtering
                Log.d(TAG, "loadCardSet: All data ready, performing filtering...")
                val filteredItems = filterVocabularyItems(
                    languages = languages?.map { it.nameResId },
                    query = null,
                    categoryIds = categories?.map { it.id },
                    stage = stages?.firstOrNull(),
                    sortOrder = SortOrder.NEWEST_FIRST,
                    dueTodayOnly = dailyOnly
                ).first()

                Log.d(TAG, "loadCardSet: filterVocabularyItems returned ${filteredItems.size} items")

                Log.d(TAG, "loadCardSet: Filtering completed, found ${filteredItems.size} items")

                if (filteredItems.isNotEmpty()) {
                    val cardSetFromSource = CardSet(
                        languageFirst = languages?.getOrNull(0)?.nameResId,
                        languageSecond = languages?.getOrNull(1)?.nameResId,
                        cards = filteredItems
                    )
                    _cardSet.value = cardSetFromSource
                    Log.d(TAG, "Successfully loaded card set with ${filteredItems.size} items")
                } else {
                    _cardSet.value = null
                    Log.d(TAG, "No items found for the specified filters")
                }
            } catch (e: Exception) {
                statusService.showErrorMessage("Error loading card set: ${e.message}")
                _cardSet.value = null
                Log.e(TAG, "Error in loadCardSet: ${e.message}")
            }

            statusService.hideMessageBar()
            if (_cardSet.value == null) {
                statusService.cancelAllMessages()
                statusService.showErrorById(StatusMessageId.ERROR_NO_CARDS_FOUND)
            }
        }
    }

    fun deleteVocabularyItemsByCategory(categoryID: Int) {
        Log.d(TAG, "Deleting vocabulary items by category ID $categoryID")
        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    val itemsToDelete = vocabularyRepository.getVocabularyItemsByCategory(categoryID)
                    vocabularyRepository.deleteVocabularyItemsByIds(itemsToDelete.map { it.id })
                }
                Log.d(TAG, "deleteVocabularyItemsByCategory for ID $categoryID took ${duration}ms")
            } catch (e: Exception) {
                statusService.showErrorMessage("Error in deleteVocabularyItemsByCategory: ${e.message}")
            }
        }
    }

    @OptIn(ExperimentalTime::class)
    fun getVocabularyItemDetailsFlow(vocabularyItemId: Int): Flow<VocabularyItemDetails> = flow {
        Log.d(TAG, "Getting details for item ID $vocabularyItemId")
        try {
            val duration = measureTimeMillis {
                coroutineScope {
                    val stage = async { vocabularyRepository.getVocabularyItemStage(vocabularyItemId).first() }
                    val lastCorrect = async { vocabularyRepository.getLastCorrectAnswer(vocabularyItemId) }
                    val lastIncorrect = async { vocabularyRepository.getLastIncorrectAnswer(vocabularyItemId) }
                    val correctCount = async { vocabularyRepository.getCorrectAnswerCount(vocabularyItemId) }
                    val incorrectCount = async { vocabularyRepository.getIncorrectAnswerCount(vocabularyItemId) }

                    emit(
                        VocabularyItemDetails(
                            stage = stage.await(),
                            lastCorrectAnswer = lastCorrect.await(),
                            lastIncorrectAnswer = lastIncorrect.await(),
                            correctAnswerCount = correctCount.await(),
                            incorrectAnswerCount = incorrectCount.await()
                        )
                    )
                }
            }
            Log.d(TAG, "getVocabularyItemDetails for ID $vocabularyItemId took ${duration}ms")
        } catch (e: Exception) {
            Log.e(TAG, "Error in getVocabularyItemDetails: ${e.message}")
        }
    }

    fun initializeSaveFileLauncher(launcher: ActivityResultLauncher<Intent>) {
        saveFileLauncher = launcher
    }

    fun saveRepositoryState() {
        if (!::saveFileLauncher.isInitialized) {
            statusService.showErrorMessage("Save File Launcher not initialized.")
            return
        }
        val intent = fileSaver.createSaveDocumentIntent(fileSaver.generateFilename())
        saveFileLauncher.launch(intent)
    }

    fun saveCategory(categoryId: Int) {
        if (!::saveFileLauncher.isInitialized) {
            statusService.showErrorMessage("Save File Launcher not initialized.")
            return
        }
        val filename = fileSaver.generateFilenameForCategory(categoryId)
        val intent = fileSaver.createSaveDocumentIntent(filename)
        saveFileLauncher.launch(intent)
    }

    fun handleSaveResult(result: ActivityResult, categoryId: Int? = null) {
        Log.d(TAG, "Handling save result for categoryId: $categoryId")
        if (result.resultCode == Activity.RESULT_OK) {
            val uri: Uri? = result.data?.data
            uri?.let {
                viewModelScope.launch {
                    if (categoryId == null) {
                        val startSave = System.currentTimeMillis()
                        fileSaver.saveRepositoryToUri(it)
                        Log.d(TAG, "handleSaveResult: Saved repository in ${System.currentTimeMillis() - startSave}ms")
                        val filename = fileSaver.getFileNameFromUri(it)
                        _saveStatus.postValue("File saved to $filename")
                    }
                    if (categoryId != null) {
                        val startSave = System.currentTimeMillis()
                        fileSaver.saveCategoryToUri(it, categoryId)
                        Log.d(TAG, "handleSaveResult: Saved category in ${System.currentTimeMillis() - startSave}ms")
                        val filename = fileSaver.getFileNameFromUri(it)
                        _saveStatus.postValue("File saved to $filename")
                    }
                }
            } ?: run {
                statusService.showErrorMessage("Error: No URI received from file picker.")
                Log.e(TAG, "handleSaveResult: No URI received")
            }
        } else {
            statusService.showErrorMessage("File save cancelled or failed.")
            Log.d(TAG, "handleSaveResult: Save cancelled or failed")
        }
    }

    fun importVocabulary(jsonString: String) {
        Log.d(TAG, "Attempting to import vocabulary from JSON string (length: ${jsonString.length})")
        viewModelScope.launch {
            try {
                val duration = measureTimeMillis {
                    val vocabularyItems = Json.decodeFromString<List<VocabularyItem>>(jsonString)
                    Log.d(TAG, "Successfully decoded ${vocabularyItems.size} items from JSON.")
                    vocabularyRepository.introduceVocabularyItems(vocabularyItems)
                    vocabularyRepository.cleanDuplicates()
                }
                statusService.showSuccessMessage("Vocabulary items imported successfully.")
                Log.d(TAG, "Vocabulary import process took ${duration}ms")
            } catch (e: Exception) {
                statusService.showErrorMessage("Error importing vocabulary items: ${e.message}")
            }
        }
    }

    fun wipeRepository() {
        viewModelScope.launch {
            try {
                vocabularyRepository.wipeRepository()
                statusService.showErrorMessage("All repository data deleted.")
            } catch (e: Exception) {
                statusService.showErrorMessage("Failed to wipe repository: $e.message}")
            }
        }
    }

    suspend fun getSynonymsForItem(
        vocabularyItemId: Int,
        isForFirstWord: Boolean
    ): List<SynonymData> {
        val vocabularyItem = getVocabularyItemById(vocabularyItemId) ?: return emptyList()

        val allLangs = languageRepository.loadLanguages(LanguageListType.ALL).first()
        val langFirst = allLangs.find { it.nameResId == vocabularyItem.languageFirstId }
        val langSecond = allLangs.find { it.nameResId == vocabularyItem.languageSecondId }

        if (langFirst == null || langSecond == null) {
            Log.e(TAG, "Could not find languages for vocabulary item $vocabularyItemId")
            return emptyList()
        }

        val termLanguage = if (isForFirstWord) langFirst else langSecond
        val translationLanguage = if (isForFirstWord) langSecond else langFirst
        val term = if (isForFirstWord) vocabularyItem.wordFirst else vocabularyItem.wordSecond
        val translation = if (isForFirstWord) vocabularyItem.wordSecond else vocabularyItem.wordFirst

        val dbSynonyms = withContext(Dispatchers.IO) {
            try {
                vocabularyRepository.getSynonymsForItem(vocabularyItemId)
            } catch (e: Exception) {
                Log.e(TAG, "Error fetching synonyms from database: ${e.message}")
                emptyList()
            }
        }
        val combinedItems = dbSynonyms.map { SynonymData(it, null) }.toMutableList()

        if (combinedItems.size < 4) {
            vocabularyItemService.generateSynonyms(
                term = term,
                language = termLanguage,
                amount = 4 - combinedItems.size,
                translation = translation,
                translationLanguage = translationLanguage
            ).onSuccess { generatedSynonyms ->
                val newItems = generatedSynonyms.map { synonym ->
                    val newItem = VocabularyItem(
                        id = 0,
                        languageFirstId = if (isForFirstWord) termLanguage.nameResId else translationLanguage.nameResId,
                        languageSecondId = if (isForFirstWord) translationLanguage.nameResId else termLanguage.nameResId,
                        wordFirst = if (isForFirstWord) synonym.word else translation,
                        wordSecond = if (isForFirstWord) translation else synonym.word
                    )
                    SynonymData(item = newItem, proximity = synonym.proximity)
                }
                combinedItems.addAll(newItems)
            }.onFailure { exception ->
                Log.e(TAG, "AI synonym generation failed: ${exception.message}")
            }
        }

        return combinedItems
            .filterNot { (item, _) ->
                val currentTerm = if (item.languageFirstId == termLanguage.nameResId) item.wordFirst else item.wordSecond
                currentTerm.equals(term, ignoreCase = true)
            }
            .distinctBy { (item, _) ->
                if (item.languageFirstId == termLanguage.nameResId) item.wordFirst else item.wordSecond
            }
    }


    suspend fun getAllLanguagesIdsPresent(): Set<Int?> {
        try {
            return withContext(Dispatchers.IO) {
                Log.d(TAG, "Fetching all present language IDs...")
                val ids = vocabularyRepository.getAllLanguageIdsFromVocabulary()
                Log.d(TAG, "Fetched ${ids.size} language IDs")
                ids
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error fetching all language IDs: ${e.message}")
            return emptySet()
        }
    }

    suspend fun getExampleForItem(itemId: Int, isFirstWord: Boolean, languageFirst: Language?, languageSecond: Language?): Pair<String, String>? {

        val item = getVocabularyItemById(itemId) ?: return null
        if (languageFirst == null || languageSecond == null) return null

        return if (isFirstWord) {
            dictionaryService.getExampleSentence(item.wordFirst , item.wordSecond, languageFirst, languageSecond).getOrNull()
        } else {
            dictionaryService.getExampleSentence(item.wordSecond, item.wordFirst , languageSecond, languageFirst).getOrNull()
        }
    }

    suspend fun fetchAndUpdateZipfFrequency(item: VocabularyItem): VocabularyItem {
        Log.d(TAG, "Fetching zipf frequency for item ID ${item.id}")
        var updatedItem = item

        try {
            val languageFirst = languageRepository.getLanguageById(item.languageFirstId ?: 0)
            if (languageFirst != null) {
                Log.d(TAG, "Fetching zipf frequency for '${item.wordFirst}' in language '${languageFirst.name}'")
                val frequencyResult = vocabularyItemService.fetchZipfFrequency(item.wordFirst, languageFirst.code)
                frequencyResult.onSuccess { frequency ->
                    Log.d(TAG, "Fetched zipf frequency for '${item.wordFirst}': $frequency")
                    updatedItem = updatedItem.copy(zipfFrequencyFirst = frequency)
                }.onFailure { exception ->
                    Log.e(TAG, "Failed to fetch zipf frequency for '${item.wordFirst}': ${exception.message}")
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error fetching zipf frequency for first word: ${e.message}")
        }

        try {

            val languageSecond = languageRepository.getLanguageById(item.languageSecondId ?: 0)
            if (languageSecond != null) {
                Log.d(TAG, "Fetching zipf frequency for '${item.wordSecond}' in language '${languageSecond.name}'")
                val frequencyResult = vocabularyItemService.fetchZipfFrequency(item.wordSecond, languageSecond.code)
                frequencyResult.onSuccess { frequency ->
                    Log.d(TAG, "Fetched zipf frequency for '${item.wordSecond}': $frequency")
                    updatedItem = updatedItem.copy(zipfFrequencySecond = frequency)
                }.onFailure { exception ->
                    Log.e(TAG, "Failed to fetch zipf frequency for '${item.wordSecond}': ${exception.message}")
                }
            }
        }catch (e: Exception) {
            Log.e(TAG, "Error fetching zipf frequency for second word: ${e.message}")
        }

        Log.d(TAG, "Updated item: $updatedItem")
        return updatedItem
    }
    

    fun fetchAndApplyGrammaticalDetailsForList(items: List<VocabularyItem>) {
        if (items.isEmpty()) {
            Log.d(TAG, "fetchAndApplyGrammaticalDetailsForList called with an empty list. Nothing to do.")
            return
        }

        viewModelScope.launch {
            statusService.showLoadingMessage("Fetching grammar for ${items.size} items...")
            Log.d(TAG, "Attempting to fetch grammar details for a list of ${items.size} items.")

            try {

                // 1. Get all unique language IDs and fetch their objects in one go.
                val languageIds = items.flatMap { listOfNotNull(it.languageFirstId, it.languageSecondId) }.toSet()
                val languagesMap = languageRepository.getLanguagesByResourceIds(languageIds).associateBy { it.nameResId }

                // 2. Create a new list with articles removed from non-sentence items
                val itemsWithoutArticles = items.map { item ->
                    if (StringHelper.isSentenceStrict(item.wordFirst) || StringHelper.isSentenceStrict(item.wordSecond)) {
                        item // Skip article removal for sentences
                    } else {
                        val articlesLangFirst = languagesMap[item.languageFirstId]?.code?.let { languageConfigRepository.getArticlesForLanguage(it) } ?: emptySet()
                        val articlesLangSecond = languagesMap[item.languageSecondId]?.code?.let { languageConfigRepository.getArticlesForLanguage(it) } ?: emptySet()

                        val allArticles = (articlesLangFirst + articlesLangSecond)

                        item.copy(
                            wordFirst = StringHelper.removeLeadingArticles(item.wordFirst, allArticles),
                            wordSecond = StringHelper.removeLeadingArticles(item.wordSecond, allArticles)
                        )
                    }
                }

                // 3. Call the new batch service method with the updated item list.
                val result = vocabularyItemService.fetchAndApplyGrammaticalDetails(itemsWithoutArticles, languagesMap)

                // 4. Handle the result from the service.
                result.onSuccess { updatedItems ->
                    Log.i(TAG, "Successfully fetched and mapped details for ${updatedItems.count { it.features != null }} items.")

                    // 5. Persist the updated items back to the database.
                    vocabularyRepository.updateVocabularyItems(updatedItems)
                    statusService.trigger(StatusAction.CancelLoadingOperation)
                    statusService.showSuccessMessage("Grammar details updated!")

                }.onFailure { exception ->
                    Log.e(TAG, "Failed to fetch grammar details for list: ${exception.message}")
                    statusService.showErrorMessage("Could not retrieve grammar details.")
                }
            } catch (e: Exception) {
                Log.e(TAG, "An unexpected error occurred in fetchAndApplyGrammaticalDetailsForList: ${e.message}")
                statusService.showErrorMessage("An unexpected error occurred.")
            }
        }
    }

    /**
     * Removes leading articles from a VocabularyItem's words based on the provided article sets for each language.
     * The item is then updated in the database.
     *
     * @param item The VocabularyItem to process.
     * @param articlesLangFirst A set of articles for the first language.
     * @param articlesLangSecond A set of articles for the second language.
     */
    fun removeArticles(item: VocabularyItem, articlesLangFirst: Set<String>, articlesLangSecond: Set<String>) {
        viewModelScope.launch {
            try {

                // Don't remove articles if either word is a sentence
                if (StringHelper.isSentenceStrict(item.wordFirst) || StringHelper.isSentenceStrict(item.wordSecond)) {
                    Log.d(TAG, "removeArticles: Skipping item ${item.id} as it contains a sentence.")
                    return@launch
                }

                // Combine all articles and filter out any blank ones.
                val allArticles = (articlesLangFirst + articlesLangSecond).filter { it.isNotBlank() }
                if (allArticles.isEmpty()) {
                    Log.d(TAG, "removeArticles: No articles provided, skipping.")
                    return@launch
                }


                // Create a new item with the articles removed.
                val updatedItem = item.copy(
                    wordFirst = StringHelper.removeLeadingArticles(item.wordFirst, allArticles),
                    wordSecond = StringHelper.removeLeadingArticles(item.wordSecond, allArticles)
                )

                // Only call the repository if a change was actually made.
                if (updatedItem != item) {
                    Log.d(TAG, "removeArticles: Articles removed, updating item ${item.id}")
                    editVocabularyItem(updatedItem)
                } else {
                    Log.d(TAG, "removeArticles: No articles found in item ${item.id}, no update needed.")
                }
            } catch (e: Exception) {
                statusService.showErrorMessage("Error removing articles: ${e.message}")
                Log.e(TAG, "Error in removeArticles: ${e.message}")
            }
        }
    }
    private val validLanguageIds: StateFlow<Set<Int>> = languageRepository.loadLanguages(LanguageListType.ALL)
        .map { languages -> languages.map { it.nameResId }.toSet() }
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptySet())

    val faultyItemsCount: StateFlow<Int> = combine(vocabularyItems, validLanguageIds) { items, validIds ->
        // Return 0 if the list of valid IDs hasn't been loaded yet to prevent incorrect counts.
        if (validIds.isEmpty()) return@combine 0

        items.count { item ->
            val lang1 = item.languageFirstId
            val lang2 = item.languageSecondId

            item.wordFirst.isBlank() ||
                    item.wordSecond.isBlank() ||
                    lang1 == null ||
                    lang2 == null ||
                    lang1 == lang2 ||
                    lang1 == 0 ||
                    lang2 == 0 ||
                    !validIds.contains(lang1) ||
                    !validIds.contains(lang2)
        }
    }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = 0
        )

    val itemsWithoutGrammarCount: StateFlow<Int> = vocabularyItems
        .map { items ->
            items.count { it.features.isNullOrEmpty() }
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = 0
        )

    val allItemsWithoutGrammar: StateFlow<List<VocabularyItem>> = vocabularyItems
        .map { items ->
            items.filter { it.features.isNullOrEmpty() }
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )


    val allFaultyItems: StateFlow<List<VocabularyItem>> = combine(vocabularyItems, validLanguageIds) { items, validIds ->
        if (validIds.isEmpty()) emptyList()
        else items.filter { item ->
            val lang1 = item.languageFirstId
            val lang2 = item.languageSecondId
            item.wordFirst.isBlank() || item.wordSecond.isBlank() || lang1 == null || lang2 == null ||
                    lang1 == lang2 || lang1 == 0 || lang2 == 0 || !validIds.contains(lang1) ||
                    !validIds.contains(lang2)
        }
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

    val missingLanguageInfo: StateFlow<Map<Int, Int>> = combine(vocabularyItems, validLanguageIds) { items, validIds ->
        if (validIds.isEmpty() || items.isEmpty()) {
            emptyMap()
        } else {
            val presentIds = items.flatMap { listOfNotNull(it.languageFirstId, it.languageSecondId) }.toSet()
            val missingIds = presentIds - validIds

            if (missingIds.isEmpty()) {
                emptyMap()
            } else {
                missingIds.associateWith { missingId ->
                    items.count { it.languageFirstId == missingId || it.languageSecondId == missingId }
                }
            }
        }
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyMap())

    fun getItemsForLanguage(languageId: Int): Flow<List<VocabularyItem>> {
        return vocabularyItems.map { items ->
            items.filter { it.languageFirstId == languageId || it.languageSecondId == languageId }
        }
    }

    fun replaceLanguageId(oldId: Int, newId: Int) {
        viewModelScope.launch {
            Log.d(TAG, "Replacing language ID $oldId with $newId")
            try {
                val itemsToUpdate = vocabularyItems.value.filter {
                    it.languageFirstId == oldId || it.languageSecondId == oldId
                }.map { item ->
                    val newFirstId = if (item.languageFirstId == oldId) newId else item.languageFirstId
                    val newSecondId = if (item.languageSecondId == oldId) newId else item.languageSecondId
                    item.copy(languageFirstId = newFirstId, languageSecondId = newSecondId)
                }

                if (itemsToUpdate.isNotEmpty()) {
                    vocabularyRepository.updateVocabularyItems(itemsToUpdate)
                    statusService.showSuccessMessage("Language ID updated for ${itemsToUpdate.size} items.")
                    Log.d(TAG, "Successfully updated ${itemsToUpdate.size} items.")
                } else {
                    Log.d(TAG, "No items found with language ID $oldId to update.")
                }
            } catch (e: Exception) {
                val errorMessage = "Error replacing language ID: ${e.message}"
                statusService.showErrorMessage(errorMessage)
                Log.e(TAG, errorMessage)
            }
        }
    }

    enum class DeleteType { VOCABULARY_ITEM_BY_ID, VOCABULARY_ITEM, VOCABULARY_ITEMS, REMOVE_FROM_CATEGORY }
    enum class SortOrder { NEWEST_FIRST, OLDEST_FIRST, ALPHABETICAL, LANGUAGE }

    data class VocabularyItemDetails @OptIn(ExperimentalTime::class) constructor(
        val stage: VocabularyStage,
        val lastCorrectAnswer: kotlin.time.Instant?,
        val lastIncorrectAnswer: kotlin.time.Instant?,
        val correctAnswerCount: Int,
        val incorrectAnswerCount: Int
    )

    data class SynonymData(
        val item: VocabularyItem,
        val proximity: Int?
    )

    // Navigation state management functions
    fun setNavigationContext(items: List<VocabularyItem>, currentItemId: Int) {
        val currentIndex = items.indexOfFirst { it.id == currentItemId }
        if (currentIndex != -1) {
            _currentNavigationItems.value = items
            _currentNavigationPosition.value = currentIndex
        }
    }

    fun navigateToNextItem(): Boolean {
        val currentPos = _currentNavigationPosition.value
        val items = _currentNavigationItems.value
        if (currentPos < items.size - 1) {
            _currentNavigationPosition.value = currentPos + 1
            return true
        }
        return false
    }

    fun navigateToPreviousItem(): Boolean {
        val currentPos = _currentNavigationPosition.value
        if (currentPos > 0) {
            _currentNavigationPosition.value = currentPos - 1
            return true
        }
        return false
    }

}
