using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging;
using Ryujinx.Ui.Common.Configuration.System;
using Ryujinx.Ui.Common.Configuration.Ui;
using Ryujinx.Ui.Common.Helper;
using System;
using System.Collections.Generic;

namespace Ryujinx.Ui.Common.Configuration
{
    public class ConfigurationState
    {
        /// <summary>
        /// UI configuration section
        /// </summary>
        public class UiSection
        {
            public class Columns
            {
                public ReactiveObject<bool> FavColumn        { get; private set; }
                public ReactiveObject<bool> IconColumn       { get; private set; }
                public ReactiveObject<bool> AppColumn        { get; private set; }
                public ReactiveObject<bool> DevColumn        { get; private set; }
                public ReactiveObject<bool> VersionColumn    { get; private set; }
                public ReactiveObject<bool> TimePlayedColumn { get; private set; }
                public ReactiveObject<bool> LastPlayedColumn { get; private set; }
                public ReactiveObject<bool> FileExtColumn    { get; private set; }
                public ReactiveObject<bool> FileSizeColumn   { get; private set; }
                public ReactiveObject<bool> PathColumn       { get; private set; }

                public Columns()
                {
                    FavColumn        = new ReactiveObject<bool>();
                    IconColumn       = new ReactiveObject<bool>();
                    AppColumn        = new ReactiveObject<bool>();
                    DevColumn        = new ReactiveObject<bool>();
                    VersionColumn    = new ReactiveObject<bool>();
                    TimePlayedColumn = new ReactiveObject<bool>();
                    LastPlayedColumn = new ReactiveObject<bool>();
                    FileExtColumn    = new ReactiveObject<bool>();
                    FileSizeColumn   = new ReactiveObject<bool>();
                    PathColumn       = new ReactiveObject<bool>();
                }
            }

            public class ColumnSortSettings
            {
                public ReactiveObject<int>  SortColumnId  { get; private set; }
                public ReactiveObject<bool> SortAscending { get; private set; }

                public ColumnSortSettings()
                {
                    SortColumnId  = new ReactiveObject<int>();
                    SortAscending = new ReactiveObject<bool>();
                }
            }

            /// <summary>
            /// Used to toggle columns in the GUI
            /// </summary>
            public Columns GuiColumns { get; private set; }

            /// <summary>
            /// Used to configure column sort settings in the GUI
            /// </summary>
            public ColumnSortSettings ColumnSort { get; private set; }

            /// <summary>
            /// A list of directories containing games to be used to load games into the games list
            /// </summary>
            public ReactiveObject<List<string>> GameDirs { get; private set; }

            /// <summary>
            /// Language Code for the UI
            /// </summary>
            public ReactiveObject<string> LanguageCode { get; private set; }

            /// <summary>
            /// Enable or disable custom themes in the GUI
            /// </summary>
            public ReactiveObject<bool> EnableCustomTheme { get; private set; }

            /// <summary>
            /// Path to custom GUI theme
            /// </summary>
            public ReactiveObject<string> CustomThemePath { get; private set; }

            /// <summary>
            /// Selects the base style
            /// </summary>
            public ReactiveObject<string> BaseStyle { get; private set; }

            /// <summary>
            /// Start games in fullscreen mode
            /// </summary>
            public ReactiveObject<bool> StartFullscreen { get; private set; }

            /// <summary>
            /// Hide / Show Console Window
            /// </summary>
            public ReactiveObject<bool> ShowConsole { get; private set; }

            /// <summary>
            /// View Mode of the Game list
            /// </summary>
            public ReactiveObject<int> GameListViewMode { get; private set; }

            /// <summary>
            /// Show application name in Grid Mode
            /// </summary>
            public ReactiveObject<bool> ShowNames { get; private set; }

            /// <summary>
            /// Sets App Icon Size in Grid Mode
            /// </summary>
            public ReactiveObject<int> GridSize { get; private set; }

            /// <summary>
            /// Sorts Apps in Grid Mode
            /// </summary>
            public ReactiveObject<int> ApplicationSort { get; private set; }

            /// <summary>
            /// Sets if Grid is ordered in Ascending Order
            /// </summary>
            public ReactiveObject<bool> IsAscendingOrder { get; private set; }

            public UiSection()
            {
                GuiColumns        = new Columns();
                ColumnSort        = new ColumnSortSettings();
                GameDirs          = new ReactiveObject<List<string>>();
                EnableCustomTheme = new ReactiveObject<bool>();
                CustomThemePath   = new ReactiveObject<string>();
                BaseStyle         = new ReactiveObject<string>();
                StartFullscreen   = new ReactiveObject<bool>();
                GameListViewMode  = new ReactiveObject<int>();
                ShowNames         = new ReactiveObject<bool>();
                GridSize          = new ReactiveObject<int>();
                ApplicationSort   = new ReactiveObject<int>();
                IsAscendingOrder  = new ReactiveObject<bool>();
                LanguageCode      = new ReactiveObject<string>();
                ShowConsole       = new ReactiveObject<bool>();
                ShowConsole.Event += static (s, e) => { ConsoleHelper.SetConsoleWindowState(e.NewValue); };
            }
        }

        /// <summary>
        /// Logger configuration section
        /// </summary>
        public class LoggerSection
        {
            /// <summary>
            /// Enables printing debug log messages
            /// </summary>
            public ReactiveObject<bool> EnableDebug { get; private set; }

            /// <summary>
            /// Enables printing stub log messages
            /// </summary>
            public ReactiveObject<bool> EnableStub { get; private set; }

            /// <summary>
            /// Enables printing info log messages
            /// </summary>
            public ReactiveObject<bool> EnableInfo { get; private set; }

