using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Input;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Versions;
using CUE4Parse_Conversion.Options;
using CUE4Parse_Conversion.Writers.UEFormat.Enums;
using CUE4Parse.UE4.Lua.unluac;
using FModel.Extensions.Themes;
using FModel.Framework;
using FModel.ViewModels;
using FModel.ViewModels.ApiEndpoints.Models;
using FModel.Views.Snooper;
using Newtonsoft.Json;

namespace FModel.Settings;

public sealed class UserSettings : ViewModel
{
    public static UserSettings Default { get; set; }
#if DEBUG
    public static readonly string FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FModel", "AppSettings_Debug.json");
#else
    public static readonly string FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FModel", "AppSettings.json");
#endif

    static UserSettings()
    {
        Default = new UserSettings();
    }

    private static bool _bSave = true;
    public static void Save()
    {
        if (!_bSave || Default == null) return;
        Default.PerDirectory[Default.CurrentDir.GameDirectory] = Default.CurrentDir;
        File.WriteAllText(FilePath, JsonConvert.SerializeObject(Default, Formatting.Indented));
    }

    public static void Delete()
    {
        if (File.Exists(FilePath))
        {
            _bSave = false;
            File.Delete(FilePath);
        }
    }

    public static bool IsEndpointValid(EEndpointType type, out EndpointSettings endpoint)
    {
        endpoint = Default.CurrentDir.Endpoints[(int) type];
        return endpoint.Overwrite || endpoint.IsValid;
    }

    public static ExportOptions GetExportOptions()
    {
        return new ExportOptions(
            Default.MeshExportFormat,
            Default.NaniteMeshExportFormat,
            Default.MeshQuality,
            Default.CurrentDir.TexturePlatform,
            Default.TextureExportFormat,
            Default.TextureQuality,
            Default.SaveHdrTexturesAsHdr,
            Default.MaterialExportFormat,
            Default.SaveEmbeddedMaterials,
            Default.SaveMorphTargets,
            Default.SocketExportFormat,
            Default.CompressionFormat,
            Default.ExportAllTextureMips
        );
    }

    private bool _showChangelog = true;
    public bool ShowChangelog
    {
        get => _showChangelog;
        set => SetProperty(ref _showChangelog, value);
    }

    private string _outputDirectory;
    public string OutputDirectory
    {
        get => _outputDirectory;
        set => SetProperty(ref _outputDirectory, value);
    }

    private string _rawDataDirectory;
    public string RawDataDirectory
    {
        get => _rawDataDirectory;
        set => SetProperty(ref _rawDataDirectory, value);
    }

    private string _propertiesDirectory;
    public string PropertiesDirectory
    {
        get => _propertiesDirectory;
        set => SetProperty(ref _propertiesDirectory, value);
    }

    private string _textureDirectory;
    public string TextureDirectory
    {
        get => _textureDirectory;
        set => SetProperty(ref _textureDirectory, value);
    }

    private string _audioDirectory;
    public string AudioDirectory
    {
        get => _audioDirectory;
        set => SetProperty(ref _audioDirectory, value);
    }

    private string _codeDirectory;
    public string CodeDirectory
    {
        get => _codeDirectory;
        set => SetProperty(ref _codeDirectory, value);
    }

    private string _modelDirectory;
    public string ModelDirectory
    {
        get => _modelDirectory;
        set => SetProperty(ref _modelDirectory, value);
    }

    private string _gameDirectory = string.Empty;
    public string GameDirectory
    {
        get => _gameDirectory;
        set => SetProperty(ref _gameDirectory, value);
    }

    private int _lastOpenedSettingTab;
    public int LastOpenedSettingTab
    {
        get => _lastOpenedSettingTab;
        set => SetProperty(ref _lastOpenedSettingTab, value);
    }

    private bool _isLoggerExpanded = true;
    public bool IsLoggerExpanded
    {
        get => _isLoggerExpanded;
        set => SetProperty(ref _isLoggerExpanded, value);
    }

    private GridLength _avalonImageSize = new (200);
    public GridLength AvalonImageSize
    {
        get => _avalonImageSize;
        set => SetProperty(ref _avalonImageSize, value);
    }

    private string _audioDeviceId;
    public string AudioDeviceId
    {
        get => _audioDeviceId;
        set => SetProperty(ref _audioDeviceId, value);
    }

    private float _audioPlayerVolume = 50.0F;
    public float AudioPlayerVolume
    {
        get => _audioPlayerVolume;
        set => SetProperty(ref _audioPlayerVolume, value);
    }

