package com.optix.android.data.repository

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
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 com.optix.android.domain.model.AiProviderConfig
import com.optix.android.domain.model.AiProviderType
import com.optix.android.domain.model.AppSettings
import com.optix.android.domain.model.DEFAULT_SYSTEM_PROMPT
import com.optix.android.domain.model.NetworkSettings
import com.optix.android.domain.repository.SettingsRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class SettingsRepositoryImpl @Inject constructor(
    private val dataStore: DataStore<Preferences>,
) : SettingsRepository {

    override fun getAiConfig(): Flow<AiProviderConfig> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { prefs ->
            AiProviderConfig(
                provider = AiProviderType.valueOf(prefs[Keys.AI_PROVIDER] ?: AiProviderType.OPENROUTER.name),
                apiKey = prefs[Keys.AI_API_KEY] ?: "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",
                baseUrl = prefs[Keys.AI_BASE_URL] ?: "https://openrouter.ai/api/v1",
                model = prefs[Keys.AI_MODEL] ?: "openrouter/free",
                systemPrompt = prefs[Keys.AI_SYSTEM_PROMPT] ?: DEFAULT_SYSTEM_PROMPT,
            )
        }

    override suspend fun saveAiConfig(config: AiProviderConfig) {
        dataStore.edit { prefs ->
            prefs[Keys.AI_PROVIDER] = config.provider.name
            prefs[Keys.AI_API_KEY] = config.apiKey
            prefs[Keys.AI_BASE_URL] = config.baseUrl
            prefs[Keys.AI_MODEL] = config.model
            prefs[Keys.AI_SYSTEM_PROMPT] = config.systemPrompt
        }
    }

    override fun getAppSettings(): Flow<AppSettings> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { prefs ->
            AppSettings(
                darkTheme = prefs[Keys.DARK_THEME] ?: true,
                accentColor = prefs[Keys.ACCENT_COLOR] ?: "#00FF88",
                maxToolTimeoutSeconds = prefs[Keys.MAX_TIMEOUT] ?: 180,
                streamingEnabled = prefs[Keys.STREAMING_ENABLED] ?: true,
                favorites = prefs[Keys.FAVORITES] ?: emptySet(),
            )
        }

    override suspend fun saveAppSettings(settings: AppSettings) {
        dataStore.edit { prefs ->
            prefs[Keys.DARK_THEME] = settings.darkTheme
            prefs[Keys.ACCENT_COLOR] = settings.accentColor
            prefs[Keys.MAX_TIMEOUT] = settings.maxToolTimeoutSeconds
            prefs[Keys.STREAMING_ENABLED] = settings.streamingEnabled
            prefs[Keys.FAVORITES] = settings.favorites
        }
    }

    override suspend fun toggleFavorite(toolId: String) {
        dataStore.edit { prefs ->
            val current = prefs[Keys.FAVORITES] ?: emptySet()
            prefs[Keys.FAVORITES] = if (current.contains(toolId)) current - toolId else current + toolId
        }
    }

    override fun getNetworkSettings(): Flow<NetworkSettings> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { prefs ->
            NetworkSettings(
                defaultScanTimeout = prefs[Keys.NET_SCAN_TIMEOUT] ?: "400",
                defaultPortRange = prefs[Keys.NET_PORT_RANGE] ?: "1-9999",
                nmapFlags = prefs[Keys.NET_NMAP_FLAGS] ?: "-sV",
                autoScanOnOpen = prefs[Keys.NET_AUTO_SCAN] ?: true,
                aggressiveScan = prefs[Keys.NET_AGGRESSIVE] ?: false,
                proxyHost = prefs[Keys.NET_PROXY_HOST] ?: "",
                proxyPort = prefs[Keys.NET_PROXY_PORT] ?: "",
                useTor = prefs[Keys.NET_USE_TOR] ?: false,
                termuxPath = prefs[Keys.NET_TERMUX_PATH] ?: "/data/data/com.termux/files/usr/bin",
                autoInstallTools = prefs[Keys.NET_AUTO_INSTALL] ?: false,
                autoSaveSessions = prefs[Keys.NET_AUTO_SAVE] ?: true,
            )
        }

    override suspend fun saveNetworkSettings(settings: NetworkSettings) {
        dataStore.edit { prefs ->
            prefs[Keys.NET_SCAN_TIMEOUT] = settings.defaultScanTimeout
            prefs[Keys.NET_PORT_RANGE] = settings.defaultPortRange
            prefs[Keys.NET_NMAP_FLAGS] = settings.nmapFlags
            prefs[Keys.NET_AUTO_SCAN] = settings.autoScanOnOpen
            prefs[Keys.NET_AGGRESSIVE] = settings.aggressiveScan
            prefs[Keys.NET_PROXY_HOST] = settings.proxyHost
            prefs[Keys.NET_PROXY_PORT] = settings.proxyPort
            prefs[Keys.NET_USE_TOR] = settings.useTor
            prefs[Keys.NET_TERMUX_PATH] = settings.termuxPath
            prefs[Keys.NET_AUTO_INSTALL] = settings.autoInstallTools
            prefs[Keys.NET_AUTO_SAVE] = settings.autoSaveSessions
        }
    }

    private object Keys {
        val AI_PROVIDER       = stringPreferencesKey("ai_provider")
        val AI_API_KEY        = stringPreferencesKey("ai_api_key")
        val AI_BASE_URL       = stringPreferencesKey("ai_base_url")
        val AI_MODEL          = stringPreferencesKey("ai_model")
        val AI_SYSTEM_PROMPT  = stringPreferencesKey("ai_system_prompt")
        val DARK_THEME        = booleanPreferencesKey("dark_theme")
        val ACCENT_COLOR      = stringPreferencesKey("accent_color")
        val MAX_TIMEOUT       = intPreferencesKey("max_timeout")
        val STREAMING_ENABLED = booleanPreferencesKey("streaming_enabled")
        val FAVORITES         = stringSetPreferencesKey("favorites")
        // Network settings
        val NET_SCAN_TIMEOUT  = stringPreferencesKey("net_scan_timeout")
        val NET_PORT_RANGE    = stringPreferencesKey("net_port_range")
        val NET_NMAP_FLAGS    = stringPreferencesKey("net_nmap_flags")
        val NET_AUTO_SCAN     = booleanPreferencesKey("net_auto_scan")
        val NET_AGGRESSIVE    = booleanPreferencesKey("net_aggressive")
        val NET_PROXY_HOST    = stringPreferencesKey("net_proxy_host")
        val NET_PROXY_PORT    = stringPreferencesKey("net_proxy_port")
        val NET_USE_TOR       = booleanPreferencesKey("net_use_tor")
        val NET_TERMUX_PATH   = stringPreferencesKey("net_termux_path")
        val NET_AUTO_INSTALL  = booleanPreferencesKey("net_auto_install")
        val NET_AUTO_SAVE     = booleanPreferencesKey("net_auto_save")
        val DISCLAIMER_ACCEPTED = booleanPreferencesKey("disclaimer_accepted")
        val ETHICAL_ACK       = booleanPreferencesKey("ethical_ack")
        val THEME_IS_DARK = booleanPreferencesKey("theme_is_dark")
        val THEME_ACCENT_ID = stringPreferencesKey("theme_accent_id")
        // OSINT API keys
        val SHODAN_API_KEY = stringPreferencesKey("osint_shodan_api_key")
        val HUNTER_API_KEY = stringPreferencesKey("osint_hunter_api_key")
        val HIBP_API_KEY   = stringPreferencesKey("osint_hibp_api_key")
    }

    fun disclaimerAccepted(): Flow<Boolean> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { it[Keys.DISCLAIMER_ACCEPTED] ?: false }

    suspend fun acceptDisclaimer() {
        dataStore.edit { it[Keys.DISCLAIMER_ACCEPTED] = true }
    }

    fun isDarkTheme(): Flow<Boolean> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { it[Keys.THEME_IS_DARK] ?: true }

    fun getAccentId(): Flow<String> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { it[Keys.THEME_ACCENT_ID] ?: "red" }

    suspend fun saveThemeConfig(isDark: Boolean, accentId: String) {
        dataStore.edit {
            it[Keys.THEME_IS_DARK] = isDark
            it[Keys.THEME_ACCENT_ID] = accentId
        }
    }

    override fun getOsintApiKeys(): Flow<Map<String, String>> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { prefs ->
            buildMap {
                prefs[Keys.SHODAN_API_KEY]?.let { put("shodan", it) }
                prefs[Keys.HUNTER_API_KEY]?.let { put("hunter", it) }
                prefs[Keys.HIBP_API_KEY]?.let { put("hibp", it) }
            }
        }

    override suspend fun saveOsintApiKey(service: String, key: String) {
        dataStore.edit { prefs ->
            when (service.lowercase()) {
                "shodan" -> prefs[Keys.SHODAN_API_KEY] = key
                "hunter" -> prefs[Keys.HUNTER_API_KEY] = key
                "hibp"   -> prefs[Keys.HIBP_API_KEY] = key
            }
        }
    }

    override fun hasEthicalAck(): Flow<Boolean> = dataStore.data
        .catch { e -> if (e is IOException) emit(androidx.datastore.preferences.core.emptyPreferences()) else throw e }
        .map { it[Keys.ETHICAL_ACK] ?: false }

    override suspend fun setEthicalAck(acknowledged: Boolean) {
        dataStore.edit { it[Keys.ETHICAL_ACK] = acknowledged }
    }
}
