package de.hackernet.wireguardtv.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import de.hackernet.wireguardtv.model.TunnelConfig
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "wireguard_tunnels")

/**
 * Repository für WireGuard Tunnel Konfigurationen
 * Speichert als JSON in DataStore
 */
class TunnelRepository(private val context: Context) {

    private val gson = Gson()
    
    companion object {
        private val TUNNELS_KEY = stringPreferencesKey("tunnels")
        private val ACTIVE_TUNNEL_KEY = stringPreferencesKey("active_tunnel_id")
        private val SETTINGS_KEY = stringPreferencesKey("settings")
        
        @Volatile
        private var INSTANCE: TunnelRepository? = null

        fun getInstance(context: Context): TunnelRepository {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: TunnelRepository(context.applicationContext).also { INSTANCE = it }
            }
        }
    }

    /**
     * Alle Tunnel als Flow (für reaktive UI Updates)
     */
    val tunnelsFlow: Flow<List<TunnelConfig>> = context.dataStore.data.map { prefs ->
        val json = prefs[TUNNELS_KEY] ?: "[]"
        val type = object : TypeToken<List<TunnelConfig>>() {}.type
        gson.fromJson(json, type) ?: emptyList()
    }

    /**
     * Aktiver Tunnel ID als Flow
     */
    val activeTunnelIdFlow: Flow<String?> = context.dataStore.data.map { prefs ->
        prefs[ACTIVE_TUNNEL_KEY]
    }

    /**
     * Alle Tunnel synchron abrufen
     */
    suspend fun getTunnels(): List<TunnelConfig> {
        return tunnelsFlow.first()
    }

    /**
     * Einzelnen Tunnel nach ID
     */
    suspend fun getTunnel(id: String): TunnelConfig? {
        return getTunnels().find { it.id == id }
    }

    /**
     * Tunnel hinzufügen
     */
    suspend fun addTunnel(config: TunnelConfig): TunnelConfig {
        context.dataStore.edit { prefs ->
            val tunnels = getTunnels().toMutableList()
            tunnels.add(config)
            prefs[TUNNELS_KEY] = gson.toJson(tunnels)
        }
        return config
    }

    /**
     * Tunnel aktualisieren
     */
    suspend fun updateTunnel(config: TunnelConfig) {
        context.dataStore.edit { prefs ->
            val tunnels = getTunnels().toMutableList()
            val index = tunnels.indexOfFirst { it.id == config.id }
            if (index >= 0) {
                tunnels[index] = config
                prefs[TUNNELS_KEY] = gson.toJson(tunnels)
            }
        }
    }

    /**
     * Tunnel löschen
     */
    suspend fun deleteTunnel(id: String) {
        context.dataStore.edit { prefs ->
            val tunnels = getTunnels().toMutableList()
            tunnels.removeAll { it.id == id }
            prefs[TUNNELS_KEY] = gson.toJson(tunnels)
            
            // Falls aktiver Tunnel gelöscht wurde
            if (prefs[ACTIVE_TUNNEL_KEY] == id) {
                prefs.remove(ACTIVE_TUNNEL_KEY)
            }
        }
    }

    /**
     * Aktiven Tunnel setzen
     */
    suspend fun setActiveTunnel(id: String?) {
        context.dataStore.edit { prefs ->
            if (id != null) {
                prefs[ACTIVE_TUNNEL_KEY] = id
            } else {
                prefs.remove(ACTIVE_TUNNEL_KEY)
            }
        }
    }

    /**
     * Aktiven Tunnel abrufen
     */
    suspend fun getActiveTunnelId(): String? {
        return activeTunnelIdFlow.first()
    }

    /**
     * Import aus .conf String
     */
    suspend fun importFromConf(confString: String, name: String): TunnelConfig {
        val config = TunnelConfig.fromConfString(confString, name)
        return addTunnel(config)
    }

    /**
     * Export als .conf String
     */
    suspend fun exportToConf(id: String): String? {
        return getTunnel(id)?.toConfString()
    }

    /**
     * Alle Tunnel löschen (für Reset)
     */
    suspend fun clearAll() {
        context.dataStore.edit { prefs ->
            prefs.remove(TUNNELS_KEY)
            prefs.remove(ACTIVE_TUNNEL_KEY)
        }
    }
}

/**
 * App-Einstellungen
 */
data class AppSettings(
    val autoConnectOnBoot: Boolean = false,
    val defaultTunnelId: String? = null,
    val killSwitch: Boolean = false,
    val excludedApps: List<String> = emptyList(),
    // WebServer Einstellungen
    val webServerPort: Int = 8080,
    val webServerPasswordEnabled: Boolean = false,
    val webServerPassword: String = "",
    val webServerAutoStart: Boolean = false
)

// DataStore muss als Top-Level Property definiert werden für Singleton-Verhalten
private val Context.settingsStore: DataStore<Preferences> by preferencesDataStore(name = "wireguard_settings")

class SettingsRepository private constructor(private val context: Context) {

    private val gson = Gson()

    companion object {
        private val SETTINGS_KEY = stringPreferencesKey("app_settings")

        @Volatile
        private var INSTANCE: SettingsRepository? = null

        fun getInstance(context: Context): SettingsRepository {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: SettingsRepository(context.applicationContext).also { INSTANCE = it }
            }
        }
    }

    val settingsFlow: Flow<AppSettings> = context.settingsStore.data.map { prefs ->
        val json = prefs[SETTINGS_KEY]
        if (json != null) {
            gson.fromJson(json, AppSettings::class.java)
        } else {
            AppSettings()
        }
    }

    suspend fun getSettings(): AppSettings = settingsFlow.first()

    suspend fun updateSettings(settings: AppSettings) {
        context.settingsStore.edit { prefs ->
            prefs[SETTINGS_KEY] = gson.toJson(settings)
        }
    }
}
