package partisan.weforge.xyz.pulse

import android.content.Context
import androidx.core.content.edit
import androidx.preference.PreferenceManager

class Preferences(private val context: Context) {

    companion object {
        private const val REDIRECTION_DELAY = "redirection_delay"
        private const val POPUP_POSITION = "popup_position_y"
        private const val POPUP_ENABLED = "popup_enabled"
        private val POPUP_EFFECT = "popup_effect"
        private const val BLACKLISTED_CONTACTS = "blacklisted_contacts"
        private const val BLACKLIST_ENABLED = "blacklist_enabled"
        private val SERVICE_ORDER_KEY = "service_order"
        private const val DONATION_ACTIVATED = "donation_activated"
        private const val DONATION_TOKEN = "donation_token"

        private const val REDIRECT_WIFI = "redirect_wifi"
        private const val REDIRECT_DATA = "redirect_data"
        private const val REDIRECT_INTERNATIONAL = "redirect_international"
        private const val REDIRECT_ROAMING = "redirect_roaming"

        private const val DEFAULT_REDIRECTION_DELAY = 2000L
        private const val DEFAULT_POPUP_POSITION = 333
        private const val SERVICE_ENABLED = "service_enabled"
    }

    private val prefs = PreferenceManager.getDefaultSharedPreferences(context)

    // Whether user enabled/disabled the service manually by tiggle button
    var isServiceEnabledByUser: Boolean
        get() = prefs.getBoolean(SERVICE_ENABLED, true)
        set(value) = prefs.edit { putBoolean(SERVICE_ENABLED, value) }

    // True only if all required permissions + toggle are satisfied
    val isEnabled: Boolean
        get() = isServiceEnabledByUser &&
                hasGeneralPermissions(context) &&
                hasCallRedirectionRole(context) &&
                (popupEnabled.not() || hasDrawOverlays(context))

    enum class PopupEffect {
        NONE, FADE, SCALE, BOUNCE, FLOP, MATRIX, SLIDE_SNAP, GAMER_MODE, RANDOM
    }

    var popupEffect: PopupEffect
        get() {
            val name = prefs.getString(POPUP_EFFECT, PopupEffect.FADE.name) ?: PopupEffect.FADE.name
            return try {
                PopupEffect.valueOf(name)
            } catch (_: IllegalArgumentException) {
                // If invalid, fallback and clear the broken value
                prefs.edit().remove(POPUP_EFFECT).apply()
                PopupEffect.BOUNCE
            }
        }
        set(value) {
            prefs.edit().putString(POPUP_EFFECT, value.name).apply()
        }

    var isBlacklistEnabled: Boolean
        get() = prefs.getBoolean(BLACKLIST_ENABLED, false)
        set(value) = prefs.edit { putBoolean(BLACKLIST_ENABLED, value) }

    var isDonationActivated: Boolean
        get() = prefs.getBoolean(DONATION_ACTIVATED, false)
        set(value) = prefs.edit { putBoolean(DONATION_ACTIVATED, value) }

    var donationToken: String
        get() {
            val stored = prefs.getString(DONATION_TOKEN, null)
            return if (stored != null) {
                stored
            } else {
                generateAndStoreToken()
            }
        }
        set(value) = prefs.edit { putString(DONATION_TOKEN, value) }
    
    var popupEnabled: Boolean
        get() = prefs.getBoolean(POPUP_ENABLED, true)
        set(value) = prefs.edit { putBoolean(POPUP_ENABLED, value) }

    var redirectionDelay: Long
        get() = prefs.getLong(REDIRECTION_DELAY, DEFAULT_REDIRECTION_DELAY)
        set(value) = prefs.edit { putLong(REDIRECTION_DELAY, value) }

    var popupPosition: Int
        get() = prefs.getInt(POPUP_POSITION, DEFAULT_POPUP_POSITION)
        set(value) = prefs.edit { putInt(POPUP_POSITION, value) }

    var redirectOnWifi: Boolean
        get() = prefs.getBoolean(REDIRECT_WIFI, true)
        set(value) = prefs.edit { putBoolean(REDIRECT_WIFI, value) }

    var redirectOnData: Boolean
        get() = prefs.getBoolean(REDIRECT_DATA, true)
        set(value) = prefs.edit { putBoolean(REDIRECT_DATA, value) }

    var redirectInternationalOnly: Boolean
        get() = prefs.getBoolean(REDIRECT_INTERNATIONAL, false)
        set(value) = prefs.edit { putBoolean(REDIRECT_INTERNATIONAL, value) }

    var redirectIfRoaming: Boolean
        get() = prefs.getBoolean(REDIRECT_ROAMING, false)
        set(value) = prefs.edit { putBoolean(REDIRECT_ROAMING, value) }

    private fun makeKeyEnabled(mimetype: String) = "enabled_$mimetype"
    private fun makeKeyPriority(mimetype: String) = "priority_$mimetype"

    fun getAvailablePopupEffects(): List<PopupEffect> {
        val locked = listOf(
            PopupEffect.FLOP,
            PopupEffect.MATRIX,
            PopupEffect.SLIDE_SNAP,
            PopupEffect.GAMER_MODE
        )
        return PopupEffect.values().filter {
            isDonationActivated || it !in locked
        }.filter { it != PopupEffect.RANDOM && it != PopupEffect.NONE }
    }

    fun isServiceEnabled(mimetype: String): Boolean {
        return prefs.getBoolean(makeKeyEnabled(mimetype), true)
    }

    fun getServicePriority(mimetype: String): Int {
        val order = getServiceOrder()
        val index = order.indexOf(mimetype)
        return if (index != -1) index else Int.MAX_VALUE
    }

    fun getServiceOrder(): List<String> {
        val stored = prefs.getString(SERVICE_ORDER_KEY, null)
        return stored?.split("|")?.filter { it.isNotBlank() } ?: emptyList()
    }

    fun setServiceOrder(order: List<String>) {
        prefs.edit().putString(SERVICE_ORDER_KEY, order.joinToString("|")).apply()
    }

    fun setServiceEnabled(mimetype: String, enabled: Boolean) {
        prefs.edit().putBoolean(makeKeyEnabled(mimetype), enabled).apply()
    }

    fun setServicePriority(mimetype: String, priority: Int) {
        prefs.edit().putInt(makeKeyPriority(mimetype), priority).apply()
    }

    var blacklistedContacts: Set<String>
        get() = prefs.getStringSet(BLACKLISTED_CONTACTS, emptySet()) ?: emptySet()
        set(value) = prefs.edit { putStringSet(BLACKLISTED_CONTACTS, value) }

    fun isContactWhitelisted(phoneNumber: String): Boolean {
        return !blacklistedContacts.contains(phoneNumber)
    }

    fun setContactWhitelisted(phoneNumber: String, allowed: Boolean) {
        val current = blacklistedContacts.toMutableSet()
        if (!allowed) {
            current.add(phoneNumber)
        } else {
            current.remove(phoneNumber)
        }
        blacklistedContacts = current
    }

    private fun generateAndStoreToken(): String {
        val newToken = (1..16)
            .map { "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".random() }
            .joinToString("")
        prefs.edit().putString(DONATION_TOKEN, newToken).apply()
        return newToken
    }
}
