/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.settings

import android.annotation.SuppressLint
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit
import androidx.preference.EditTextPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.utils.view.addToRadioGroup

/**
 * Lets the user customize the UI.
 */

@Suppress("LargeClass", "TooManyFunctions")
class CustomizationFragment : PreferenceFragmentCompat() {
    private lateinit var radioLightTheme: RadioButtonPreference
    private lateinit var radioDarkTheme: RadioButtonPreference
    private lateinit var radioAutoBatteryTheme: RadioButtonPreference
    private lateinit var radioFollowDeviceTheme: RadioButtonPreference

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.customization_preferences, rootKey)

        requirePreference<SwitchPreference>(R.string.pref_key_strip_url).apply {
            isChecked = context.settings().shouldStripUrl

            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
    }

    override fun onResume() {
        super.onResume()
        showToolbar(getString(R.string.preferences_customize))
        setupPreferences()
    }

    private fun setupPreferences() {
        bindFollowDeviceTheme()
        bindDarkTheme()
        bindLightTheme()
        bindAutoBatteryTheme()
        setupRadioGroups()
        setupToolbarCategory()
        setupTabsTrayCategory()
        setupFabCategory()
        setupHomeCategory()
        setupGesturesCategory()
        setupAddonsCustomizationCategory()
        setupSystemBehaviorCategory()
    }

    private fun setupRadioGroups() {
        addToRadioGroup(
            radioLightTheme,
            radioDarkTheme,
            if (SDK_INT >= Build.VERSION_CODES.P) {
                radioFollowDeviceTheme
            } else {
                radioAutoBatteryTheme
            }
        )
    }

    private fun bindLightTheme() {
        radioLightTheme = requirePreference(R.string.pref_key_light_theme)
        radioLightTheme.onClickListener {
            setNewTheme(AppCompatDelegate.MODE_NIGHT_NO)
        }
    }

    @SuppressLint("WrongConstant")
    // Suppressing erroneous lint warning about using MODE_NIGHT_AUTO_BATTERY, a likely library bug
    private fun bindAutoBatteryTheme() {
        radioAutoBatteryTheme = requirePreference(R.string.pref_key_auto_battery_theme)
        radioAutoBatteryTheme.onClickListener {
            setNewTheme(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
        }
    }

    private fun bindDarkTheme() {
        radioDarkTheme = requirePreference(R.string.pref_key_dark_theme)
        radioDarkTheme.onClickListener {
            requireContext().components.analytics.metrics.track(
                Event.DarkThemeSelected(
                    Event.DarkThemeSelected.Source.SETTINGS
                )
            )
            setNewTheme(AppCompatDelegate.MODE_NIGHT_YES)
        }
    }

    private fun bindFollowDeviceTheme() {
        radioFollowDeviceTheme = requirePreference(R.string.pref_key_follow_device_theme)
        if (SDK_INT >= Build.VERSION_CODES.P) {
            radioFollowDeviceTheme.onClickListener {
                setNewTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
            }
        }
    }

    private fun setNewTheme(mode: Int) {
        if (AppCompatDelegate.getDefaultNightMode() == mode) return
        AppCompatDelegate.setDefaultNightMode(mode)
        activity?.recreate()
        with(requireComponents.core) {
            engine.settings.preferredColorScheme = getPreferredColorScheme()
        }
        requireComponents.useCases.sessionUseCases.reload.invoke()
    }

    private fun setupToolbarCategory() {
        val topPreference = requirePreference<RadioButtonPreference>(R.string.pref_key_toolbar_top)
        topPreference.onClickListener {
            requireContext().components.analytics.metrics.track(Event.ToolbarPositionChanged(
                Event.ToolbarPositionChanged.Position.TOP
            ))
        }

        val bottomPreference = requirePreference<RadioButtonPreference>(R.string.pref_key_toolbar_bottom)
        bottomPreference.onClickListener {
            requireContext().components.analytics.metrics.track(Event.ToolbarPositionChanged(
                Event.ToolbarPositionChanged.Position.BOTTOM
            ))
        }

        val toolbarPosition = requireContext().settings().toolbarPosition
        topPreference.setCheckedWithoutClickListener(toolbarPosition == ToolbarPosition.TOP)
        bottomPreference.setCheckedWithoutClickListener(toolbarPosition == ToolbarPosition.BOTTOM)

        addToRadioGroup(topPreference, bottomPreference)
    }

    private fun setupTabsTrayCategory() {
        requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_top_tray).apply {
            isChecked = context.settings().useTopTabsTray
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }

        requirePreference<SwitchPreference>(R.string.pref_key_use_fullscreen_tabs_screen).apply {
            isChecked = context.settings().useFullScreenTabScreen
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }

        val reverseOrderPref = requirePreference<SwitchPreference>(
                R.string.pref_key_tabs_tray_reverse_tab_order).apply {
            if (context.settings().enableCompactTabs) {
                isChecked = false
                isEnabled = false
            } else {
                isChecked = context.settings().reverseTabOrderInTabsTray
                isEnabled = true
            }
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }

        requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_compact_tab).apply {
            isChecked = context.settings().enableCompactTabs

            onPreferenceChangeListener = Preference.OnPreferenceChangeListener { preference, newValue ->
                val newValueBoolean = newValue as Boolean
                preference.context.settings().preferences.edit {
                    putBoolean(preference.key, newValueBoolean)
                    if (newValueBoolean) {
                        reverseOrderPref.isChecked = false
                        putBoolean(getString(R.string.pref_key_tabs_tray_reverse_tab_order), false)
                    }
                    reverseOrderPref.isEnabled = !newValueBoolean
                }
                true
            }
        }
    }

    private fun setupFabCategory() {
        val fabPositionTop = requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_fab_top_position).apply {
            if (context.settings().useNewTabFloatingActionButton) {
                isChecked = context.settings().placeNewTabFloatingActionButtonAtTop
                isEnabled = true
            } else {
                isChecked = false
                isEnabled = false
            }
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }

        requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_use_fab).apply {
            isChecked = context.settings().useNewTabFloatingActionButton
            onPreferenceChangeListener = Preference.OnPreferenceChangeListener { preference, newValue ->
                val newValueBoolean = newValue as Boolean
                preference.context.settings().preferences.edit {
                    putBoolean(preference.key, newValueBoolean)
                    if (!newValueBoolean) {
                        fabPositionTop.isChecked = false
                        putBoolean(getString(R.string.pref_key_tabs_tray_fab_top_position), false)
                    }
                    fabPositionTop.isEnabled = newValueBoolean
                }
                true
            }
        }
    }

    private fun setupHomeCategory() {
        requirePreference<PreferenceCategory>(R.string.pref_home_category).apply {
            isVisible = FeatureFlags.topFrecentSite
        }

        requirePreference<SwitchPreference>(R.string.pref_key_enable_top_frecent_sites).apply {
            isVisible = FeatureFlags.topFrecentSite
            isChecked = context.settings().showTopFrecentSites
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
    }

    private fun setupGesturesCategory() {
        requirePreference<SwitchPreference>(R.string.pref_key_website_pull_to_refresh).apply {
            isVisible = FeatureFlags.pullToRefreshEnabled
            isChecked = context.settings().isPullToRefreshEnabledInBrowser
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
        requirePreference<SwitchPreference>(R.string.pref_key_dynamic_toolbar).apply {
            isChecked = context.settings().isDynamicToolbarEnabled
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
        requirePreference<SwitchPreference>(R.string.pref_key_swipe_toolbar_switch_tabs).apply {
            isChecked = context.settings().isSwipeToolbarToSwitchTabsEnabled
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
    }

    private fun setupAddonsCustomizationCategory() {
        requirePreference<EditTextPreference>(R.string.pref_key_addons_custom_account).apply {
            text = context.settings().customAddonsAccount
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }

        requirePreference<EditTextPreference>(R.string.pref_key_addons_custom_collection).apply {
            text = context.settings().customAddonsCollection
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
    }

    private fun setupSystemBehaviorCategory() {
        requirePreference<SwitchPreference>(R.string.pref_key_relinquish_memory_under_pressure).apply {
            isChecked = context.settings().shouldRelinquishMemoryUnderPressure
            onPreferenceChangeListener = SharedPreferenceUpdater()
        }
    }
}
