@file:OptIn(ExperimentalTime::class)
@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.db

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert
import eu.gaudian.translator.model.VocabularyItem
import eu.gaudian.translator.model.VocabularyItemState
import kotlinx.coroutines.flow.Flow
import kotlinx.datetime.LocalDate
import kotlin.time.ExperimentalTime

@OptIn(ExperimentalTime::class)

@Dao
interface VocabularyItemDao {
    @Query("DELETE FROM vocabulary_items")
    suspend fun clearAllItems()
    @Query("SELECT * FROM vocabulary_items")
    fun getAllItemsFlow(): Flow<List<VocabularyItem>>

    @Query("SELECT * FROM vocabulary_items")
    suspend fun getAllItems(): List<VocabularyItem>

    @Query("SELECT * FROM vocabulary_items WHERE id = :id")
    suspend fun getItemById(id: Int): VocabularyItem?

    @Query("SELECT EXISTS(SELECT 1 FROM vocabulary_items WHERE (LOWER(wordFirst) = LOWER(:word) AND languageFirstId IS :languageId) OR (LOWER(wordSecond) = LOWER(:word) AND languageSecondId IS :languageId))")
    suspend fun itemExists(word: String, languageId: Int?): Boolean

    @Upsert
    suspend fun upsertItem(item: VocabularyItem)

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertAll(items: List<VocabularyItem>)

    @Query("DELETE FROM vocabulary_items WHERE id = :itemId")
    suspend fun deleteItemById(itemId: Int)

    @Query("DELETE FROM vocabulary_items WHERE id IN (:itemIds)")
    suspend fun deleteItemsByIds(itemIds: List<Int>)

    @Query("SELECT * FROM vocabulary_items WHERE id IN (:ids)")
    suspend fun getItemsByIds(ids: List<Int>): List<VocabularyItem>

    @Query("SELECT MAX(id) FROM vocabulary_items")
    suspend fun getMaxItemId(): Int?

    @Query("""
    SELECT i.* FROM vocabulary_items i
    INNER JOIN category_mappings cm ON i.id = cm.vocabularyItemId
    WHERE cm.categoryId = :categoryId
"""
    )
    suspend fun getItemsByCategoryId(categoryId: Int): List<VocabularyItem>

    @Query("""
    SELECT i.* FROM vocabulary_items AS i
    LEFT JOIN stage_mappings AS sm ON i.id = sm.vocabularyItemId
    LEFT JOIN vocabulary_states AS vs ON i.id = vs.vocabularyItemId
    WHERE
        -- Condition 1: Item is NEW
        sm.stage IS NULL OR sm.stage = 'NEW' OR
        -- Condition 2: Item has a due date that is in the past
        (
            -- Use last correct or incorrect answer as the base time
            (COALESCE(vs.lastCorrectAnswer, vs.lastIncorrectAnswer) / 1000) +
            (
                CASE IFNULL(sm.stage, 'NEW')
                    WHEN 'STAGE_1' THEN :intervalStage1 * 86400
                    WHEN 'STAGE_2' THEN :intervalStage2 * 86400
                    WHEN 'STAGE_3' THEN :intervalStage3 * 86400
                    WHEN 'STAGE_4' THEN :intervalStage4 * 86400
                    WHEN 'STAGE_5' THEN :intervalStage5 * 86400
                    WHEN 'LEARNED' THEN :intervalLearned * 86400
                    ELSE 0
                END
            ) <= :now
        )
"""
    )
    fun getDueTodayItemsFlow(
        now: Long,
        intervalStage1: Int,
        intervalStage2: Int,
        intervalStage3: Int,
        intervalStage4: Int,
        intervalStage5: Int,
        intervalLearned: Int
    ): Flow<List<VocabularyItem>>

    @Query("""
        SELECT * FROM vocabulary_items
        WHERE id != :excludeId AND (
            ((languageFirstId = :lang1 AND languageSecondId = :lang2) OR (languageFirstId = :lang2 AND languageSecondId = :lang1))
            AND (wordFirst = :wordFirst OR wordSecond = :wordSecond)
        )
    """)
    suspend fun getSynonyms(excludeId: Int, lang1: Int, lang2: Int, wordFirst: String, wordSecond: String): List<VocabularyItem>
}

