using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using NixExampleWinUI.ViewModels;
using NixUniversalSDK;
using Windows.ApplicationModel.Resources;

namespace NixExampleWinUI.Views;

public sealed partial class MainPage : Page
{
    public MainViewModel ViewModel
    {
        get;
    }

    public MainPage()
    {
        ViewModel = App.GetService<MainViewModel>();
        InitializeComponent();

        // Connect InfoBar, Plot, and ColorSwatch to ViewModel
        ViewModel.DeviceInfoBar = InfoBar;
        ViewModel.SpectralPlot = SpectralPlot;
        ViewModel.MeasuredSwatch = MeasuredSwatch;
    }

    #region Constants
    private static readonly ResourceLoader Loader = ResourceLoader.GetForViewIndependentUse();
    #endregion

    #region Devices pane
    private async void ToggleScannerState()
    {
        // Get current state
        var state = await ViewModel.UpdateDeviceScannerStateAsync();
        switch (state)
        {
            case DeviceScannerState.Idle:
                // Start the scanner
                ViewModel.ClearDevices();
                ViewModel.Scanner?.Start();
                break;
            case DeviceScannerState.Scanning:
                // Stop the scanner
                ViewModel.Scanner?.Stop();
                break;
            default:
                // Error state
                // Clear the list
                ViewModel.ClearDevices();

                // If a Bluetooth type error, can still list USB devices
                if (state == DeviceScannerState.ErrorBluetoothDisabled || 
                    state == DeviceScannerState.ErrorBluetoothPermissions || 
                    state == DeviceScannerState.ErrorBluetoothUnavailable)
                {
                    await ViewModel.UpdateUsbDeviceListAsync();
                }

                // Show error message
                InfoBar.Title = Loader.GetString("TitleScannerError");
                InfoBar.Message = string.Format(Loader.GetString("MessageScannerError"), state);
                InfoBar.Severity = InfoBarSeverity.Error;
                InfoBar.IsOpen = true;                
                break;
        }
    }

    private void SplitView_PaneOpening(SplitView sender, object args)
    {
        // Start the device scanner
        ToggleScannerState();
    }

    private void SplitView_PaneClosed(SplitView sender, object args)
    {
        // Stop the device scanner
        ViewModel.Scanner?.Stop();
    }

    private void RefreshButton_Click(object sender, RoutedEventArgs args)
    {
        // Start/stop the device scanner
        ToggleScannerState();
    }

    private void DevicesList_ItemClick(object sender, ItemClickEventArgs args)
    {
        if (args.ClickedItem is IDeviceCompat selectedDevice)
        {
            // Device was selected in the list...

            // Stop the scanner
            ViewModel.Scanner?.Stop();

            // Close the list
            SplitView.IsPaneOpen = false;

            // Set this device in the view model (starts a connection process)
            ViewModel.SelectedDevice = selectedDevice;

            // Show info bar
            InfoBar.Title = string.Empty;
            InfoBar.Message = string.Format(Loader.GetString("MessageConnecting"), selectedDevice.Name, selectedDevice.Id);
            InfoBar.Severity = InfoBarSeverity.Informational;
            InfoBar.IsOpen = true;
        }
    }
    #endregion

    private async void ScanButton_Click(object sender, RoutedEventArgs e)
    {
        if (ViewModel.SelectedDevice is null) { return; }

        // Hide any status messages
        InfoBar.IsOpen = false;
        
        // Start measurement
        var measureTask = ViewModel.SelectedDevice.MeasureAsync();

        // Note: the above command will report measurements in all supported
        // modes by the device. It is also possible to specify specific scan
        // modes. This is usually not necessary. Some cases where this could
        // be desired include:

        // ** On Spectro 2 devices running firmware F1.0.0 **:
        // M0 and M1 are captured in two separate measurements. If only one of
        // M0 or M1 is desired, requesting only one will speed up the scan
        // cycle.

        // Specific example cases are listed below:

        // EXAMPLE: request scan only for M2 mode:
        // Device.MeasureAsync(ScanMode.M2)

        // EXAMPLE: request scan for M0 and M1 mode:
        // Device.MeasureAsync(ScanMode.M0, ScanMode.M1)

        // EXAMPLE: request scan for all supported modes:
        // Device.MeasureAsync()

        // Trigger UI update
        ViewModel.UpdateDisplayedDeviceProperties();

        // Wait for result
        var result = await measureTask;
        if (result.Status != CommandStatus.Success)
        {
            // Show error status
            InfoBar.Title = Loader.GetString("TitleMeasureError");
            InfoBar.Message = string.Format(Loader.GetString("MessageMeasureError"), result.Status.GetName());
            InfoBar.Severity = InfoBarSeverity.Error;
            InfoBar.IsOpen = true;
        }
        else if (result.Measurements?.Count > 0)
        {
            // Update data in view model
            ViewModel.Measurements = result.Measurements;
        }

        // Update UI
        ViewModel.UpdateDisplayedDeviceProperties();
    }

    protected override void OnNavigatedTo(NavigationEventArgs args)
    {
        // Notify spectral plot container (in case the theme was changed on the settings page)
        SpectralPlot.ViewModel.UpdateTheme();

        // Continue
        base.OnNavigatedTo(args);
    }

    private void CancelConnectButton_Click(object sender, RoutedEventArgs args)
    {
        // Cancel a connection attempt in progress
        ViewModel.SelectedDevice?.Disconnect();
    }
}
