/**
 * Android Consent SDK - ConsentManager
 *
 * DSGVO/TTDSG-konformes Consent Management fuer Android Apps.
 *
 * Nutzung:
 * 1. In Application.onCreate() konfigurieren
 * 2. In Activities/Fragments mit ConsentManager.current nutzen
 * 3. In Jetpack Compose mit rememberConsentState()
 *
 * Copyright (c) 2025 BreakPilot
 * Apache License 2.0
 */

package com.breakpilot.consent

import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import android.provider.Settings
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import java.security.MessageDigest
import java.util.*

// =============================================================================
// Consent Categories
// =============================================================================

/**
 * Standard-Consent-Kategorien nach IAB TCF 2.2
 */
enum class ConsentCategory {
    ESSENTIAL,     // Technisch notwendig
    FUNCTIONAL,    // Personalisierung
    ANALYTICS,     // Nutzungsanalyse
    MARKETING,     // Werbung
    SOCIAL         // Social Media
}

// =============================================================================
// Consent State
// =============================================================================

/**
 * Aktueller Consent-Zustand
 */
@Serializable
data class ConsentState(
    val categories: Map<ConsentCategory, Boolean> = defaultCategories(),
    val vendors: Map<String, Boolean> = emptyMap(),
    val timestamp: Long = System.currentTimeMillis(),
    val version: String = "1.0.0",
    val consentId: String? = null,
    val expiresAt: Long? = null,
    val tcfString: String? = null
) {
    companion object {
        fun defaultCategories() = mapOf(
            ConsentCategory.ESSENTIAL to true,
            ConsentCategory.FUNCTIONAL to false,
            ConsentCategory.ANALYTICS to false,
            ConsentCategory.MARKETING to false,
            ConsentCategory.SOCIAL to false
        )

        val DEFAULT = ConsentState()
    }
}

// =============================================================================
// Configuration
// =============================================================================

/**
 * SDK-Konfiguration
 */
data class ConsentConfig(
    val apiEndpoint: String,
    val siteId: String,
    val language: String = Locale.getDefault().language,
    val showRejectAll: Boolean = true,
    val showAcceptAll: Boolean = true,
    val granularControl: Boolean = true,
    val rememberDays: Int = 365,
    val debug: Boolean = false
)

// =============================================================================
// Consent Manager
// =============================================================================

/**
 * Haupt-Manager fuer Consent-Verwaltung
 */
class ConsentManager private constructor() {

    // State
    private val _consent = MutableStateFlow(ConsentState.DEFAULT)
    val consent: StateFlow<ConsentState> = _consent.asStateFlow()

    private val _isInitialized = MutableStateFlow(false)
    val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()

    private val _isLoading = MutableStateFlow(true)
    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

    private val _isBannerVisible = MutableStateFlow(false)
    val isBannerVisible: StateFlow<Boolean> = _isBannerVisible.asStateFlow()

    private val _isSettingsVisible = MutableStateFlow(false)
    val isSettingsVisible: StateFlow<Boolean> = _isSettingsVisible.asStateFlow()

    // Private
    private var config: ConsentConfig? = null
    private var storage: ConsentStorage? = null
    private var apiClient: ConsentApiClient? = null
    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

    // Singleton
    companion object {
        @Volatile
        private var INSTANCE: ConsentManager? = null

        val current: ConsentManager
            get() = INSTANCE ?: synchronized(this) {
                INSTANCE ?: ConsentManager().also { INSTANCE = it }
            }

        /**
         * Konfiguriert den ConsentManager
         * Sollte in Application.onCreate() aufgerufen werden
         */
        fun configure(context: Context, config: ConsentConfig) {
            current.apply {
                this.config = config
                this.storage = ConsentStorage(context)
                this.apiClient = ConsentApiClient(config.apiEndpoint, config.siteId)

                if (config.debug) {
                    println("[ConsentSDK] Configured with siteId: ${config.siteId}")
                }

                scope.launch {
                    initialize(context)
                }
            }
        }
    }

    // ==========================================================================
    // Initialization
    // ==========================================================================