    private ELoadingMode _loadingMode = ELoadingMode.All;
    public ELoadingMode LoadingMode
    {
        get => _loadingMode;
        set => SetProperty(ref _loadingMode, value);
    }

    private DateTime _lastUpdateCheck = DateTime.MinValue;
    public DateTime LastUpdateCheck
    {
        get => _lastUpdateCheck;
        set => SetProperty(ref _lastUpdateCheck, value);
    }

    private DateTime _nextUpdateCheck = DateTime.Now;
    public DateTime NextUpdateCheck
    {
        get => _nextUpdateCheck;
        set => SetProperty(ref _nextUpdateCheck, value);
    }

    private bool _keepDirectoryStructure = true;
    public bool KeepDirectoryStructure
    {
        get => _keepDirectoryStructure;
        set => SetProperty(ref _keepDirectoryStructure, value);
    }

    private bool _showDecompileOption = false;
    public bool ShowDecompileOption
    {
        get => _showDecompileOption;
        set => SetProperty(ref _showDecompileOption, value);
    }

    private ECompressedAudio _compressedAudioMode = ECompressedAudio.PlayDecompressed;
    public ECompressedAudio CompressedAudioMode
    {
        get => _compressedAudioMode;
        set => SetProperty(ref _compressedAudioMode, value);
    }

    private EAesReload _aesReload = EAesReload.OncePerDay;
    public EAesReload AesReload
    {
        get => _aesReload;
        set => SetProperty(ref _aesReload, value);
    }

    private EDiscordRpc _discordRpc = EDiscordRpc.Always;
    public EDiscordRpc DiscordRpc
    {
        get => _discordRpc;
        set => SetProperty(ref _discordRpc, value);
    }

    private ELanguage _assetLanguage = ELanguage.English;
    public ELanguage AssetLanguage
    {
        get => _assetLanguage;
        set => SetProperty(ref _assetLanguage, value);
    }

    private EIconStyle _cosmeticStyle = EIconStyle.Default;
    public EIconStyle CosmeticStyle
    {
        get => _cosmeticStyle;
        set => SetProperty(ref _cosmeticStyle, value);
    }

    private bool _cosmeticDisplayAsset;
    public bool CosmeticDisplayAsset
    {
        get => _cosmeticDisplayAsset;
        set => SetProperty(ref _cosmeticDisplayAsset, value);
    }

    private int _imageMergerMargin = 5;
    public int ImageMergerMargin
    {
        get => _imageMergerMargin;
        set => SetProperty(ref _imageMergerMargin, value);
    }

    private bool _readScriptData;
    public bool ReadScriptData
    {
        get => _readScriptData;
        set => SetProperty(ref _readScriptData, value);
    }

    private bool _readShaderMaps;
    public bool ReadShaderMaps
    {
        get => _readShaderMaps;
        set => SetProperty(ref _readShaderMaps, value);
    }

    private bool _convertAudioOnBulkExport;
    public bool ConvertAudioOnBulkExport
    {
        get => _convertAudioOnBulkExport;
        set => SetProperty(ref _convertAudioOnBulkExport, value);
    }

    private bool _mergeEditorOnlyDataExports = false;
    public bool MergeEditorOnlyDataExports
    {
        get => _mergeEditorOnlyDataExports;
        set => SetProperty(ref _mergeEditorOnlyDataExports, value);
    }

    private bool _decompileLua;
    public bool DecompileLua
    {
        get => _decompileLua;
        set => SetProperty(ref _decompileLua, value);
    }

    [JsonIgnore]
    public EUnluacMode UnluacMode
    {
        get => UnluacFlags.HasFlag(EUnluacFlags.Disassemble) ? EUnluacMode.Disassemble : EUnluacMode.Decompile;
        set
        {
            var withoutMode = UnluacFlags & ~(EUnluacFlags.Decompile | EUnluacFlags.Disassemble);
            var modeFlag = value == EUnluacMode.Disassemble ? EUnluacFlags.Disassemble : EUnluacFlags.Decompile;
            UnluacFlags = withoutMode | modeFlag;
        }
    }

    private EUnluacFlags _unluacFlags = EUnluacFlags.Decompile;
    public EUnluacFlags UnluacFlags
    {
        get => _unluacFlags;
        set
        {
            if (!SetProperty(ref _unluacFlags, value)) return;
            RaisePropertyChanged(nameof(UnluacMode));
        }
    }

    private EJsonHighlightTheme _jsonHighlightTheme;
    public EJsonHighlightTheme JsonHighlightTheme
    {
        get => _jsonHighlightTheme;
        set => SetProperty(ref _jsonHighlightTheme, value);
    }

