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

package eu.gaudian.translator.model

import android.content.Context
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import eu.gaudian.translator.R
import eu.gaudian.translator.model.grammar.VocabularyFeatures
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.time.Clock
import kotlin.time.ExperimentalTime
import kotlin.time.Instant

val jsonParser = Json { ignoreUnknownKeys = true }

@Serializable
@Parcelize
@Entity(tableName = "vocabulary_items")
data class VocabularyItem(
    @PrimaryKey val id: Int,
    val languageFirstId: Int?,
    val languageSecondId: Int?,
    val wordFirst: String,
    val wordSecond: String,
    @Contextual val createdAt: Instant? = Clock.System.now(),
    val features: String? = null,
    val zipfFrequencyFirst: Float? = null,
    val zipfFrequencySecond: Float? = null
) : Parcelable {

    fun isDuplicate(other: VocabularyItem): Boolean {
        val normalizedWords = setOf(wordFirst.lowercase(), wordSecond.lowercase())
        val otherNormalizedWords = setOf(other.wordFirst.lowercase(), other.wordSecond.lowercase())
        val normalizedIds = setOf(languageFirstId, languageSecondId)
        val otherNormalizedIds = setOf(other.languageFirstId, other.languageSecondId)
        return normalizedWords == otherNormalizedWords && normalizedIds == otherNormalizedIds
    }

    @Suppress("unused")
    fun switchOrder(): VocabularyItem {
        val currentFeatures = features?.let { jsonParser.decodeFromString<VocabularyFeatures>(it) }
        val switchedFeatures = currentFeatures?.copy(first = currentFeatures.second, second = currentFeatures.first)
        val switchedFeaturesJson = switchedFeatures?.let { jsonParser.encodeToString(it) }

        return this.copy(
            languageFirstId = this.languageSecondId,
            languageSecondId = this.languageFirstId,
            wordFirst = this.wordSecond,
            wordSecond = this.wordFirst,
            features = switchedFeaturesJson
        )
    }
}

@Serializable
@Parcelize
data class WordDetails(
    @SerialName("category")
    val wordClass: String,
    val properties: Map<String, String>
) : Parcelable

/**
 * A container holding the grammatical details for both words in a VocabularyItem.
 */
@Serializable
@Parcelize
data class VocabularyGrammarDetails(
    val first: WordDetails? = null,
    val second: WordDetails? = null
) : Parcelable


@Serializable
sealed class VocabularyCategory {
    abstract val id: Int
    abstract val name: String
}


@Serializable
@SerialName("FilterCategory")
data class VocabularyFilter(
    override val id: Int,
    override val name: String,
    val languages: List<Int>? = null,
    @Contextual val languagePairs: Pair<Int, Int> ? = null,
    val stages: List<VocabularyStage>? = null,
) : VocabularyCategory()

@Serializable
@SerialName("TagCategory")
data class TagCategory(
    override val id: Int,
    override val name: String,
) : VocabularyCategory()


@Serializable
@Entity(tableName = "vocabulary_states")
data class VocabularyItemState(
    @PrimaryKey val vocabularyItemId: Int,
    @Contextual var lastCorrectAnswer: Instant? = null,
    @Contextual var lastIncorrectAnswer: Instant? = null,
    var correctAnswerCount: Int = 0,
    var incorrectAnswerCount: Int = 0
)

@Serializable
enum class VocabularyStage {
    NEW,
    STAGE_1,
    STAGE_2,
    STAGE_3,
    STAGE_4,
    STAGE_5,
    LEARNED;

    fun toString(context: Context): String {
        val res = context.resources
        return when (this) {
            NEW -> res.getString(R.string.stage_new)
            STAGE_1 -> res.getString(R.string.stage_1)
            STAGE_2 -> res.getString(R.string.stage_2)
            STAGE_3 -> res.getString(R.string.stage_3)
            STAGE_4 -> res.getString(R.string.stage_4)
            STAGE_5 -> res.getString(R.string.stage_5)
            LEARNED -> res.getString(R.string.stage_learned)
        }
    }
}

@Serializable
@Parcelize
data class CardSet(
    val id: Int?=null,
    val languageFirst: Int?=null,
    val languageSecond: Int?=null,
    val cards: List<VocabularyItem>,
): Parcelable