            /// <summary>
            /// Enables printing warning log messages
            /// </summary>
            public ReactiveObject<bool> EnableWarn { get; private set; }

            /// <summary>
            /// Enables printing error log messages
            /// </summary>
            public ReactiveObject<bool> EnableError { get; private set; }

            /// <summary>
            /// Enables printing trace log messages
            /// </summary>
            public ReactiveObject<bool> EnableTrace { get; private set; }

            /// <summary>
            /// Enables printing guest log messages
            /// </summary>
            public ReactiveObject<bool> EnableGuest { get; private set; }

            /// <summary>
            /// Enables printing FS access log messages
            /// </summary>
            public ReactiveObject<bool> EnableFsAccessLog { get; private set; }

            /// <summary>
            /// Controls which log messages are written to the log targets
            /// </summary>
            public ReactiveObject<LogClass[]> FilteredClasses { get; private set; }

            /// <summary>
            /// Enables or disables logging to a file on disk
            /// </summary>
            public ReactiveObject<bool> EnableFileLog { get; private set; }

            /// <summary>
            /// Controls which OpenGL log messages are recorded in the log
            /// </summary>
            public ReactiveObject<GraphicsDebugLevel> GraphicsDebugLevel { get; private set; }

            public LoggerSection()
            {
                EnableDebug         = new ReactiveObject<bool>();
                EnableStub          = new ReactiveObject<bool>();
                EnableInfo          = new ReactiveObject<bool>();
                EnableWarn          = new ReactiveObject<bool>();
                EnableError         = new ReactiveObject<bool>();
                EnableTrace         = new ReactiveObject<bool>();
                EnableGuest         = new ReactiveObject<bool>();
                EnableFsAccessLog   = new ReactiveObject<bool>();
                FilteredClasses     = new ReactiveObject<LogClass[]>();
                EnableFileLog       = new ReactiveObject<bool>();
                EnableFileLog.Event += static (sender, e) => LogValueChange(sender, e, nameof(EnableFileLog));
                GraphicsDebugLevel  = new ReactiveObject<GraphicsDebugLevel>();
            }
        }

        /// <summary>
        /// System configuration section
        /// </summary>
        public class SystemSection
        {
            /// <summary>
            /// Change System Language
            /// </summary>
            public ReactiveObject<Language> Language { get; private set; }

            /// <summary>
            /// Change System Region
            /// </summary>
            public ReactiveObject<Region> Region { get; private set; }

            /// <summary>
            /// Change System TimeZone
            /// </summary>
            public ReactiveObject<string> TimeZone { get; private set; }

            /// <summary>
            /// System Time Offset in Seconds
            /// </summary>
            public ReactiveObject<long> SystemTimeOffset { get; private set; }

            /// <summary>
            /// Enables or disables Docked Mode
            /// </summary>
            public ReactiveObject<bool> EnableDockedMode { get; private set; }

            /// <summary>
            /// Enables or disables profiled translation cache persistency
            /// </summary>
            public ReactiveObject<bool> EnablePtc { get; private set; }

            /// <summary>
            /// Enables or disables guest Internet access
            /// </summary>
            public ReactiveObject<bool> EnableInternetAccess { get; private set; }

            /// <summary>
            /// Enables integrity checks on Game content files
            /// </summary>
            public ReactiveObject<bool> EnableFsIntegrityChecks { get; private set; }

            /// <summary>
            /// Enables FS access log output to the console. Possible modes are 0-3
            /// </summary>
            public ReactiveObject<int> FsGlobalAccessLogMode { get; private set; }

            /// <summary>
            /// The selected audio backend
            /// </summary>
            public ReactiveObject<AudioBackend> AudioBackend { get; private set; }

            /// <summary>
            /// The audio backend volume
            /// </summary>
            public ReactiveObject<float> AudioVolume { get; private set; }

            /// <summary>
            /// The selected memory manager mode
            /// </summary>
            public ReactiveObject<MemoryManagerMode> MemoryManagerMode { get; private set; }

            /// <summary>
            /// Defines the amount of RAM available on the emulated system, and how it is distributed
            /// </summary>
            public ReactiveObject<bool> ExpandRam { get; private set; }

            /// <summary>
            /// Enable or disable ignoring missing services
            /// </summary>
            public ReactiveObject<bool> IgnoreMissingServices { get; private set; }

            /// <summary>
            /// Uses Hypervisor over JIT if available
            /// </summary>
            public ReactiveObject<bool> UseHypervisor { get; private set; }

            public SystemSection()
            {
                Language                      = new ReactiveObject<Language>();
                Region                        = new ReactiveObject<Region>();
                TimeZone                      = new ReactiveObject<string>();
                SystemTimeOffset              = new ReactiveObject<long>();
                EnableDockedMode              = new ReactiveObject<bool>();
                EnableDockedMode.Event        += static (sender, e) => LogValueChange(sender, e, nameof(EnableDockedMode));
                EnablePtc                     = new ReactiveObject<bool>();
                EnablePtc.Event               += static (sender, e) => LogValueChange(sender, e, nameof(EnablePtc));
                EnableInternetAccess          = new ReactiveObject<bool>();
                EnableInternetAccess.Event    += static (sender, e) => LogValueChange(sender, e, nameof(EnableInternetAccess));
                EnableFsIntegrityChecks       = new ReactiveObject<bool>();
                EnableFsIntegrityChecks.Event += static (sender, e) => LogValueChange(sender, e, nameof(EnableFsIntegrityChecks));
                FsGlobalAccessLogMode         = new ReactiveObject<int>();
                FsGlobalAccessLogMode.Event   += static (sender, e) => LogValueChange(sender, e, nameof(FsGlobalAccessLogMode));
                AudioBackend                  = new ReactiveObject<AudioBackend>();
                AudioBackend.Event            += static (sender, e) => LogValueChange(sender, e, nameof(AudioBackend));
                MemoryManagerMode             = new ReactiveObject<MemoryManagerMode>();
                MemoryManagerMode.Event       += static (sender, e) => LogValueChange(sender, e, nameof(MemoryManagerMode));
                ExpandRam                     = new ReactiveObject<bool>();
                ExpandRam.Event               += static (sender, e) => LogValueChange(sender, e, nameof(ExpandRam));
                IgnoreMissingServices         = new ReactiveObject<bool>();
                IgnoreMissingServices.Event   += static (sender, e) => LogValueChange(sender, e, nameof(IgnoreMissingServices));
                AudioVolume                   = new ReactiveObject<float>();
                AudioVolume.Event             += static (sender, e) => LogValueChange(sender, e, nameof(AudioVolume));
                UseHypervisor                 = new ReactiveObject<bool>();
                UseHypervisor.Event           += static (sender, e) => LogValueChange(sender, e, nameof(UseHypervisor));
            }
        }

