@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.repository

import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
import eu.gaudian.translator.model.communication.ApiProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map

class SettingsRepository(private val context: Context) {

    private object PrefKeys {
        const val API_KEY_SUFFIX = "_api_key"

        val CUSTOM_PROMPT_TRANSLATION = stringPreferencesKey("custom_prompt_translation")
        val CUSTOM_PROMPT_VOCABULARY = stringPreferencesKey("custom_prompt_vocabulary")
        val CUSTOM_PROMPT_DICTIONARY = stringPreferencesKey("custom_prompt_dictionary")
        val CUSTOM_PROMPT_EXERCISE = stringPreferencesKey("custom_prompt_exercise")
        val SPEAKING_SPEED = intPreferencesKey("SPEAKING_SPEED")
        val DEVELOPER_MODE = booleanPreferencesKey("developer_mode")
        val DAILY_GOAL = intPreferencesKey("daily_goal")
        val SELECTED_CATEGORIES = stringSetPreferencesKey("selectedCategories")
        val DICTIONARY_SWITCHES = stringSetPreferencesKey("dictionary_switches")
        val THEME = stringPreferencesKey("selected_theme")
        val DARK_MODE_PREFERENCE = stringPreferencesKey("dark_mode_preference")
        val FONT_PREFERENCE = stringPreferencesKey("font_preference")
        val INTRO_COMPLETED = booleanPreferencesKey("intro_completed")
        val INTERVAL_NEW = intPreferencesKey("interval_new")
        val INTERVAL_STAGE_1 = intPreferencesKey("interval_stage_1")
        val INTERVAL_STAGE_2 = intPreferencesKey("interval_stage_2")
        val INTERVAL_STAGE_3 = intPreferencesKey("interval_stage_3")
        val INTERVAL_STAGE_4 = intPreferencesKey("interval_stage_4")
        val INTERVAL_STAGE_5 = intPreferencesKey("interval_stage_5")
        val INTERVAL_LEARNED = intPreferencesKey("interval_learned")
        val CRITERIA_CORRECT = intPreferencesKey("criteria_correct")
        val CRITERIA_WRONG = intPreferencesKey("criteria_wrong")
        val SHOW_HINTS = booleanPreferencesKey("show_hints")
        val EXPERIMENTAL_FEATURES = booleanPreferencesKey("experimental_features")
        val TRY_WIKTIONARY_FIRST = booleanPreferencesKey("try_wiktionary_first")
        val SHOW_BOTTOM_NAV_LABELS = booleanPreferencesKey("show_bottom_nav_labels")
        val CONNECTION_CONFIGURED = booleanPreferencesKey("connection_configured")
        val USE_LIBRE_TRANSLATE = booleanPreferencesKey("use_libretranslate")
        val LAST_SEEN_VERSION = stringPreferencesKey("last_seen_version")

        fun getTtsVoiceKey(code: String, region: String): androidx.datastore.preferences.core.Preferences.Key<String> {
            val c = code.lowercase()
            val r = region.trim()
            return stringPreferencesKey("tts_voice_" + if (r.isBlank()) c else "${c}_${r.uppercase()}")
        }
        fun getLegacyTtsVoiceKey(code: String) = stringPreferencesKey("tts_voice_" + code.lowercase())
        fun getApiKeyPrefKey(providerKey: String) = stringPreferencesKey("${providerKey}$API_KEY_SUFFIX")
    }

    suspend fun setTtsVoiceForLanguage(code: String, region: String, voiceName: String?) {
        context.dataStore.edit { prefs ->
            val key = PrefKeys.getTtsVoiceKey(code, region)
            if (voiceName.isNullOrBlank()) {
                prefs.remove(key)
            } else {
                prefs[key] = voiceName
            }
        }
    }

    fun getTtsVoiceForLanguage(code: String, region: String): Flow<String?> {
        val key = PrefKeys.getTtsVoiceKey(code, region)
        val legacy = PrefKeys.getLegacyTtsVoiceKey(code)
        return context.dataStore.data.map { prefs ->
            prefs[key] ?: prefs[legacy]
        }
    }

    @Deprecated("Use region-aware overload", ReplaceWith("getTtsVoiceForLanguage(code, region)"))
    fun getTtsVoiceForLanguage(code: String): Flow<String?> = getTtsVoiceForLanguage(code, "")

    @Deprecated("Use region-aware overload", ReplaceWith("setTtsVoiceForLanguage(code, region, voiceName)"))
    suspend fun setTtsVoiceForLanguage(code: String, voiceName: String?) = setTtsVoiceForLanguage(code, "", voiceName)