    private IDictionary<string, DirectorySettings> _perDirectory = new Dictionary<string, DirectorySettings>();
    public IDictionary<string, DirectorySettings> PerDirectory
    {
        get => _perDirectory;
        set => SetProperty(ref _perDirectory, value);
    }

    [JsonIgnore]
    public DirectorySettings CurrentDir { get; set; }

    /// <summary>
    /// TO DELETEEEEEEEEEEEEE
    /// </summary>
    private IDictionary<string, GameSelectorViewModel.DetectedGame> _manualGames = new Dictionary<string, GameSelectorViewModel.DetectedGame>();
    public IDictionary<string, GameSelectorViewModel.DetectedGame> ManualGames
    {
        get => _manualGames;
        set => SetProperty(ref _manualGames, value);
    }

    private AuthResponse _lastAuthResponse = new() {AccessToken = "", ExpiresAt = DateTime.Now};
    public AuthResponse LastAuthResponse
    {
        get => _lastAuthResponse;
        set => SetProperty(ref _lastAuthResponse, value);
    }

    private Hotkey _dirLeftTab = new(Key.A);
    public Hotkey DirLeftTab
    {
        get => _dirLeftTab;
        set => SetProperty(ref _dirLeftTab, value);
    }

    private Hotkey _dirRightTab = new(Key.D);
    public Hotkey DirRightTab
    {
        get => _dirRightTab;
        set => SetProperty(ref _dirRightTab, value);
    }

    private Hotkey _switchAssetExplorer = new(Key.Z);
    public Hotkey SwitchAssetExplorer
    {
        get => _switchAssetExplorer;
        set => SetProperty(ref _switchAssetExplorer, value);
    }

    private Hotkey _assetLeftTab = new(Key.Q);
    public Hotkey AssetLeftTab
    {
        get => _assetLeftTab;
        set => SetProperty(ref _assetLeftTab, value);
    }

    private Hotkey _assetRightTab = new(Key.E);
    public Hotkey AssetRightTab
    {
        get => _assetRightTab;
        set => SetProperty(ref _assetRightTab, value);
    }

    private Hotkey _assetAddTab = new(Key.T, ModifierKeys.Control);
    public Hotkey AssetAddTab
    {
        get => _assetAddTab;
        set => SetProperty(ref _assetAddTab, value);
    }

    private Hotkey _assetRemoveTab = new(Key.W, ModifierKeys.Control);
    public Hotkey AssetRemoveTab
    {
        get => _assetRemoveTab;
        set => SetProperty(ref _assetRemoveTab, value);
    }

    private Hotkey _addAudio = new(Key.N, ModifierKeys.Control);
    public Hotkey AddAudio
    {
        get => _addAudio;
        set => SetProperty(ref _addAudio, value);
    }

    private Hotkey _removeAudio = new(Key.X);
    public Hotkey RemoveAudio
    {
        get => _removeAudio;
        set => SetProperty(ref _removeAudio, value);
    }

    private Hotkey _playPauseAudio = new(Key.K);
    public Hotkey PlayPauseAudio
    {
        get => _playPauseAudio;
        set => SetProperty(ref _playPauseAudio, value);
    }

    private Hotkey _previousAudio = new(Key.J);
    public Hotkey PreviousAudio
    {
        get => _previousAudio;
        set => SetProperty(ref _previousAudio, value);
    }

    private Hotkey _nextAudio = new(Key.L);
    public Hotkey NextAudio
    {
        get => _nextAudio;
        set => SetProperty(ref _nextAudio, value);
    }

    private EMeshFormat _meshExportFormat = EMeshFormat.UEFormat;
    public EMeshFormat MeshExportFormat
    {
        get => _meshExportFormat;
        set => SetProperty(ref _meshExportFormat, value);
    }

    private ENaniteMeshFormat _naniteMeshExportFormat = ENaniteMeshFormat.NaniteOnly;
    public ENaniteMeshFormat NaniteMeshExportFormat
    {
        get => _naniteMeshExportFormat;
        set => SetProperty(ref _naniteMeshExportFormat, value);
    }

    private EMeshQuality _meshQuality = EMeshQuality.Highest;
    public EMeshQuality MeshQuality
    {
        get => _meshQuality;
        set => SetProperty(ref _meshQuality, value);
    }

    private EMaterialDepth _materialExportFormat = EMaterialDepth.TopLayerOnly;
    public EMaterialDepth MaterialExportFormat
    {
        get => _materialExportFormat;
        set => SetProperty(ref _materialExportFormat, value);
    }

    private ETextureFormat _textureExportFormat = ETextureFormat.Png;
    public ETextureFormat TextureExportFormat
    {
        get => _textureExportFormat;
        set => SetProperty(ref _textureExportFormat, value);
    }