        /// <summary>
        /// Hid configuration section
        /// </summary>
        public class HidSection
        {
            /// <summary>
            /// Enable or disable keyboard support (Independent from controllers binding)
            /// </summary>
            public ReactiveObject<bool> EnableKeyboard { get; private set; }

            /// <summary>
            /// Enable or disable mouse support (Independent from controllers binding)
            /// </summary>
            public ReactiveObject<bool> EnableMouse { get; private set; }

            /// <summary>
            /// Hotkey Keyboard Bindings
            /// </summary>
            public ReactiveObject<KeyboardHotkeys> Hotkeys { get; private set; }

            /// <summary>
            /// Input device configuration.
            /// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed.
            /// TODO: Implement a ReactiveList class.
            /// </summary>
            public ReactiveObject<List<InputConfig>> InputConfig { get; private set; }

            public HidSection()
            {
                EnableKeyboard = new ReactiveObject<bool>();
                EnableMouse    = new ReactiveObject<bool>();
                Hotkeys        = new ReactiveObject<KeyboardHotkeys>();
                InputConfig    = new ReactiveObject<List<InputConfig>>();
            }
        }

        /// <summary>
        /// Graphics configuration section
        /// </summary>
        public class GraphicsSection
        {
            /// <summary>
            /// Whether or not backend threading is enabled. The "Auto" setting will determine whether threading should be enabled at runtime.
            /// </summary>
            public ReactiveObject<BackendThreading> BackendThreading { get; private set; }

            /// <summary>
            /// Max Anisotropy. Values range from 0 - 16. Set to -1 to let the game decide.
            /// </summary>
            public ReactiveObject<float> MaxAnisotropy { get; private set; }

            /// <summary>
            /// Aspect Ratio applied to the renderer window.
            /// </summary>
            public ReactiveObject<AspectRatio> AspectRatio { get; private set; }

            /// <summary>
            /// Resolution Scale. An integer scale applied to applicable render targets. Values 1-4, or -1 to use a custom floating point scale instead.
            /// </summary>
            public ReactiveObject<int> ResScale { get; private set; }

            /// <summary>
            /// Custom Resolution Scale. A custom floating point scale applied to applicable render targets. Only active when Resolution Scale is -1.
            /// </summary>
            public ReactiveObject<float> ResScaleCustom { get; private set; }

            /// <summary>
            /// Dumps shaders in this local directory
            /// </summary>
            public ReactiveObject<string> ShadersDumpPath { get; private set; }

            /// <summary>
            /// Enables or disables Vertical Sync
            /// </summary>
            public ReactiveObject<bool> EnableVsync { get; private set; }

            /// <summary>
            /// Enables or disables Shader cache
            /// </summary>
            public ReactiveObject<bool> EnableShaderCache { get; private set; }

            /// <summary>
            /// Enables or disables texture recompression
            /// </summary>
            public ReactiveObject<bool> EnableTextureRecompression { get; private set; }

            /// <summary>
            /// Enables or disables Macro high-level emulation
            /// </summary>
            public ReactiveObject<bool> EnableMacroHLE { get; private set; }

            /// <summary>
            /// Graphics backend
            /// </summary>
            public ReactiveObject<GraphicsBackend> GraphicsBackend { get; private set; }

            /// <summary>
            /// Preferred GPU
            /// </summary>
            public ReactiveObject<string> PreferredGpu { get; private set; }

            public GraphicsSection()
            {
                BackendThreading                 = new ReactiveObject<BackendThreading>();
                BackendThreading.Event           += static (sender, e) => LogValueChange(sender, e, nameof(BackendThreading));
                ResScale                         = new ReactiveObject<int>();
                ResScale.Event                   += static (sender, e) => LogValueChange(sender, e, nameof(ResScale));
                ResScaleCustom                   = new ReactiveObject<float>();
                ResScaleCustom.Event             += static (sender, e) => LogValueChange(sender, e, nameof(ResScaleCustom));
                MaxAnisotropy                    = new ReactiveObject<float>();
                MaxAnisotropy.Event              += static (sender, e) => LogValueChange(sender, e, nameof(MaxAnisotropy));
                AspectRatio                      = new ReactiveObject<AspectRatio>();
                AspectRatio.Event                += static (sender, e) => LogValueChange(sender, e, nameof(AspectRatio));
                ShadersDumpPath                  = new ReactiveObject<string>();
                EnableVsync                      = new ReactiveObject<bool>();
                EnableVsync.Event                += static (sender, e) => LogValueChange(sender, e, nameof(EnableVsync));
                EnableShaderCache                = new ReactiveObject<bool>();
                EnableShaderCache.Event          += static (sender, e) => LogValueChange(sender, e, nameof(EnableShaderCache));
                EnableTextureRecompression       = new ReactiveObject<bool>();
                EnableTextureRecompression.Event += static (sender, e) => LogValueChange(sender, e, nameof(EnableTextureRecompression));
                GraphicsBackend                  = new ReactiveObject<GraphicsBackend>();
                GraphicsBackend.Event            += static (sender, e) => LogValueChange(sender, e, nameof(GraphicsBackend));
                PreferredGpu                     = new ReactiveObject<string>();
                PreferredGpu.Event               += static (sender, e) => LogValueChange(sender, e, nameof(PreferredGpu));
                EnableMacroHLE                   = new ReactiveObject<bool>();
                EnableMacroHLE.Event             += static (sender, e) => LogValueChange(sender, e, nameof(EnableMacroHLE));
            }
        }