    private suspend fun initialize(context: Context) {
        try {
            // Lokalen Consent laden
            storage?.load()?.let { stored ->
                // Pruefen ob abgelaufen
                val expiresAt = stored.expiresAt
                if (expiresAt != null && System.currentTimeMillis() > expiresAt) {
                    _consent.value = ConsentState.DEFAULT
                    storage?.clear()
                } else {
                    _consent.value = stored
                }
            }

            // Vom Server synchronisieren
            try {
                apiClient?.getConsent(DeviceFingerprint.generate(context))?.let { serverConsent ->
                    _consent.value = serverConsent
                    storage?.save(serverConsent)
                }
            } catch (e: Exception) {
                if (config?.debug == true) {
                    println("[ConsentSDK] Failed to sync consent: $e")
                }
            }

            _isInitialized.value = true

            // Banner anzeigen falls noetig
            if (needsConsent) {
                showBanner()
            }
        } finally {
            _isLoading.value = false
        }
    }

    // ==========================================================================
    // Public API
    // ==========================================================================

    /**
     * Prueft ob Consent fuer Kategorie erteilt wurde
     */
    fun hasConsent(category: ConsentCategory): Boolean {
        // Essential ist immer erlaubt
        if (category == ConsentCategory.ESSENTIAL) return true
        return consent.value.categories[category] ?: false
    }

    /**
     * Prueft ob Consent eingeholt werden muss
     */
    val needsConsent: Boolean
        get() = consent.value.consentId == null

    /**
     * Alle Kategorien akzeptieren
     */
    suspend fun acceptAll() {
        val newCategories = ConsentCategory.values().associateWith { true }
        val newConsent = consent.value.copy(
            categories = newCategories,
            timestamp = System.currentTimeMillis()
        )
        saveConsent(newConsent)
        hideBanner()
    }

    /**
     * Alle nicht-essentiellen Kategorien ablehnen
     */
    suspend fun rejectAll() {
        val newCategories = ConsentCategory.values().associateWith {
            it == ConsentCategory.ESSENTIAL
        }
        val newConsent = consent.value.copy(
            categories = newCategories,
            timestamp = System.currentTimeMillis()
        )
        saveConsent(newConsent)
        hideBanner()
    }

    /**
     * Auswahl speichern
     */
    suspend fun saveSelection(categories: Map<ConsentCategory, Boolean>) {
        val updated = categories.toMutableMap()
        updated[ConsentCategory.ESSENTIAL] = true // Essential immer true
        val newConsent = consent.value.copy(
            categories = updated,
            timestamp = System.currentTimeMillis()
        )
        saveConsent(newConsent)
        hideBanner()
    }

    // ==========================================================================
    // UI Control
    // ==========================================================================

    fun showBanner() {
        _isBannerVisible.value = true
    }

    fun hideBanner() {
        _isBannerVisible.value = false
    }

    fun showSettings() {
        _isSettingsVisible.value = true
    }

    fun hideSettings() {
        _isSettingsVisible.value = false
    }

    // ==========================================================================
    // Private Methods
    // ==========================================================================

    private suspend fun saveConsent(newConsent: ConsentState) {
        // Lokal speichern
        storage?.save(newConsent)

        // An Server senden
        try {
            val response = apiClient?.saveConsent(
                newConsent,
                DeviceFingerprint.generate(storage?.context!!)
            )
            val updated = newConsent.copy(
                consentId = response?.consentId,
                expiresAt = response?.expiresAt
            )
            _consent.value = updated
            storage?.save(updated)
        } catch (e: Exception) {
            // Lokal speichern auch bei Fehler
            _consent.value = newConsent
            if (config?.debug == true) {
                println("[ConsentSDK] Failed to sync consent: $e")
            }
        }
    }
}

// =============================================================================
// Storage
// =============================================================================

/**
 * Sichere Speicherung mit EncryptedSharedPreferences
 */
