@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.repository

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import eu.gaudian.translator.model.LanguageModel
import eu.gaudian.translator.model.communication.ApiProvider
import eu.gaudian.translator.utils.Log
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map

class ApiRepository(private val context: Context) {

    private val settingsRepository = SettingsRepository(context)
    private val dataStore: DataStore<Preferences> = context.dataStore

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

    /**
     * Checks and sets fallback models.
     * Enforces consistency: If no key is present, default models are removed.
     */
    suspend fun initialInit() {
        Log.i(TAG, "Starting initial model check...")

        val jsonProviders = ApiProvider.loadProviders(context.applicationContext)
        val jsonProvidersByKey = jsonProviders.associateBy { it.key }

        // Load currently saved providers
        var storedProviders = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).first()

        // 1. First Run Handling
        if (storedProviders.isEmpty()) {
            Log.i(TAG, "DataStore empty. Initializing with JSON defaults.")
            val initial = jsonProviders.map {
                if (!it.isCustom) it.copy(models = emptyList()) else it
            }
            saveProviders(initial)
            storedProviders = initial
        }

        val apiKeys = getAllApiKeys().first()
        var needsSync = false

        // --- NEW STEP: CLEANUP ---
        // Filter out providers that are NOT custom AND are NO LONGER in the JSON
        val validStoredProviders = storedProviders.filter { stored ->
            val stillExistsInJson = jsonProvidersByKey.containsKey(stored.key)
            val isCustom = stored.isCustom

            // Keep it if it's custom OR if it still exists in the JSON source
            if (isCustom || stillExistsInJson) {
                true
            } else {
                Log.i(TAG, "Removing obsolete provider: ${stored.displayName} (Key: ${stored.key})")
                needsSync = true
                false // Drop this provider
            }
        }

        // 2. Sync Existing Providers (Run logic on the CLEANED list)
        val syncedStoredProviders = validStoredProviders.map { stored ->
            if (!stored.isCustom) {
                val latestDefault = jsonProvidersByKey[stored.key]
                if (latestDefault != null) {
                    val hasKey = apiKeys[stored.key]?.isNotBlank() ?: false
                    val customModels = stored.models.filter { it.isCustom }

                    val targetModels = if (hasKey) {
                        val newDefaultModels = latestDefault.models.filter { !it.isCustom }
                        (customModels + newDefaultModels).distinctBy { it.modelId }
                    } else {
                        customModels
                    }

                    val needsUpdate = stored.displayName != latestDefault.displayName ||
                            stored.baseUrl != latestDefault.baseUrl ||
                            stored.endpoint != latestDefault.endpoint ||
                            stored.websiteUrl != latestDefault.websiteUrl ||
                            stored.models.size != targetModels.size ||
                            stored.models.map { it.modelId }.toSet() != targetModels.map { it.modelId }.toSet()

                    if (needsUpdate) {
                        needsSync = true
                        stored.copy(
                            displayName = latestDefault.displayName,
                            baseUrl = latestDefault.baseUrl,
                            endpoint = latestDefault.endpoint,
                            websiteUrl = latestDefault.websiteUrl,
                            models = targetModels,
                            isCustom = false
                        )
                    } else {
                        stored
                    }
                } else {
                    stored
                }
            } else {
                stored
            }
        }

        // 3. Detect & Add NEW Providers
        val existingKeys = syncedStoredProviders.map { it.key }.toSet()
        val newProvidersFromJson = jsonProviders.filter { it.key !in existingKeys }

        val newProvidersInitialized = newProvidersFromJson.map {
            if (!it.isCustom) it.copy(models = emptyList()) else it
        }

        if (newProvidersInitialized.isNotEmpty()) {
            Log.i(TAG, "Found ${newProvidersInitialized.size} new providers in JSON. Adding them.")
            needsSync = true
        }

        // 4. Save and Apply
        val finalProviderList = syncedStoredProviders + newProvidersInitialized

        if (needsSync) {
            Log.i(TAG, "Syncing providers...")
            saveProviders(finalProviderList)
            storedProviders = finalProviderList
        }

        // 5. Fallback Selection Logic
        val currentTrans = getTranslationModel().first()
        val currentExer = getExerciseModel().first()
        val currentVocab = getVocabularyModel().first()
        val currentDict = getDictionaryModel().first()