        /// <summary>
        /// The default configuration instance
        /// </summary>
        public static ConfigurationState Instance { get; private set; }

        /// <summary>
        /// The Ui section
        /// </summary>
        public UiSection Ui { get; private set; }

        /// <summary>
        /// The Logger section
        /// </summary>
        public LoggerSection Logger { get; private set; }

        /// <summary>
        /// The System section
        /// </summary>
        public SystemSection System { get; private set; }

        /// <summary>
        /// The Graphics section
        /// </summary>
        public GraphicsSection Graphics { get; private set; }

        /// <summary>
        /// The Hid section
        /// </summary>
        public HidSection Hid { get; private set; }

        /// <summary>
        /// Enables or disables Discord Rich Presence
        /// </summary>
        public ReactiveObject<bool> EnableDiscordIntegration { get; private set; }

        /// <summary>
        /// Checks for updates when Ryujinx starts when enabled
        /// </summary>
        public ReactiveObject<bool> CheckUpdatesOnStart { get; private set; }

        /// <summary>
        /// Show "Confirm Exit" Dialog
        /// </summary>
        public ReactiveObject<bool> ShowConfirmExit { get; private set; }

        /// <summary>
        /// Hide Cursor on Idle
        /// </summary>
        public ReactiveObject<bool> HideCursorOnIdle { get; private set; }

        private ConfigurationState()
        {
            Ui                       = new UiSection();
            Logger                   = new LoggerSection();
            System                   = new SystemSection();
            Graphics                 = new GraphicsSection();
            Hid                      = new HidSection();
            EnableDiscordIntegration = new ReactiveObject<bool>();
            CheckUpdatesOnStart      = new ReactiveObject<bool>();
            ShowConfirmExit          = new ReactiveObject<bool>();
            HideCursorOnIdle         = new ReactiveObject<bool>();
        }

        public ConfigurationFileFormat ToFileFormat()
        {
            ConfigurationFileFormat configurationFile = new ConfigurationFileFormat
            {
                Version                    = ConfigurationFileFormat.CurrentVersion,
                BackendThreading           = Graphics.BackendThreading,
                EnableFileLog              = Logger.EnableFileLog,
                ResScale                   = Graphics.ResScale,
                ResScaleCustom             = Graphics.ResScaleCustom,
                MaxAnisotropy              = Graphics.MaxAnisotropy,
                AspectRatio                = Graphics.AspectRatio,
                GraphicsShadersDumpPath    = Graphics.ShadersDumpPath,
                LoggingEnableDebug         = Logger.EnableDebug,
                LoggingEnableStub          = Logger.EnableStub,
                LoggingEnableInfo          = Logger.EnableInfo,
                LoggingEnableWarn          = Logger.EnableWarn,
                LoggingEnableError         = Logger.EnableError,
                LoggingEnableTrace         = Logger.EnableTrace,
                LoggingEnableGuest         = Logger.EnableGuest,
                LoggingEnableFsAccessLog   = Logger.EnableFsAccessLog,
                LoggingFilteredClasses     = Logger.FilteredClasses,
                LoggingGraphicsDebugLevel  = Logger.GraphicsDebugLevel,
                SystemLanguage             = System.Language,
                SystemRegion               = System.Region,
                SystemTimeZone             = System.TimeZone,
                SystemTimeOffset           = System.SystemTimeOffset,
                DockedMode                 = System.EnableDockedMode,
                EnableDiscordIntegration   = EnableDiscordIntegration,
                CheckUpdatesOnStart        = CheckUpdatesOnStart,
                ShowConfirmExit            = ShowConfirmExit,
                HideCursorOnIdle           = HideCursorOnIdle,
                EnableVsync                = Graphics.EnableVsync,
                EnableShaderCache          = Graphics.EnableShaderCache,
                EnableTextureRecompression = Graphics.EnableTextureRecompression,
                EnableMacroHLE             = Graphics.EnableMacroHLE,
                EnablePtc                  = System.EnablePtc,
                EnableInternetAccess       = System.EnableInternetAccess,
                EnableFsIntegrityChecks    = System.EnableFsIntegrityChecks,
                FsGlobalAccessLogMode      = System.FsGlobalAccessLogMode,
                AudioBackend               = System.AudioBackend,
                AudioVolume                = System.AudioVolume,
                MemoryManagerMode          = System.MemoryManagerMode,
                ExpandRam                  = System.ExpandRam,
                IgnoreMissingServices      = System.IgnoreMissingServices,
                UseHypervisor              = System.UseHypervisor,
                GuiColumns                 = new GuiColumns
                {
                    FavColumn        = Ui.GuiColumns.FavColumn,
                    IconColumn       = Ui.GuiColumns.IconColumn,
                    AppColumn        = Ui.GuiColumns.AppColumn,
                    DevColumn        = Ui.GuiColumns.DevColumn,
                    VersionColumn    = Ui.GuiColumns.VersionColumn,
                    TimePlayedColumn = Ui.GuiColumns.TimePlayedColumn,
                    LastPlayedColumn = Ui.GuiColumns.LastPlayedColumn,
                    FileExtColumn    = Ui.GuiColumns.FileExtColumn,
                    FileSizeColumn   = Ui.GuiColumns.FileSizeColumn,
                    PathColumn       = Ui.GuiColumns.PathColumn
                },
                ColumnSort                 = new ColumnSort
                {
                    SortColumnId  = Ui.ColumnSort.SortColumnId,
                    SortAscending = Ui.ColumnSort.SortAscending
                },
                GameDirs                   = Ui.GameDirs,
                LanguageCode               = Ui.LanguageCode,
                EnableCustomTheme          = Ui.EnableCustomTheme,
                CustomThemePath            = Ui.CustomThemePath,
                BaseStyle                  = Ui.BaseStyle,
                GameListViewMode           = Ui.GameListViewMode,
                ShowNames                  = Ui.ShowNames,
                GridSize                   = Ui.GridSize,
                ApplicationSort            = Ui.ApplicationSort,
                IsAscendingOrder           = Ui.IsAscendingOrder,
                StartFullscreen            = Ui.StartFullscreen,
                ShowConsole                = Ui.ShowConsole,
                EnableKeyboard             = Hid.EnableKeyboard,
                EnableMouse                = Hid.EnableMouse,
                Hotkeys                    = Hid.Hotkeys,
                KeyboardConfig             = new List<object>(),
                ControllerConfig           = new List<object>(),
                InputConfig                = Hid.InputConfig,
                GraphicsBackend            = Graphics.GraphicsBackend,
                PreferredGpu               = Graphics.PreferredGpu
            };

            return configurationFile;
        }