internal class ConsentStorage(val context: Context) {
    private val prefs: SharedPreferences by lazy {
        val masterKey = MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

        EncryptedSharedPreferences.create(
            context,
            "breakpilot_consent",
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }

    private val json = Json { ignoreUnknownKeys = true }

    fun load(): ConsentState? {
        val data = prefs.getString("consent_state", null) ?: return null
        return try {
            json.decodeFromString<ConsentState>(data)
        } catch (e: Exception) {
            null
        }
    }

    fun save(consent: ConsentState) {
        val data = json.encodeToString(consent)
        prefs.edit().putString("consent_state", data).apply()
    }

    fun clear() {
        prefs.edit().remove("consent_state").apply()
    }
}

// =============================================================================
// API Client
// =============================================================================

/**
 * API Client fuer Backend-Kommunikation
 */
internal class ConsentApiClient(
    private val baseUrl: String,
    private val siteId: String
) {
    private val client = OkHttpClient()
    private val json = Json { ignoreUnknownKeys = true }

    @Serializable
    data class ConsentResponse(
        val consentId: String,
        val expiresAt: Long
    )

    suspend fun getConsent(fingerprint: String): ConsentState? = withContext(Dispatchers.IO) {
        val request = Request.Builder()
            .url("$baseUrl/banner/consent?site_id=$siteId&fingerprint=$fingerprint")
            .get()
            .build()

        client.newCall(request).execute().use { response ->
            if (!response.isSuccessful) return@withContext null
            val body = response.body?.string() ?: return@withContext null
            json.decodeFromString<ConsentState>(body)
        }
    }

    suspend fun saveConsent(
        consent: ConsentState,
        fingerprint: String
    ): ConsentResponse = withContext(Dispatchers.IO) {
        val body = """
            {
                "site_id": "$siteId",
                "device_fingerprint": "$fingerprint",
                "categories": ${json.encodeToString(consent.categories.mapKeys { it.key.name.lowercase() })},
                "vendors": ${json.encodeToString(consent.vendors)},
                "platform": "android",
                "app_version": "${BuildConfig.VERSION_NAME}"
            }
        """.trimIndent()

        val request = Request.Builder()
            .url("$baseUrl/banner/consent")
            .post(body.toRequestBody("application/json".toMediaType()))
            .build()

        client.newCall(request).execute().use { response ->
            val responseBody = response.body?.string() ?: throw Exception("Empty response")
            json.decodeFromString<ConsentResponse>(responseBody)
        }
    }
}

// =============================================================================
// Device Fingerprint
// =============================================================================

/**
 * Privacy-konformer Device Fingerprint
 */
internal object DeviceFingerprint {
    fun generate(context: Context): String {
        // Android ID (reset bei Factory Reset)
        val androidId = Settings.Secure.getString(
            context.contentResolver,
            Settings.Secure.ANDROID_ID
        ) ?: UUID.randomUUID().toString()

        // Device Info
        val model = Build.MODEL
        val version = Build.VERSION.SDK_INT.toString()
        val locale = Locale.getDefault().toString()

        // Hash erstellen
        val raw = "$androidId-$model-$version-$locale"
        val md = MessageDigest.getInstance("SHA-256")
        val digest = md.digest(raw.toByteArray())
        return digest.joinToString("") { "%02x".format(it) }
    }
}

// =============================================================================
// Jetpack Compose Integration
// =============================================================================

/**
 * State Holder fuer Compose
 */
@Composable
fun rememberConsentState(): State<ConsentState> {
    return ConsentManager.current.consent.collectAsState()
}

/**
 * Banner Visibility State
 */
@Composable
fun rememberBannerVisibility(): State<Boolean> {
    return ConsentManager.current.isBannerVisible.collectAsState()
}

/**
 * Consent Gate - Zeigt Inhalt nur bei Consent
 */
@Composable
fun ConsentGate(
    category: ConsentCategory,
    placeholder: @Composable () -> Unit = {},
    content: @Composable () -> Unit
) {
    val consent by rememberConsentState()

    if (ConsentManager.current.hasConsent(category)) {
        content()
    } else {
        placeholder()
    }
}

/**
 * Local Composition fuer ConsentManager
 */
val LocalConsentManager = staticCompositionLocalOf { ConsentManager.current }

/**
 * Consent Provider
 */
@Composable
fun ConsentProvider(
    content: @Composable () -> Unit
) {
    CompositionLocalProvider(
        LocalConsentManager provides ConsentManager.current
    ) {
        content()
    }
}
