using System.Reflection;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml;
using NixExampleWinUI.Contracts.Services;
using NixExampleWinUI.Helpers;
using NixExampleWinUI.Models;
using NixExampleWinUI.Views;
using NixUniversalSDK;
using Windows.ApplicationModel;

namespace NixExampleWinUI.ViewModels;

/// <summary>
/// View model for <see cref="SettingsPage"/>
/// </summary>
public class SettingsViewModel : ObservableRecipient
{
    private const string LogPrefix = nameof(SettingsViewModel) + "/";
    private readonly IThemeSelectorService _themeSelectorService;
    private ElementTheme _elementTheme;
    private string _versionDescription;

    /// <summary>
    /// DeviceModel singleton, used to hold instances of the `DeviceScanner` and connected `IDeviceCompat` instances
    /// </summary>
    private readonly DeviceModel _deviceModel;

    public ElementTheme ElementTheme
    {
        get => _elementTheme;
        set => SetProperty(ref _elementTheme, value);
    }

    public string VersionDescription
    {
        get => _versionDescription;
        set => SetProperty(ref _versionDescription, value);
    }

    public ICommand SwitchThemeCommand
    {
        get;
    }

    public SettingsViewModel(IThemeSelectorService themeSelectorService)
    {
        _themeSelectorService = themeSelectorService;
        _elementTheme = _themeSelectorService.Theme;
        _versionDescription = GetVersionDescription();
        _deviceModel = App.GetService<DeviceModel>();

        SwitchThemeCommand = new RelayCommand<ElementTheme>(
            async (param) =>
            {
                if (ElementTheme != param)
                {
                    ElementTheme = param;
                    await _themeSelectorService.SetThemeAsync(param);
                }
            });
    }

    private static string GetVersionDescription()
    {
        Version version;

        if (RuntimeHelper.IsMSIX)
        {
            var packageVersion = Package.Current.Id.Version;

            version = new(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision);
        }
        else
        {
            version = Assembly.GetExecutingAssembly().GetName().Version!;
        }

        return $"{"AppDisplayName".GetLocalized()} - {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
    }

    #region Nix device and events
    public IDeviceCompat? Device => _deviceModel.Device;
    public IEnumerable<SimpleInfoItem> DeviceInfoList => Device.GetDeviceInfoList();
    public bool IsDeviceInfoAvailable => Device?.State switch
    {
        DeviceState.Idle or 
        DeviceState.BusyRunningCommand or 
        DeviceState.BusyDataTransfer => true,
        _ => false
    };
    private void UpdateDeviceInfo()
    {
        OnPropertyChanged(nameof(IsDeviceInfoAvailable));
        OnPropertyChanged(nameof(DeviceInfoList));
    }
    public void AddDeviceEvents()
    {
        if (Device is not null)
        {
            Device.Connected += OnConnected;
            Device.Disconnected += OnDisconnected;
            Device.BatteryStateChanged += OnBatteryStateChanged;
            Device.ExtPowerStateChanged += OnExtPowerStateChanged;
        }
    }
    public void RemoveDeviceEvents()
    {
        if (Device is not null)
        {
            Device.Connected -= OnConnected;
            Device.Disconnected -= OnDisconnected;
            Device.BatteryStateChanged -= OnBatteryStateChanged;
            Device.ExtPowerStateChanged -= OnExtPowerStateChanged;
        }
    }

    private void OnConnected(object? sender, EventArgs args) => UpdateDeviceInfo();
    private void OnDisconnected(object? sender, DeviceStatusArgs args) => UpdateDeviceInfo();
    private void OnBatteryStateChanged(object? sender, BatteryStateEventArgs args) => UpdateDeviceInfo();
    private void OnExtPowerStateChanged(object? sender, ExtPowerStateEventArgs args) => UpdateDeviceInfo();
    #endregion

    #region Nix device settings
    public bool IsRgbEnabled => Device?.RgbFeedbackEnabled ?? false;
    public void SyncRgbSetting() => OnPropertyChanged(nameof(IsRgbEnabled));
    public bool IsHapticEnabled => Device?.HapticFeedbackEnabled ?? false;
    public void SyncHapticSetting() => OnPropertyChanged(nameof(IsHapticEnabled));
    public bool IsTileEnabled => Device?.FieldCalibrationEnabled ?? false;
    public void SyncTileSetting() => OnPropertyChanged(nameof(IsTileEnabled));
    public bool IsTempCompEnabled => Device?.TemperatureCompensationEnabled ?? false;
    public void SyncTemperatureSetting() => OnPropertyChanged(nameof(IsTempCompEnabled));
    #endregion
}