        public void LoadDefault()
        {
            Logger.EnableFileLog.Value                = true;
            Graphics.BackendThreading.Value           = BackendThreading.Auto;
            Graphics.ResScale.Value                   = 1;
            Graphics.ResScaleCustom.Value             = 1.0f;
            Graphics.MaxAnisotropy.Value              = -1.0f;
            Graphics.AspectRatio.Value                = AspectRatio.Fixed16x9;
            Graphics.GraphicsBackend.Value            = OperatingSystem.IsMacOS() ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl;
            Graphics.PreferredGpu.Value               = "";
            Graphics.ShadersDumpPath.Value            = "";
            Logger.EnableDebug.Value                  = false;
            Logger.EnableStub.Value                   = true;
            Logger.EnableInfo.Value                   = true;
            Logger.EnableWarn.Value                   = true;
            Logger.EnableError.Value                  = true;
            Logger.EnableTrace.Value                  = false;
            Logger.EnableGuest.Value                  = true;
            Logger.EnableFsAccessLog.Value            = false;
            Logger.FilteredClasses.Value              = Array.Empty<LogClass>();
            Logger.GraphicsDebugLevel.Value           = GraphicsDebugLevel.None;
            System.Language.Value                     = Language.AmericanEnglish;
            System.Region.Value                       = Region.USA;
            System.TimeZone.Value                     = "UTC";
            System.SystemTimeOffset.Value             = 0;
            System.EnableDockedMode.Value             = true;
            EnableDiscordIntegration.Value            = true;
            CheckUpdatesOnStart.Value                 = true;
            ShowConfirmExit.Value                     = true;
            HideCursorOnIdle.Value                    = false;
            Graphics.EnableVsync.Value                = true;
            Graphics.EnableShaderCache.Value          = true;
            Graphics.EnableTextureRecompression.Value = false;
            Graphics.EnableMacroHLE.Value             = true;
            System.EnablePtc.Value                    = true;
            System.EnableInternetAccess.Value         = false;
            System.EnableFsIntegrityChecks.Value      = true;
            System.FsGlobalAccessLogMode.Value        = 0;
            System.AudioBackend.Value                 = AudioBackend.SDL2;
            System.AudioVolume.Value                  = 1;
            System.MemoryManagerMode.Value            = MemoryManagerMode.HostMappedUnsafe;
            System.ExpandRam.Value                    = false;
            System.IgnoreMissingServices.Value        = false;
            System.UseHypervisor.Value                = true;
            Ui.GuiColumns.FavColumn.Value             = true;
            Ui.GuiColumns.IconColumn.Value            = true;
            Ui.GuiColumns.AppColumn.Value             = true;
            Ui.GuiColumns.DevColumn.Value             = true;
            Ui.GuiColumns.VersionColumn.Value         = true;
            Ui.GuiColumns.TimePlayedColumn.Value      = true;
            Ui.GuiColumns.LastPlayedColumn.Value      = true;
            Ui.GuiColumns.FileExtColumn.Value         = true;
            Ui.GuiColumns.FileSizeColumn.Value        = true;
            Ui.GuiColumns.PathColumn.Value            = true;
            Ui.ColumnSort.SortColumnId.Value          = 0;
            Ui.ColumnSort.SortAscending.Value         = false;
            Ui.GameDirs.Value                         = new List<string>();
            Ui.EnableCustomTheme.Value                = false;
            Ui.LanguageCode.Value                     = "en_US";
            Ui.CustomThemePath.Value                  = "";
            Ui.BaseStyle.Value                        = "Dark";
            Ui.GameListViewMode.Value                 = 0;
            Ui.ShowNames.Value                        = true;
            Ui.GridSize.Value                         = 2;
            Ui.ApplicationSort.Value                  = 0;
            Ui.IsAscendingOrder.Value                 = true;
            Ui.StartFullscreen.Value                  = false;
            Ui.ShowConsole.Value                      = true;
            Hid.EnableKeyboard.Value                  = false;
            Hid.EnableMouse.Value                     = false;
            Hid.Hotkeys.Value = new KeyboardHotkeys
            {
                ToggleVsync = Key.F1,
                ToggleMute = Key.F2,
                Screenshot = Key.F8,
                ShowUi = Key.F4,
                Pause = Key.F5,
                ResScaleUp = Key.Unbound,
                ResScaleDown = Key.Unbound,
                VolumeUp = Key.Unbound,
                VolumeDown = Key.Unbound
            };
            Hid.InputConfig.Value = new List<InputConfig>
            {
                 new StandardKeyboardInputConfig
                 {
                        Version          = InputConfig.CurrentVersion,
                        Backend          = InputBackendType.WindowKeyboard,
                        Id               = "0",
                        PlayerIndex      = PlayerIndex.Player1,
                        ControllerType   = ControllerType.JoyconPair,
                        LeftJoycon       = new LeftJoyconCommonConfig<Key>
                        {
                            DpadUp       = Key.Up,
                            DpadDown     = Key.Down,
                            DpadLeft     = Key.Left,
                            DpadRight    = Key.Right,
                            ButtonMinus  = Key.Minus,
                            ButtonL      = Key.E,
                            ButtonZl     = Key.Q,
                            ButtonSl     = Key.Unbound,
                            ButtonSr     = Key.Unbound
                        },

                        LeftJoyconStick  = new JoyconConfigKeyboardStick<Key>
                        {
                            StickUp      = Key.W,
                            StickDown    = Key.S,
                            StickLeft    = Key.A,
                            StickRight   = Key.D,
                            StickButton  = Key.F,
                        },

                        RightJoycon      = new RightJoyconCommonConfig<Key>
                        {
                            ButtonA      = Key.Z,
                            ButtonB      = Key.X,
                            ButtonX      = Key.C,
                            ButtonY      = Key.V,
                            ButtonPlus   = Key.Plus,
                            ButtonR      = Key.U,
                            ButtonZr     = Key.O,
                            ButtonSl     = Key.Unbound,
                            ButtonSr     = Key.Unbound
                        },

                        RightJoyconStick = new JoyconConfigKeyboardStick<Key>
                        {
                            StickUp      = Key.I,
                            StickDown    = Key.K,
                            StickLeft    = Key.J,
                            StickRight   = Key.L,
                            StickButton  = Key.H,
                        }
                 }
            };
        }