    private int _textureQuality = 100;
    public int TextureQuality
    {
        get => _textureQuality;
        set => SetProperty(ref _textureQuality, value);
    }

    private ESocketFormat _socketExportFormat = ESocketFormat.Bone;
    public ESocketFormat SocketExportFormat
    {
        get => _socketExportFormat;
        set => SetProperty(ref _socketExportFormat, value);
    }

    private EFileCompressionFormat _compressionFormat = EFileCompressionFormat.ZSTD;
    public EFileCompressionFormat CompressionFormat
    {
        get => _compressionFormat;
        set => SetProperty(ref _compressionFormat, value);
    }

    private bool _showSkybox = true;
    public bool ShowSkybox
    {
        get => _showSkybox;
        set => SetProperty(ref _showSkybox, value);
    }

    private bool _showGrid = true;
    public bool ShowGrid
    {
        get => _showGrid;
        set => SetProperty(ref _showGrid, value);
    }

    private bool _animateWithRotationOnly;
    public bool AnimateWithRotationOnly
    {
        get => _animateWithRotationOnly;
        set => SetProperty(ref _animateWithRotationOnly, value);
    }

    private Camera.WorldMode _cameraMode = Camera.WorldMode.Arcball;
    public Camera.WorldMode CameraMode
    {
        get => _cameraMode;
        set => SetProperty(ref _cameraMode, value);
    }

    private int _previewMaxTextureSize = 1024;
    public int PreviewMaxTextureSize
    {
        get => _previewMaxTextureSize;
        set => SetProperty(ref _previewMaxTextureSize, value);
    }

    private bool _previewStaticMeshes = true;
    public bool PreviewStaticMeshes
    {
        get => _previewStaticMeshes;
        set => SetProperty(ref _previewStaticMeshes, value);
    }

    private bool _previewSkeletalMeshes = true;
    public bool PreviewSkeletalMeshes
    {
        get => _previewSkeletalMeshes;
        set => SetProperty(ref _previewSkeletalMeshes, value);
    }

    private bool _previewAnimations = true;
    public bool PreviewAnimations
    {
        get => _previewAnimations;
        set => SetProperty(ref _previewAnimations, value);
    }

    private bool _previewMaterials = true;
    public bool PreviewMaterials
    {
        get => _previewMaterials;
        set => SetProperty(ref _previewMaterials, value);
    }

    private bool _previewWorlds = true;
    public bool PreviewWorlds
    {
        get => _previewWorlds;
        set => SetProperty(ref _previewWorlds, value);
    }

    private bool _saveMorphTargets = true;
    public bool SaveMorphTargets
    {
        get => _saveMorphTargets;
        set => SetProperty(ref _saveMorphTargets, value);
    }

    private bool _saveEmbeddedMaterials = true;
    public bool SaveEmbeddedMaterials
    {
        get => _saveEmbeddedMaterials;
        set => SetProperty(ref _saveEmbeddedMaterials, value);
    }

    private bool _saveSkeletonAsMesh;
    public bool SaveSkeletonAsMesh
    {
        get => _saveSkeletonAsMesh;
        set => SetProperty(ref _saveSkeletonAsMesh, value);
    }

    private bool _saveHdrTexturesAsHdr = true;
    public bool SaveHdrTexturesAsHdr
    {
        get => _saveHdrTexturesAsHdr;
        set => SetProperty(ref _saveHdrTexturesAsHdr, value);
    }

    private bool _featurePreviewNewAssetExplorer = true;
    public bool FeaturePreviewNewAssetExplorer
    {
        get => _featurePreviewNewAssetExplorer;
        set => SetProperty(ref _featurePreviewNewAssetExplorer, value);
    }

    private bool _previewTexturesAssetExplorer = true;
    public bool PreviewTexturesAssetExplorer
    {
        get => _previewTexturesAssetExplorer;
        set => SetProperty(ref _previewTexturesAssetExplorer, value);
    }

    private EExplorerViewMode _explorerViewMode = EExplorerViewMode.Grid;

    public EExplorerViewMode ExplorerViewMode
    {
        get => _explorerViewMode;
        set => SetProperty(ref _explorerViewMode, value);
    }

    private bool _exportAllTextureMips = false;
    public bool ExportAllTextureMips
    {
        get => _exportAllTextureMips;
        set => SetProperty(ref _exportAllTextureMips, value);
    }

    private bool _exportImmediately;
    public bool ExportImmediately
    {
        get => _exportImmediately;
        set => SetProperty(ref _exportImmediately, value);
    }
}
