package com.seven.ikar.kotlin.core.push

import android.content.Context
import android.util.Base64
import java.util.UUID

class AndroidPushSettings(context: Context) {
    private val preferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)

    fun getInstallationId(): String {
        val existing = preferences.getString(KEY_INSTALLATION_ID, null)
        if (!existing.isNullOrBlank()) {
            return existing
        }

        val generated = UUID.randomUUID().toString().replace("-", "")
        preferences.edit().putString(KEY_INSTALLATION_ID, generated).apply()
        return generated
    }

    fun getDeviceToken(): String? = preferences.getString(KEY_DEVICE_TOKEN, null)

    fun setDeviceToken(token: String?) {
        preferences.edit().putString(KEY_DEVICE_TOKEN, token).apply()
    }

    fun areNotificationsEnabled(): Boolean =
        preferences.getBoolean(KEY_NOTIFICATIONS_ENABLED, true)

    fun setNotificationsEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_NOTIFICATIONS_ENABLED, enabled).apply()
    }

    fun getMessageSound(): NotificationSoundOption =
        getEnum(KEY_MESSAGE_SOUND, NotificationSoundOption.Default)

    fun setMessageSound(value: NotificationSoundOption) {
        setEnum(KEY_MESSAGE_SOUND, value)
    }

    fun getPrivateChatsEnabled(): Boolean =
        preferences.getBoolean(KEY_PRIVATE_CHATS_ENABLED, true)

    fun setPrivateChatsEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_PRIVATE_CHATS_ENABLED, enabled).apply()
    }

    fun getGroupsEnabled(): Boolean =
        preferences.getBoolean(KEY_GROUPS_ENABLED, true)

    fun setGroupsEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_GROUPS_ENABLED, enabled).apply()
    }

    fun getChannelsEnabled(): Boolean =
        preferences.getBoolean(KEY_CHANNELS_ENABLED, false)

    fun setChannelsEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_CHANNELS_ENABLED, enabled).apply()
    }

    fun getStoriesEnabled(): Boolean =
        preferences.getBoolean(KEY_STORIES_ENABLED, false)

    fun setStoriesEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_STORIES_ENABLED, enabled).apply()
    }

    fun getReactionsEnabled(): Boolean =
        preferences.getBoolean(KEY_REACTIONS_ENABLED, true)

    fun setReactionsEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_REACTIONS_ENABLED, enabled).apply()
    }

    fun getCallVibrationEnabled(): Boolean =
        preferences.getBoolean(KEY_CALL_VIBRATION_ENABLED, true)

    fun setCallVibrationEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_CALL_VIBRATION_ENABLED, enabled).apply()
    }

    fun getCallRingtone(): NotificationSoundOption =
        getEnum(KEY_CALL_RINGTONE, NotificationSoundOption.Default)

    fun setCallRingtone(value: NotificationSoundOption) {
        setEnum(KEY_CALL_RINGTONE, value)
    }

    fun getShowBadgeEnabled(): Boolean =
        preferences.getBoolean(KEY_SHOW_BADGE, true)

    fun setShowBadgeEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_SHOW_BADGE, enabled).apply()
    }

    fun getIncludeMutedChatsInBadge(): Boolean =
        preferences.getBoolean(KEY_INCLUDE_MUTED_CHATS_IN_BADGE, true)

    fun setIncludeMutedChatsInBadge(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_INCLUDE_MUTED_CHATS_IN_BADGE, enabled).apply()
    }

    fun getCountMessagesInBadge(): Boolean =
        preferences.getBoolean(KEY_COUNT_MESSAGES_IN_BADGE, true)

    fun setCountMessagesInBadge(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_COUNT_MESSAGES_IN_BADGE, enabled).apply()
    }

    fun getInAppSoundEnabled(): Boolean =
        preferences.getBoolean(KEY_IN_APP_SOUND_ENABLED, true)

    fun setInAppSoundEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_IN_APP_SOUND_ENABLED, enabled).apply()
    }

    fun getInAppVibrationEnabled(): Boolean =
        preferences.getBoolean(KEY_IN_APP_VIBRATION_ENABLED, true)

    fun setInAppVibrationEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_IN_APP_VIBRATION_ENABLED, enabled).apply()
    }

    fun getInAppShowTextEnabled(): Boolean =
        preferences.getBoolean(KEY_IN_APP_SHOW_TEXT_ENABLED, true)

    fun setInAppShowTextEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_IN_APP_SHOW_TEXT_ENABLED, enabled).apply()
    }

    fun getSoundInActiveChatEnabled(): Boolean =
        preferences.getBoolean(KEY_SOUND_IN_ACTIVE_CHAT_ENABLED, true)

    fun setSoundInActiveChatEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_SOUND_IN_ACTIVE_CHAT_ENABLED, enabled).apply()
    }

    fun getPopupWindowsEnabled(): Boolean =
        preferences.getBoolean(KEY_POPUP_WINDOWS_ENABLED, false)

    fun setPopupWindowsEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_POPUP_WINDOWS_ENABLED, enabled).apply()
    }

    fun getContactJoinedEnabled(): Boolean =
        preferences.getBoolean(KEY_CONTACT_JOINED_ENABLED, false)

    fun setContactJoinedEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_CONTACT_JOINED_ENABLED, enabled).apply()
    }

    fun getPinnedMessagesEnabled(): Boolean =
        preferences.getBoolean(KEY_PINNED_MESSAGES_ENABLED, true)

    fun setPinnedMessagesEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_PINNED_MESSAGES_ENABLED, enabled).apply()
    }

    fun getRestartOnCloseEnabled(): Boolean =
        preferences.getBoolean(KEY_RESTART_ON_CLOSE_ENABLED, false)

    fun setRestartOnCloseEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_RESTART_ON_CLOSE_ENABLED, enabled).apply()
    }

    fun getBackgroundConnectionEnabled(): Boolean =
        preferences.getBoolean(KEY_BACKGROUND_CONNECTION_ENABLED, false)

    fun setBackgroundConnectionEnabled(enabled: Boolean) {
        preferences.edit().putBoolean(KEY_BACKGROUND_CONNECTION_ENABLED, enabled).apply()
    }

    fun getRepeatInterval(): NotificationRepeatIntervalOption {
        val rawValue = preferences.getInt(KEY_REPEAT_INTERVAL, NotificationRepeatIntervalOption.OneHour.minutes)
        return NotificationRepeatIntervalOption.entries.firstOrNull { it.minutes == rawValue }
            ?: NotificationRepeatIntervalOption.OneHour
    }

    fun setRepeatInterval(value: NotificationRepeatIntervalOption) {
        preferences.edit().putInt(KEY_REPEAT_INTERVAL, value.minutes).apply()
    }

    fun loadSnapshot(): NotificationSettingsSnapshot =
        NotificationSettingsSnapshot(
            notificationsEnabled = areNotificationsEnabled(),
            messageSound = getMessageSound(),
            privateChatsEnabled = getPrivateChatsEnabled(),
            groupsEnabled = getGroupsEnabled(),
            channelsEnabled = getChannelsEnabled(),
            storiesEnabled = getStoriesEnabled(),
            reactionsEnabled = getReactionsEnabled(),
            callVibrationEnabled = getCallVibrationEnabled(),
            callRingtone = getCallRingtone(),
            showBadge = getShowBadgeEnabled(),
            includeMutedChatsInBadge = getIncludeMutedChatsInBadge(),
            countMessagesInBadge = getCountMessagesInBadge(),
            inAppSoundEnabled = getInAppSoundEnabled(),
            inAppVibrationEnabled = getInAppVibrationEnabled(),
            inAppShowTextEnabled = getInAppShowTextEnabled(),
            soundInActiveChatEnabled = getSoundInActiveChatEnabled(),
            popupWindowsEnabled = getPopupWindowsEnabled(),
            contactJoinedEnabled = getContactJoinedEnabled(),
            pinnedMessagesEnabled = getPinnedMessagesEnabled(),
            restartOnCloseEnabled = getRestartOnCloseEnabled(),
            backgroundConnectionEnabled = getBackgroundConnectionEnabled(),
            repeatInterval = getRepeatInterval()
        )

    fun saveSnapshot(snapshot: NotificationSettingsSnapshot) {
        setNotificationsEnabled(snapshot.notificationsEnabled)
        setMessageSound(snapshot.messageSound)
        setPrivateChatsEnabled(snapshot.privateChatsEnabled)
        setGroupsEnabled(snapshot.groupsEnabled)
        setChannelsEnabled(snapshot.channelsEnabled)
        setStoriesEnabled(snapshot.storiesEnabled)
        setReactionsEnabled(snapshot.reactionsEnabled)
        setCallVibrationEnabled(snapshot.callVibrationEnabled)
        setCallRingtone(snapshot.callRingtone)
        setShowBadgeEnabled(snapshot.showBadge)
        setIncludeMutedChatsInBadge(snapshot.includeMutedChatsInBadge)
        setCountMessagesInBadge(snapshot.countMessagesInBadge)
        setInAppSoundEnabled(snapshot.inAppSoundEnabled)
        setInAppVibrationEnabled(snapshot.inAppVibrationEnabled)
        setInAppShowTextEnabled(snapshot.inAppShowTextEnabled)
        setSoundInActiveChatEnabled(snapshot.soundInActiveChatEnabled)
        setPopupWindowsEnabled(snapshot.popupWindowsEnabled)
        setContactJoinedEnabled(snapshot.contactJoinedEnabled)
        setPinnedMessagesEnabled(snapshot.pinnedMessagesEnabled)
        setRestartOnCloseEnabled(snapshot.restartOnCloseEnabled)
        setBackgroundConnectionEnabled(snapshot.backgroundConnectionEnabled)
        setRepeatInterval(snapshot.repeatInterval)
    }

    fun loadChatNotificationSnapshot(chatId: String): ChatNotificationSettingsSnapshot =
        ChatNotificationSettingsSnapshot(
            notificationsEnabled = getNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_NOTIFICATIONS_ENABLED)),
            messageSound = getNullableEnum(
                chatPreferenceKey(chatId, KEY_CHAT_MESSAGE_SOUND),
                NotificationSoundOption.Default
            ),
            showMessagePreview = getNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_SHOW_MESSAGE_PREVIEW)),
            popupWindowsEnabled = getNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_POPUP_WINDOWS_ENABLED)),
            soundInActiveChatEnabled = getNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_SOUND_IN_ACTIVE_CHAT_ENABLED))
        )

    fun saveChatNotificationSnapshot(chatId: String, snapshot: ChatNotificationSettingsSnapshot) {
        preferences.edit().apply {
            putNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_NOTIFICATIONS_ENABLED), snapshot.notificationsEnabled)
            putNullableEnum(chatPreferenceKey(chatId, KEY_CHAT_MESSAGE_SOUND), snapshot.messageSound)
            putNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_SHOW_MESSAGE_PREVIEW), snapshot.showMessagePreview)
            putNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_POPUP_WINDOWS_ENABLED), snapshot.popupWindowsEnabled)
            putNullableBoolean(chatPreferenceKey(chatId, KEY_CHAT_SOUND_IN_ACTIVE_CHAT_ENABLED), snapshot.soundInActiveChatEnabled)
            apply()
        }
    }

    fun resetChatNotificationPreferences(chatId: String) {
        val prefix = chatPreferencePrefix(chatId)
        val keys = preferences.all.keys.filter { it.startsWith(prefix) }
        preferences.edit().apply {
            keys.forEach(::remove)
            apply()
        }
    }

    fun resetAllChatNotificationPreferences() {
        val keys = preferences.all.keys.filter { it.startsWith(KEY_CHAT_NOTIFICATION_PREFIX) }
        preferences.edit().apply {
            keys.forEach(::remove)
            apply()
        }
    }

    fun createDefaultSnapshot(): NotificationSettingsSnapshot =
        NotificationSettingsSnapshot(
            notificationsEnabled = true,
            messageSound = NotificationSoundOption.Default,
            privateChatsEnabled = true,
            groupsEnabled = true,
            channelsEnabled = false,
            storiesEnabled = false,
            reactionsEnabled = true,
            callVibrationEnabled = true,
            callRingtone = NotificationSoundOption.Default,
            showBadge = true,
            includeMutedChatsInBadge = true,
            countMessagesInBadge = true,
            inAppSoundEnabled = true,
            inAppVibrationEnabled = true,
            inAppShowTextEnabled = true,
            soundInActiveChatEnabled = true,
            popupWindowsEnabled = false,
            contactJoinedEnabled = false,
            pinnedMessagesEnabled = true,
            restartOnCloseEnabled = false,
            backgroundConnectionEnabled = false,
            repeatInterval = NotificationRepeatIntervalOption.OneHour
        )

    fun resetNotificationPreferences() {
        val chatKeys = preferences.all.keys.filter { it.startsWith(KEY_CHAT_NOTIFICATION_PREFIX) }
        preferences.edit().apply {
            remove(KEY_NOTIFICATIONS_ENABLED)
            remove(KEY_MESSAGE_SOUND)
            remove(KEY_PRIVATE_CHATS_ENABLED)
            remove(KEY_GROUPS_ENABLED)
            remove(KEY_CHANNELS_ENABLED)
            remove(KEY_STORIES_ENABLED)
            remove(KEY_REACTIONS_ENABLED)
            remove(KEY_CALL_VIBRATION_ENABLED)
            remove(KEY_CALL_RINGTONE)
            remove(KEY_SHOW_BADGE)
            remove(KEY_INCLUDE_MUTED_CHATS_IN_BADGE)
            remove(KEY_COUNT_MESSAGES_IN_BADGE)
            remove(KEY_IN_APP_SOUND_ENABLED)
            remove(KEY_IN_APP_VIBRATION_ENABLED)
            remove(KEY_IN_APP_SHOW_TEXT_ENABLED)
            remove(KEY_SOUND_IN_ACTIVE_CHAT_ENABLED)
            remove(KEY_POPUP_WINDOWS_ENABLED)
            remove(KEY_CONTACT_JOINED_ENABLED)
            remove(KEY_PINNED_MESSAGES_ENABLED)
            remove(KEY_RESTART_ON_CLOSE_ENABLED)
            remove(KEY_BACKGROUND_CONNECTION_ENABLED)
            remove(KEY_REPEAT_INTERVAL)
            chatKeys.forEach(::remove)
            apply()
        }
    }

    private fun <T : Enum<T>> getEnum(key: String, defaultValue: T): T {
        val rawValue = preferences.getString(key, defaultValue.name).orEmpty()
        @Suppress("UNCHECKED_CAST")
        return defaultValue.declaringJavaClass.enumConstants
            ?.firstOrNull { it.name == rawValue } as? T
            ?: defaultValue
    }

    private fun <T : Enum<T>> setEnum(key: String, value: T) {
        preferences.edit().putString(key, value.name).apply()
    }

    private fun getNullableBoolean(key: String): Boolean? =
        if (preferences.contains(key)) preferences.getBoolean(key, true) else null

    private fun android.content.SharedPreferences.Editor.putNullableBoolean(key: String, value: Boolean?) {
        if (value == null) {
            remove(key)
        } else {
            putBoolean(key, value)
        }
    }

    private fun <T : Enum<T>> getNullableEnum(key: String, defaultValue: T): T? {
        if (!preferences.contains(key)) {
            return null
        }
        return getEnum(key, defaultValue)
    }

    private fun <T : Enum<T>> android.content.SharedPreferences.Editor.putNullableEnum(key: String, value: T?) {
        if (value == null) {
            remove(key)
        } else {
            putString(key, value.name)
        }
    }

    private fun chatPreferenceKey(chatId: String, key: String): String =
        "${chatPreferencePrefix(chatId)}.$key"

    private fun chatPreferencePrefix(chatId: String): String {
        val encodedChatId = Base64.encodeToString(
            chatId.toByteArray(Charsets.UTF_8),
            Base64.NO_WRAP or Base64.URL_SAFE
        )
        return "$KEY_CHAT_NOTIFICATION_PREFIX$encodedChatId"
    }

    companion object {
        private const val PREFERENCES_NAME = "ikar_kotlin_push"
        private const val KEY_INSTALLATION_ID = "installation_id"
        private const val KEY_DEVICE_TOKEN = "device_token"
        private const val KEY_NOTIFICATIONS_ENABLED = "notifications_enabled"
        private const val KEY_MESSAGE_SOUND = "notification_sound"
        private const val KEY_PRIVATE_CHATS_ENABLED = "notification_private_chats_enabled"
        private const val KEY_GROUPS_ENABLED = "notification_groups_enabled"
        private const val KEY_CHANNELS_ENABLED = "notification_channels_enabled"
        private const val KEY_STORIES_ENABLED = "notification_stories_enabled"
        private const val KEY_REACTIONS_ENABLED = "notification_reactions_enabled"
        private const val KEY_CALL_VIBRATION_ENABLED = "notification_call_vibration_enabled"
        private const val KEY_CALL_RINGTONE = "notification_call_ringtone"
        private const val KEY_SHOW_BADGE = "notification_show_badge_enabled"
        private const val KEY_INCLUDE_MUTED_CHATS_IN_BADGE = "notification_include_muted_chats_in_badge"
        private const val KEY_COUNT_MESSAGES_IN_BADGE = "notification_count_messages_in_badge"
        private const val KEY_IN_APP_SOUND_ENABLED = "notification_in_app_sound_enabled"
        private const val KEY_IN_APP_VIBRATION_ENABLED = "notification_in_app_vibration_enabled"
        private const val KEY_IN_APP_SHOW_TEXT_ENABLED = "notification_in_app_show_text_enabled"
        private const val KEY_SOUND_IN_ACTIVE_CHAT_ENABLED = "notification_sound_in_active_chat_enabled"
        private const val KEY_POPUP_WINDOWS_ENABLED = "notification_popup_windows_enabled"
        private const val KEY_CONTACT_JOINED_ENABLED = "notification_contact_joined_enabled"
        private const val KEY_PINNED_MESSAGES_ENABLED = "notification_pinned_messages_enabled"
        private const val KEY_RESTART_ON_CLOSE_ENABLED = "notification_restart_on_close_enabled"
        private const val KEY_BACKGROUND_CONNECTION_ENABLED = "notification_background_connection_enabled"
        private const val KEY_REPEAT_INTERVAL = "notification_repeat_interval_minutes"
        private const val KEY_CHAT_NOTIFICATION_PREFIX = "chat_notification."
        private const val KEY_CHAT_NOTIFICATIONS_ENABLED = "notifications_enabled"
        private const val KEY_CHAT_MESSAGE_SOUND = "message_sound"
        private const val KEY_CHAT_SHOW_MESSAGE_PREVIEW = "show_message_preview"
        private const val KEY_CHAT_POPUP_WINDOWS_ENABLED = "popup_windows_enabled"
        private const val KEY_CHAT_SOUND_IN_ACTIVE_CHAT_ENABLED = "sound_in_active_chat_enabled"
    }
}