        public ConfigurationLoadResult Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
        {
            bool configurationFileUpdated = false;

            if (configurationFileFormat.Version < 0 || configurationFileFormat.Version > ConfigurationFileFormat.CurrentVersion)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");

                LoadDefault();

                return ConfigurationLoadResult.NotLoaded;
            }

            ConfigurationLoadResult result = ConfigurationLoadResult.Success;

            if (configurationFileFormat.Version < 2)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");

                configurationFileFormat.SystemRegion = Region.USA;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 3)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 3.");

                configurationFileFormat.SystemTimeZone = "UTC";

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 4)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 4.");

                configurationFileFormat.MaxAnisotropy = -1;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 5)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 5.");

                configurationFileFormat.SystemTimeOffset = 0;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 8)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 8.");

                configurationFileFormat.EnablePtc = true;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 9)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 9.");

                configurationFileFormat.ColumnSort = new ColumnSort
                {
                    SortColumnId  = 0,
                    SortAscending = false
                };

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = Key.F1
                };

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 10)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 10.");

                configurationFileFormat.AudioBackend = AudioBackend.OpenAl;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 11)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 11.");

                configurationFileFormat.ResScale = 1;
                configurationFileFormat.ResScaleCustom = 1.0f;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 12)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 12.");

                configurationFileFormat.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 14)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 14.");

                configurationFileFormat.CheckUpdatesOnStart = true;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 16)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 16.");

                configurationFileFormat.EnableShaderCache = true;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 17)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17.");

                configurationFileFormat.StartFullscreen = false;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 18)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 18.");

                configurationFileFormat.AspectRatio = AspectRatio.Fixed16x9;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 20)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 20.");

                configurationFileFormat.ShowConfirmExit = true;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 22)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22.");

                configurationFileFormat.HideCursorOnIdle = false;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 24)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 24.");

                configurationFileFormat.InputConfig = new List<InputConfig>
                {
                     new StandardKeyboardInputConfig
                     {
                            Version          = InputConfig.CurrentVersion,
                            Backend          = InputBackendType.WindowKeyboard,
                            Id               = "0",
                            PlayerIndex      = PlayerIndex.Player1,
                            ControllerType   = ControllerType.JoyconPair,
                            LeftJoycon       = new LeftJoyconCommonConfig<Key>
                            {
                                DpadUp       = Key.Up,
                                DpadDown     = Key.Down,
                                DpadLeft     = Key.Left,
                                DpadRight    = Key.Right,
                                ButtonMinus  = Key.Minus,
                                ButtonL      = Key.E,
                                ButtonZl     = Key.Q,
                                ButtonSl     = Key.Unbound,
                                ButtonSr     = Key.Unbound
                            },

                            LeftJoyconStick  = new JoyconConfigKeyboardStick<Key>
                            {
                                StickUp      = Key.W,
                                StickDown    = Key.S,
                                StickLeft    = Key.A,
                                StickRight   = Key.D,
                                StickButton  = Key.F,
                            },

                            RightJoycon      = new RightJoyconCommonConfig<Key>
                            {
                                ButtonA      = Key.Z,
                                ButtonB      = Key.X,
                                ButtonX      = Key.C,
                                ButtonY      = Key.V,
                                ButtonPlus   = Key.Plus,
                                ButtonR      = Key.U,
                                ButtonZr     = Key.O,
                                ButtonSl     = Key.Unbound,
                                ButtonSr     = Key.Unbound
                            },

                            RightJoyconStick = new JoyconConfigKeyboardStick<Key>
                            {
                                StickUp      = Key.I,
                                StickDown    = Key.K,
                                StickLeft    = Key.J,
                                StickRight   = Key.L,
                                StickButton  = Key.H,
                            }
                     }
                };

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 25)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 25.");

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 26)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 26.");

                configurationFileFormat.MemoryManagerMode = MemoryManagerMode.HostMappedUnsafe;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 27)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 27.");

                configurationFileFormat.EnableMouse = false;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 28)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 28.");

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = Key.F1,
                    Screenshot = Key.F8
                };

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 29)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 29.");

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = Key.F1,
                    Screenshot = Key.F8,
                    ShowUi = Key.F4
                };

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 30)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 30.");

                foreach(InputConfig config in configurationFileFormat.InputConfig)
                {
                    if (config is StandardControllerInputConfig controllerConfig)
                    {
                        controllerConfig.Rumble = new RumbleConfigController
                        {
                            EnableRumble = false,
                            StrongRumble = 1f,
                            WeakRumble = 1f
                        };
                    }
                }

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 31)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 31.");

                configurationFileFormat.BackendThreading = BackendThreading.Auto;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 32)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 32.");

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
                    Screenshot = configurationFileFormat.Hotkeys.Screenshot,
                    ShowUi = configurationFileFormat.Hotkeys.ShowUi,
                    Pause = Key.F5
                };

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 33)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 33.");

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
                    Screenshot = configurationFileFormat.Hotkeys.Screenshot,
                    ShowUi = configurationFileFormat.Hotkeys.ShowUi,
                    Pause = configurationFileFormat.Hotkeys.Pause,
                    ToggleMute = Key.F2
                };

                configurationFileFormat.AudioVolume = 1;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 34)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 34.");

                configurationFileFormat.EnableInternetAccess = false;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 35)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 35.");

                foreach (InputConfig config in configurationFileFormat.InputConfig)
                {
                    if (config is StandardControllerInputConfig controllerConfig)
                    {
                        controllerConfig.RangeLeft  = 1.0f;
                        controllerConfig.RangeRight = 1.0f;
                    }
                }

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 36)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 36.");

                configurationFileFormat.LoggingEnableTrace = false;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 37)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 37.");

                configurationFileFormat.ShowConsole = true;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 38)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 38.");

                configurationFileFormat.BaseStyle        = "Dark";
                configurationFileFormat.GameListViewMode = 0;
                configurationFileFormat.ShowNames        = true;
                configurationFileFormat.GridSize         = 2;
                configurationFileFormat.LanguageCode     = "en_US";

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 39)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 39.");

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
                    Screenshot = configurationFileFormat.Hotkeys.Screenshot,
                    ShowUi = configurationFileFormat.Hotkeys.ShowUi,
                    Pause = configurationFileFormat.Hotkeys.Pause,
                    ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
                    ResScaleUp = Key.Unbound,
                    ResScaleDown = Key.Unbound
                };

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 40)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 40.");

                configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;

                result |= ConfigurationLoadResult.MigratedFromPreVulkan;

                configurationFileUpdated = true;
            }

            if (configurationFileFormat.Version < 41)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");

                configurationFileFormat.Hotkeys = new KeyboardHotkeys
                {
                    ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
                    Screenshot = configurationFileFormat.Hotkeys.Screenshot,
                    ShowUi = configurationFileFormat.Hotkeys.ShowUi,
                    Pause = configurationFileFormat.Hotkeys.Pause,
                    ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
                    ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
                    ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
                    VolumeUp = Key.Unbound,
                    VolumeDown = Key.Unbound
                };
            }

            if (configurationFileFormat.Version < 42)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 42.");

                configurationFileFormat.EnableMacroHLE = true;
            }

            if (configurationFileFormat.Version < 43)
            {
                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 43.");

                configurationFileFormat.UseHypervisor = true;
            }

            Logger.EnableFileLog.Value                = configurationFileFormat.EnableFileLog;
            Graphics.ResScale.Value                   = configurationFileFormat.ResScale;
            Graphics.ResScaleCustom.Value             = configurationFileFormat.ResScaleCustom;
            Graphics.MaxAnisotropy.Value              = configurationFileFormat.MaxAnisotropy;
            Graphics.AspectRatio.Value                = configurationFileFormat.AspectRatio;
            Graphics.ShadersDumpPath.Value            = configurationFileFormat.GraphicsShadersDumpPath;
            Graphics.BackendThreading.Value           = configurationFileFormat.BackendThreading;
            Graphics.GraphicsBackend.Value            = configurationFileFormat.GraphicsBackend;
            Graphics.PreferredGpu.Value               = configurationFileFormat.PreferredGpu;
            Logger.EnableDebug.Value                  = configurationFileFormat.LoggingEnableDebug;
            Logger.EnableStub.Value                   = configurationFileFormat.LoggingEnableStub;
            Logger.EnableInfo.Value                   = configurationFileFormat.LoggingEnableInfo;
            Logger.EnableWarn.Value                   = configurationFileFormat.LoggingEnableWarn;
            Logger.EnableError.Value                  = configurationFileFormat.LoggingEnableError;
            Logger.EnableTrace.Value                  = configurationFileFormat.LoggingEnableTrace;
            Logger.EnableGuest.Value                  = configurationFileFormat.LoggingEnableGuest;
            Logger.EnableFsAccessLog.Value            = configurationFileFormat.LoggingEnableFsAccessLog;
            Logger.FilteredClasses.Value              = configurationFileFormat.LoggingFilteredClasses;
            Logger.GraphicsDebugLevel.Value           = configurationFileFormat.LoggingGraphicsDebugLevel;
            System.Language.Value                     = configurationFileFormat.SystemLanguage;
            System.Region.Value                       = configurationFileFormat.SystemRegion;
            System.TimeZone.Value                     = configurationFileFormat.SystemTimeZone;
            System.SystemTimeOffset.Value             = configurationFileFormat.SystemTimeOffset;
            System.EnableDockedMode.Value             = configurationFileFormat.DockedMode;
            EnableDiscordIntegration.Value            = configurationFileFormat.EnableDiscordIntegration;
            CheckUpdatesOnStart.Value                 = configurationFileFormat.CheckUpdatesOnStart;
            ShowConfirmExit.Value                     = configurationFileFormat.ShowConfirmExit;
            HideCursorOnIdle.Value                    = configurationFileFormat.HideCursorOnIdle;
            Graphics.EnableVsync.Value                = configurationFileFormat.EnableVsync;
            Graphics.EnableShaderCache.Value          = configurationFileFormat.EnableShaderCache;
            Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
            Graphics.EnableMacroHLE.Value             = configurationFileFormat.EnableMacroHLE;
            System.EnablePtc.Value                    = configurationFileFormat.EnablePtc;
            System.EnableInternetAccess.Value         = configurationFileFormat.EnableInternetAccess;
            System.EnableFsIntegrityChecks.Value      = configurationFileFormat.EnableFsIntegrityChecks;
            System.FsGlobalAccessLogMode.Value        = configurationFileFormat.FsGlobalAccessLogMode;
            System.AudioBackend.Value                 = configurationFileFormat.AudioBackend;
            System.AudioVolume.Value                  = configurationFileFormat.AudioVolume;
            System.MemoryManagerMode.Value            = configurationFileFormat.MemoryManagerMode;
            System.ExpandRam.Value                    = configurationFileFormat.ExpandRam;
            System.IgnoreMissingServices.Value        = configurationFileFormat.IgnoreMissingServices;
            System.UseHypervisor.Value                = configurationFileFormat.UseHypervisor;
            Ui.GuiColumns.FavColumn.Value             = configurationFileFormat.GuiColumns.FavColumn;
            Ui.GuiColumns.IconColumn.Value            = configurationFileFormat.GuiColumns.IconColumn;
            Ui.GuiColumns.AppColumn.Value             = configurationFileFormat.GuiColumns.AppColumn;
            Ui.GuiColumns.DevColumn.Value             = configurationFileFormat.GuiColumns.DevColumn;
            Ui.GuiColumns.VersionColumn.Value         = configurationFileFormat.GuiColumns.VersionColumn;
            Ui.GuiColumns.TimePlayedColumn.Value      = configurationFileFormat.GuiColumns.TimePlayedColumn;
            Ui.GuiColumns.LastPlayedColumn.Value      = configurationFileFormat.GuiColumns.LastPlayedColumn;
            Ui.GuiColumns.FileExtColumn.Value         = configurationFileFormat.GuiColumns.FileExtColumn;
            Ui.GuiColumns.FileSizeColumn.Value        = configurationFileFormat.GuiColumns.FileSizeColumn;
            Ui.GuiColumns.PathColumn.Value            = configurationFileFormat.GuiColumns.PathColumn;
            Ui.ColumnSort.SortColumnId.Value          = configurationFileFormat.ColumnSort.SortColumnId;
            Ui.ColumnSort.SortAscending.Value         = configurationFileFormat.ColumnSort.SortAscending;
            Ui.GameDirs.Value                         = configurationFileFormat.GameDirs;
            Ui.EnableCustomTheme.Value                = configurationFileFormat.EnableCustomTheme;
            Ui.LanguageCode.Value                     = configurationFileFormat.LanguageCode;
            Ui.CustomThemePath.Value                  = configurationFileFormat.CustomThemePath;
            Ui.BaseStyle.Value                        = configurationFileFormat.BaseStyle;
            Ui.GameListViewMode.Value                 = configurationFileFormat.GameListViewMode;
            Ui.ShowNames.Value                        = configurationFileFormat.ShowNames;
            Ui.IsAscendingOrder.Value                 = configurationFileFormat.IsAscendingOrder;
            Ui.GridSize.Value                         = configurationFileFormat.GridSize;
            Ui.ApplicationSort.Value                  = configurationFileFormat.ApplicationSort;
            Ui.StartFullscreen.Value                  = configurationFileFormat.StartFullscreen;
            Ui.ShowConsole.Value                      = configurationFileFormat.ShowConsole;
            Hid.EnableKeyboard.Value                  = configurationFileFormat.EnableKeyboard;
            Hid.EnableMouse.Value                     = configurationFileFormat.EnableMouse;
            Hid.Hotkeys.Value                         = configurationFileFormat.Hotkeys;
            Hid.InputConfig.Value                     = configurationFileFormat.InputConfig;

            if (Hid.InputConfig.Value == null)
            {
                Hid.InputConfig.Value = new List<InputConfig>();
            }

            if (configurationFileUpdated)
            {
                ToFileFormat().SaveConfig(configurationFilePath);

                Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
            }

            return result;
        }

        private static void LogValueChange<T>(object sender, ReactiveEventArgs<T> eventArgs, string valueName)
        {
            Ryujinx.Common.Logging.Logger.Info?.Print(LogClass.Configuration, $"{valueName} set to: {eventArgs.NewValue}");
        }

        public static void Initialize()
        {
            if (Instance != null)
            {
                throw new InvalidOperationException("Configuration is already initialized");
            }

            Instance = new ConfigurationState();
        }
    }
}