        val validProviders = storedProviders.filter { provider ->
            val hasKey = apiKeys[provider.key]?.isNotBlank() ?: false
            val isLocalHost = provider.baseUrl.contains("localhost") || provider.baseUrl.contains("127.0.0.1")
            hasKey || isLocalHost || provider.isCustom
        }
        val availableModels = validProviders.flatMap { it.models }

        var configurationValid = true

        // Fallback checks
        if (currentTrans == null || !availableModels.any { it.modelId == currentTrans.modelId && it.providerKey == currentTrans.providerKey }) {
            findFallbackModel(availableModels)?.let { setTranslationModel(it) } ?: run { configurationValid = false }
        }

        if (currentExer == null || !availableModels.any { it.modelId == currentExer.modelId && it.providerKey == currentExer.providerKey }) {
            findFallbackModel(availableModels)?.let { setExerciseModel(it) } ?: run { configurationValid = false }
        }

        if (currentVocab == null || !availableModels.any { it.modelId == currentVocab.modelId && it.providerKey == currentVocab.providerKey }) {
            findFallbackModel(availableModels)?.let { setVocabularyModel(it) } ?: run { configurationValid = false }
        }

        if (currentDict == null || !availableModels.any { it.modelId == currentDict.modelId && it.providerKey == currentDict.providerKey }) {
            findFallbackModel(availableModels)?.let { setDictionaryModel(it) } ?: run { configurationValid = false }
        }