data class DailyCount(val date: LocalDate, val count: Int)

@Dao
interface VocabularyStateDao {

    @Query("DELETE FROM vocabulary_states")
    suspend fun clearAllStates()

    @Query("""
    SELECT DATE(lastCorrectAnswer / 1000, 'unixepoch') as date, COUNT(vocabularyItemId) as count
    FROM vocabulary_states
    WHERE lastCorrectAnswer IS NOT NULL AND date BETWEEN :startDate AND :endDate
    GROUP BY date
""")
    suspend fun getCorrectAnswerCountsByDate(startDate: LocalDate, endDate: LocalDate): List<DailyCount>
    @Query("SELECT * FROM vocabulary_states")
    fun getAllStatesFlow(): Flow<List<VocabularyItemState>>

    @Query("SELECT * FROM vocabulary_states")
    suspend fun getAllStates(): List<VocabularyItemState>

    @Query("SELECT * FROM vocabulary_states WHERE vocabularyItemId = :itemId")
    suspend fun getStateById(itemId: Int): VocabularyItemState?

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertAll(states: List<VocabularyItemState>)

    @Upsert
    suspend fun upsertState(state: VocabularyItemState)
}

@Dao
interface CategoryDao {
    @Query("DELETE FROM categories")
    suspend fun clearAllCategories()
    @Query("SELECT * FROM categories")
    fun getAllCategoriesFlow(): Flow<List<VocabularyCategoryEntity>>

    @Query("SELECT * FROM categories")
    suspend fun getAllCategories(): List<VocabularyCategoryEntity>

    @Query("SELECT * FROM categories WHERE id = :id")
    suspend fun getCategoryById(id: Int): VocabularyCategoryEntity?

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertAll(categories: List<VocabularyCategoryEntity>)

    @Upsert
    suspend fun upsertCategory(category: VocabularyCategoryEntity)

    @Query("DELETE FROM categories WHERE id = :categoryId")
    suspend fun deleteCategoryById(categoryId: Int)
}

@Dao
interface MappingDao {
    @Query("DELETE FROM stage_mappings")
    suspend fun clearStageMappings()
    @Query("DELETE FROM stage_mappings WHERE vocabularyItemId NOT IN (:itemIds)")
    suspend fun deleteStageMappingsNotIn(itemIds: List<Int>)
    @Query("SELECT * FROM category_mappings")
    fun getCategoryMappingsFlow(): Flow<List<CategoryMappingEntity>>

    @Query("SELECT * FROM category_mappings")
    suspend fun getCategoryMappings(): List<CategoryMappingEntity>


    @Query("DELETE FROM category_mappings")
    suspend fun clearCategoryMappings()

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertCategoryMappings(mappings: List<CategoryMappingEntity>)

    @Transaction
    suspend fun setAllCategoryMappings(mappings: List<CategoryMappingEntity>) {
        clearCategoryMappings()
        if (mappings.isNotEmpty()) {
            insertCategoryMappings(mappings)
        }
    }

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun addCategoryMapping(mapping: CategoryMappingEntity)

    @Query("DELETE FROM category_mappings WHERE vocabularyItemId = :itemId AND categoryId = :listId")
    suspend fun removeCategoryMapping(itemId: Int, listId: Int)

    @Query("SELECT * FROM stage_mappings")
    fun getStageMappingsFlow(): Flow<List<StageMappingEntity>>

    @Query("SELECT * FROM stage_mappings")
    suspend fun getStageMappings(): List<StageMappingEntity>

    @Upsert
    suspend fun upsertStageMapping(mapping: StageMappingEntity)

    @Upsert
    suspend fun upsertStageMappings(mappings: List<StageMappingEntity>)
}

@Dao
interface DailyStatDao {
    @Query("DELETE FROM daily_stats")
    suspend fun clearAll()
    @Query("SELECT * FROM daily_stats WHERE date = :date")
    suspend fun getStatForDate(date: LocalDate): DailyStatEntity?

    @Upsert
    suspend fun upsertStat(stat: DailyStatEntity)
}