using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using System;
using System.IO;
using System.Reflection;
using VeloeMinecraftLauncher.MinecraftLauncher;
using Avalonia.Controls;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Serilog.Events;
using System.Linq;
using ReactiveUI.Validation.Components;

namespace VeloeMinecraftLauncher.ViewModels;

public class SettingsWindowViewModel : ViewModelBase
{
    public SettingsWindowViewModel()
    {
        LauncherVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();

        var _logger = Settings.logger;

        this.ValidationRule(
            viewModel => viewModel.MaxRam,
            value => { UInt32 result; bool resultb = UInt32.TryParse(value, out result); return resultb; },
            "Not a number.");

        var helper = this.ValidationRule(
            viewModel => viewModel.JavaPath,
            value => { string path = Path.Combine(value, "bin/java"); if (OperatingSystem.IsWindows()) path += ".exe"; bool resultb = File.Exists(path); return resultb; },
            "Can't find java executable.");

        this.ValidationRule(
            viewModel => viewModel.MaxLog,
            value => { UInt32 result; bool resultb = UInt32.TryParse(value, out result); return resultb; },
            "Not a number.");   
}

    private string _launcherVersion;
    private string _minecraftFolderPath = Settings.minecraftForlderPath;
    private string _javaPath = Settings.javaPath;
    private string _maxRam = Settings.maxRam.ToString();
    private bool _isValid;
    private LogEventLevel _fileLogEventLevel = Settings.fileLogEventLevel;
    private LogEventLevel _consoleLogEventLevel = Settings.consoleLogEventLevel;
    private string _maxLog = Settings.maxLog.ToString();
    
    private ObservableCollection<LogEventLevel> _logEventLevels = new() {LogEventLevel.Debug, LogEventLevel.Information, LogEventLevel.Warning, LogEventLevel.Error };

    public bool UseCustomJava
    {
        get => Settings.useCustomJava;
        set 
        {
            this.RaiseAndSetIfChanged(ref Settings.useCustomJava, value);
            this.RaisePropertyChanged(nameof(IsValid));
        }
    }

    public bool SetMaxRam
    {
        get => Settings.setMaxRam;
        set => this.RaiseAndSetIfChanged(ref Settings.setMaxRam, value);
    }

    public bool SetMinecraftFolder
    {
        get => Settings.setPath;
        set 
        { 
            this.RaiseAndSetIfChanged(ref Settings.setPath, value); 
            this.RaisePropertyChanged(nameof(IsValid)); 
        }
    }

    public bool CheckAssets
    {
        get => Settings.checkGameAssets;
        set => this.RaiseAndSetIfChanged(ref Settings.checkGameAssets, value);
    }

    public string JavaPath
    {
        get => _javaPath;
        set 
        { 
            this.RaiseAndSetIfChanged(ref _javaPath, value); 
            this.RaisePropertyChanged(nameof(IsValid)); 
        }
    }

    public string MaxRam
    {
        get => _maxRam;
        set 
        { 
            this.RaiseAndSetIfChanged(ref _maxRam, value); 
            this.RaisePropertyChanged(nameof(IsValid)); 
        }
    }

    public bool IsValid
    {
        get
        {
            _isValid = true;
            if (!UseCustomJava)
            {
                var rules = ValidationContext.Validations.Where(r => !(r as BasePropertyValidation<SettingsWindowViewModel>).Properties.Contains(nameof(JavaPath)));
                foreach (var rule in rules)
                    _isValid &= rule.IsValid;  
            }
            else
                 _isValid = ValidationContext.GetIsValid();
            return _isValid;
        }
    }

    public string MinecraftFolderPath
    {
        get => _minecraftFolderPath;
        set => this.RaiseAndSetIfChanged(ref _minecraftFolderPath, value);
    }

    public string LauncherVersion
    {
        get => _launcherVersion;
        set => this.RaiseAndSetIfChanged(ref _launcherVersion, value);
    }

    public bool GameLogToLauncher
    {
        get => Settings.gameLogToLauncher;
        set => this.RaiseAndSetIfChanged(ref Settings.gameLogToLauncher, value);
    }

    public ObservableCollection<LogEventLevel> LogEventLevels
    {
        get => _logEventLevels;
        set => this.RaiseAndSetIfChanged(ref _logEventLevels, value);
    }

    public LogEventLevel FileLogEventLevel
    {
        get =>_fileLogEventLevel;
        set => this.RaiseAndSetIfChanged(ref _fileLogEventLevel, value);
    }

    public LogEventLevel ConsoleLogEventLevel
    {
        get => _consoleLogEventLevel;
        set => this.RaiseAndSetIfChanged(ref _consoleLogEventLevel, value);
    }

    public bool SetMaxLog
    {
        get => Settings.setMaxLog;
        set => this.RaiseAndSetIfChanged(ref Settings.setMaxLog, value);
    }

    public string MaxLog
    {
        get => _maxLog;
        set => this.RaiseAndSetIfChanged(ref _maxLog, value);
    }

    public void SaveSettings()
    {
        Settings.javaPath = _javaPath;
        Settings.minecraftForlderPath = _minecraftFolderPath;
        Settings.maxRam = UInt32.Parse(_maxRam);
        Settings.maxLog = UInt32.Parse(_maxLog);
        Settings.consoleLogEventLevel = _consoleLogEventLevel;
        Settings.fileLogEventLevel = _fileLogEventLevel;
        Settings.SaveSettings();
    }

    public void OpenMinecraftPathDialog(Window window)
    {
        Task.Run(() =>
        {
            OpenFolderDialog dialog = new OpenFolderDialog();

            var initPath = String.Empty;

            if (Settings.minecraftForlderPath is not null)
                if (Settings.minecraftForlderPath != String.Empty)
                    initPath = Path.GetFullPath(Settings.minecraftForlderPath);

            dialog.Directory = initPath;

            var result = dialog.ShowAsync(window).Result;
            if (result is null)
                return;

            if (result == String.Empty)
                return;

            MinecraftFolderPath = result;
        });
    }

    public void OpenJavaPathDialog(Window window)
    {
        Task.Run(() =>
        {
            OpenFileDialog dialog = new OpenFileDialog();

            var initPath = String.Empty;

            if (Settings.javaPath is not null)
                if (Settings.javaPath != String.Empty)
                    initPath = Path.GetFullPath(Settings.javaPath);

            dialog.AllowMultiple = false;
            dialog.Directory = initPath;

            var result = dialog.ShowAsync(window).Result;
            if (result is null)
                return;

            if (result[0] == String.Empty)
                return;

            JavaPath = result[0];
        });
    }
}