        settingsRepository.connectionConfigured.set(configurationValid)
    }

    /**
     * Manually adds default models for a provider (Triggered on Key Activation).
     */
    suspend fun addDefaultModels(providerKey: String) {
        val currentProviders = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).first().toMutableList()
        val index = currentProviders.indexOfFirst { it.key == providerKey }
        if (index == -1) return

        val stored = currentProviders[index]
        if (stored.isCustom) return // Don't touch custom providers

        val jsonProviders = ApiProvider.loadProviders(context.applicationContext)
        val default = jsonProviders.find { it.key == providerKey } ?: return

        // Merge default models into existing (preserving customs)
        val customModels = stored.models.filter { it.isCustom }
        val defaultModels = default.models.filter { !it.isCustom }
        val merged = (customModels + defaultModels).distinctBy { it.modelId }

        currentProviders[index] = stored.copy(models = merged)
        saveProviders(currentProviders)
        Log.i(TAG, "Added default models for $providerKey. Count: ${defaultModels.size}")
    }

    /**
     * Manually removes default models for a provider (Triggered on Key Deactivation).
     */
    suspend fun removeDefaultModels(providerKey: String) {
        val currentProviders = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).first().toMutableList()
        val index = currentProviders.indexOfFirst { it.key == providerKey }
        if (index == -1) return

        val stored = currentProviders[index]
        if (stored.isCustom) return

        // Remove all non-custom models
        val customOnly = stored.models.filter { it.isCustom }

        currentProviders[index] = stored.copy(models = customOnly)
        saveProviders(currentProviders)
        Log.i(TAG, "Removed default models for $providerKey.")
    }

    fun getProviders(): Flow<List<ApiProvider>> {
        val providersFlow = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).map { list ->
            list.ifEmpty {
                ApiProvider.loadProviders(context.applicationContext).map {
                    // Initial state: No key = No models
                    if (!it.isCustom) it.copy(models = emptyList()) else it
                }
            }
        }
        val apiKeysFlow = getAllApiKeys()

        return combine(providersFlow, apiKeysFlow) { providers, apiKeys ->
            providers.map { provider ->
                val hasKey = apiKeys[provider.key]?.isNotBlank() ?: false
                val base = provider.baseUrl.trim().lowercase()
                val isLocalHost = (base.contains("localhost") || base.contains("127.0.0.1") || base.startsWith("10."))

                provider.copy().apply {
                    hasValidKey = hasKey || isLocalHost || isCustom
                }
            }
        }
    }

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

    private fun findFallbackModel(allModels: List<LanguageModel>): LanguageModel? {
        val preferredProviderOrder = listOf("mistral", "openai", "gemini", "deepseek", "openrouter")
        for (providerKey in preferredProviderOrder) {
            val model = allModels.firstOrNull { it.providerKey == providerKey }
            if (model != null) return model
        }
        return allModels.firstOrNull()
    }

    suspend fun saveProviders(providers: List<ApiProvider>) {
        try {
            dataStore.saveObjectList(DataStoreKeys.PROVIDERS_KEY, providers)
        } catch (e: Exception) {
            Log.e(TAG, "Error saving providers: ${e.message}", e)
        }
    }

    suspend fun addProvider(provider: ApiProvider) {
        val currentProviders = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).first().toMutableList()
        if (currentProviders.none { it.key == provider.key }) {
            currentProviders.add(provider)
            saveProviders(currentProviders)
            initialInit()
        }
    }

    suspend fun updateProvider(updatedProvider: ApiProvider) {
        val currentProviders = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).first().toMutableList()
        val index = currentProviders.indexOfFirst { it.key == updatedProvider.key }
        if (index != -1) {
            currentProviders[index] = updatedProvider
            saveProviders(currentProviders)
            initialInit()
        }
    }

    suspend fun deleteProvider(providerKey: String) {
        val currentProviders = dataStore.loadObjectList<ApiProvider>(DataStoreKeys.PROVIDERS_KEY).first().toMutableList()
        val removed = currentProviders.removeAll { it.key == providerKey && it.isCustom }
        if (removed) {
            saveProviders(currentProviders)
            initialInit()
        }
    }

    /* --- Model Selection Setters --- */

    suspend fun setTranslationModel(model: LanguageModel) {
        dataStore.saveObject(DataStoreKeys.SELECTED_TRANSLATION_MODEL_KEY, model)
        settingsRepository.connectionConfigured.set(true)
    }
    fun getTranslationModel(): Flow<LanguageModel?> = dataStore.loadObject(DataStoreKeys.SELECTED_TRANSLATION_MODEL_KEY)

    suspend fun setExerciseModel(model: LanguageModel) {
        dataStore.saveObject(DataStoreKeys.SELECTED_EXERCISE_MODEL_KEY, model)
        settingsRepository.connectionConfigured.set(true)
    }
    fun getExerciseModel(): Flow<LanguageModel?> = dataStore.loadObject(DataStoreKeys.SELECTED_EXERCISE_MODEL_KEY)

    suspend fun setVocabularyModel(model: LanguageModel) {
        dataStore.saveObject(DataStoreKeys.SELECTED_VOCABULARY_MODEL_KEY, model)
        settingsRepository.connectionConfigured.set(true)
    }
    fun getVocabularyModel(): Flow<LanguageModel?> = dataStore.loadObject(DataStoreKeys.SELECTED_VOCABULARY_MODEL_KEY)

    suspend fun setDictionaryModel(model: LanguageModel) {
        dataStore.saveObject(DataStoreKeys.SELECTED_DICTIONARY_MODEL_KEY, model)
        settingsRepository.connectionConfigured.set(true)
    }
    fun getDictionaryModel(): Flow<LanguageModel?> = dataStore.loadObject(DataStoreKeys.SELECTED_DICTIONARY_MODEL_KEY)

    suspend fun wipeAll() {
        Log.w(TAG, "Executing wipeAll()")
        settingsRepository.connectionConfigured.set(false)
        try {
            dataStore.edit { prefs ->
                prefs.remove(DataStoreKeys.PROVIDERS_KEY)
                prefs.remove(DataStoreKeys.SELECTED_TRANSLATION_MODEL_KEY)
                prefs.remove(DataStoreKeys.SELECTED_EXERCISE_MODEL_KEY)
                prefs.remove(DataStoreKeys.SELECTED_VOCABULARY_MODEL_KEY)
                prefs.remove(DataStoreKeys.SELECTED_DICTIONARY_MODEL_KEY)

                val apiKeySuffix = "_api_key"
                val keysToRemove = prefs.asMap().keys.filter { it.name.endsWith(apiKeySuffix) }
                for (k in keysToRemove) {
                    @Suppress("UNCHECKED_CAST")
                    val anyKey = k as Preferences.Key<Any>
                    prefs.remove(anyKey)
                }
            }
            // initialInit will be called, see empty DataStore, and reload default providers (with EMPTY models)
            initialInit()
        } catch (e: Exception) {
            Log.e(TAG, "Error during wipeAll: ${e.message}", e)
        }
    }}