    val theme = Setting(context.dataStore, PrefKeys.THEME, "Default")
    val darkModePreference = Setting(context.dataStore, PrefKeys.DARK_MODE_PREFERENCE, "System")
    val fontPreference = Setting(context.dataStore, PrefKeys.FONT_PREFERENCE, "Default")
    val introCompleted = Setting(context.dataStore, PrefKeys.INTRO_COMPLETED, false)
    val developerMode = Setting(context.dataStore, PrefKeys.DEVELOPER_MODE, false)
    val dailyGoal = Setting(context.dataStore, PrefKeys.DAILY_GOAL, 10)
    val selectedCategories = Setting(context.dataStore, PrefKeys.SELECTED_CATEGORIES, emptySet())
    val dictionarySwitches = Setting(context.dataStore, PrefKeys.DICTIONARY_SWITCHES, emptySet())
    val customPromptTranslation = Setting(context.dataStore, PrefKeys.CUSTOM_PROMPT_TRANSLATION, "")
    val customPromptVocabulary = Setting(context.dataStore, PrefKeys.CUSTOM_PROMPT_VOCABULARY, "")
    val customPromptDictionary = Setting(context.dataStore, PrefKeys.CUSTOM_PROMPT_DICTIONARY, "")
    val customPromptExercise = Setting(context.dataStore, PrefKeys.CUSTOM_PROMPT_EXERCISE, "")
    val speakingSpeed = Setting(context.dataStore, PrefKeys.SPEAKING_SPEED, 100)
    val intervalNew = Setting(context.dataStore, PrefKeys.INTERVAL_NEW, 1)
    val intervalStage1 = Setting(context.dataStore, PrefKeys.INTERVAL_STAGE_1, 3)
    val intervalStage2 = Setting(context.dataStore, PrefKeys.INTERVAL_STAGE_2, 7)
    val intervalStage3 = Setting(context.dataStore, PrefKeys.INTERVAL_STAGE_3, 14)
    val intervalStage4 = Setting(context.dataStore, PrefKeys.INTERVAL_STAGE_4, 30)
    val intervalStage5 = Setting(context.dataStore, PrefKeys.INTERVAL_STAGE_5, 60)
    val intervalLearned = Setting(context.dataStore, PrefKeys.INTERVAL_LEARNED, 90)
    val criteriaCorrect = Setting(context.dataStore, PrefKeys.CRITERIA_CORRECT, 1)
    val criteriaWrong = Setting(context.dataStore, PrefKeys.CRITERIA_WRONG, 1)
    val showHints = Setting(context.dataStore, PrefKeys.SHOW_HINTS, true)
    val experimentalFeatures = Setting(context.dataStore, PrefKeys.EXPERIMENTAL_FEATURES, false)
    val tryWiktionaryFirst = Setting(context.dataStore, PrefKeys.TRY_WIKTIONARY_FIRST, false)
    val showBottomNavLabels = Setting(context.dataStore, PrefKeys.SHOW_BOTTOM_NAV_LABELS, true)
    val connectionConfigured = Setting(context.dataStore, PrefKeys.CONNECTION_CONFIGURED, true)
    val useLibreTranslate = Setting(context.dataStore, PrefKeys.USE_LIBRE_TRANSLATE, false)
    val lastSeenVersion = Setting(context.dataStore, PrefKeys.LAST_SEEN_VERSION, "")



    fun getAllApiKeys(): Flow<Map<String, String>> {
        return context.dataStore.data.map { preferences ->
            preferences.asMap().mapNotNull { (key, value) ->
                if (key.name.endsWith(PrefKeys.API_KEY_SUFFIX) && value is String) {
                    val providerKey = key.name.removeSuffix(PrefKeys.API_KEY_SUFFIX)
                    providerKey to value
                } else {
                    null
                }
            }.toMap()
        }
    }

    /**
     * Checks if the user has seen the "what's new" dialog for the current version
     */
    suspend fun hasSeenCurrentVersion(currentVersion: String): Boolean {
        val lastSeen = lastSeenVersion.flow.first()
        return lastSeen == currentVersion
    }

    /**
     * Marks the current version as seen by the user
     */
    suspend fun markVersionAsSeen(version: String) {
        lastSeenVersion.set(version)
    }

    /**
     * Saves an API key for a given provider.
     * The provider object is used to get the key, but the preference is stored dynamically.
     */
    suspend fun saveApiKey(provider: ApiProvider, apiKey: String) {
        context.dataStore.edit { settings ->
            settings[PrefKeys.getApiKeyPrefKey(provider.key)] = apiKey
        }
    }

    /**
     * Deletes an API key for a given provider.
     */
    suspend fun deleteApiKey(providerKey: String) {
        context.dataStore.edit { settings ->
            settings.remove(PrefKeys.getApiKeyPrefKey(providerKey))
        }
    }
}
