using NixExampleWinUI.Views;
using NixUniversalSDK;
using Windows.ApplicationModel.Resources;

namespace NixExampleWinUI.Helpers;

public static class DeviceHelper
{
    // See https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font for full icon glyph list
    private const string GlyphError = "\uE783";
    private const string GlyphWiredUsb = "\uECF0";
    private const string GlyphSignalBars1 = "\uE86C";
    private const string GlyphSignalBars2 = "\uE86D";
    private const string GlyphSignalBars3 = "\uE86E";
    private const string GlyphSignalBars4 = "\uE86F";
    private const string GlyphSignalBars5 = "\uE870";

    // RSSI threshold values used to determine Bluetooth signal icon
    private const int RssiBars4 = -45;
    private const int RssiBars3 = -60;
    private const int RssiBars2 = -75;
    private const int RssiBars1 = -90;

    /// <summary>
    /// Gets a glyph for the Segoe Fluent Icons Font corresponding to this device based on its connection method and signal strength
    /// </summary>
    public static string GetIconGlyph(InterfaceType interfaceType, int rssi)
    {
        switch (interfaceType)
        {
            case InterfaceType.Ble:
                {
                    if (rssi >= RssiBars4)
                    {
                        return GlyphSignalBars5;
                    }
                    else if (rssi >= RssiBars3)
                    {
                        return GlyphSignalBars4;
                    }
                    else if (rssi >= RssiBars2)
                    {
                        return GlyphSignalBars3;
                    }
                    else if (rssi >= RssiBars1)
                    {
                        return GlyphSignalBars2;
                    }
                    else
                    {
                        return GlyphSignalBars1;
                    }
                }
            case InterfaceType.UsbCdc:
                // Wired USB
                return GlyphWiredUsb;
            default:
                // Error
                return GlyphError;
        }
    }

    /// <summary>
    /// Provides a list of <see cref="SimpleInfoItem"/> for an <see cref="IDeviceCompat"/> instance, useful for populating <see cref="InfoListContentDialog"/>.
    /// </summary>
    public static IEnumerable<SimpleInfoItem> GetDeviceInfoList(this IDeviceCompat? device)
    {
        // String resources
        ResourceLoader loader = ResourceLoader.GetForViewIndependentUse();
        var valueUnavailable = loader.GetString("ValueUnavailable");
        var valueTrue = loader.GetString("ValueTrue");
        var valueFalse = loader.GetString("ValueFalse");

        // Create and fill the list
        var list = new List<SimpleInfoItem>();

        // Device Name
        list.Add(new SimpleInfoItem(
            type: SimpleInfoItem.ListType.DeviceInfo,
            title: loader.GetString("TitleDeviceName"),
            subtitle: device?.Name ?? string.Empty));

        if ((device?.State ?? DeviceState.Disconnected) == DeviceState.Disconnected)
        {
            // Device is disconnected, do not add the remaining list items
            return list;
        }

        // Hardware Version
        // Edge case: version cannot be read for Nix Pro devices over USB and will be empty
        if (device?.HardwareVersion?.String is string hardwareString)
        {
            list.Add(new SimpleInfoItem(
            type: SimpleInfoItem.ListType.DeviceInfo,
            title: loader.GetString("TitleDeviceHardware"),
            subtitle: hardwareString.Length > 0 ? hardwareString : valueUnavailable));
        }

        // Firmware Version
        // Edge case: version cannot be read for Nix Pro devices over USB and will be empty
        if (device?.FirmwareVersion?.String is string firmwareString)
        {
            list.Add(new SimpleInfoItem(
            type: SimpleInfoItem.ListType.DeviceInfo,
            title: loader.GetString("TitleDeviceFirmware"),
            subtitle: firmwareString.Length > 0 ? firmwareString : valueUnavailable));
        }

        // Serial Number
        list.Add(new SimpleInfoItem(
            type: SimpleInfoItem.ListType.DeviceInfo,
            title: loader.GetString("TitleSerialNumber"),
            subtitle: device?.SerialNumber ?? string.Empty));

        // Battery Level
        var batteryLevel = device?.BatteryLevel;
        list.Add(new SimpleInfoItem(
            type: SimpleInfoItem.ListType.DeviceInfo,
            title: loader.GetString("TitleBatteryLevel"),
            subtitle: (device is null) ? string.Empty :
                (batteryLevel is null) ? valueUnavailable :
                $"{batteryLevel}%"));

        // External Power Connected
        list.Add(new SimpleInfoItem(
            type: SimpleInfoItem.ListType.DeviceInfo,
            title: loader.GetString("TitleExtPowerConnected"),
            subtitle: (device is null) ? string.Empty :
                (device?.ExtPowerState == true) ?
                valueTrue : valueFalse));

        // Optional device properties
        // Scan Counter
        if (device?.ScanCount is uint scanCount)
        {
            list.Add(new SimpleInfoItem(
                type: SimpleInfoItem.ListType.DeviceInfo,
                title: loader.GetString("TitleScanCounter"),
                subtitle: scanCount.ToString()));
        }

        // Field Calibration Info
        if (device?.ReferenceDate is DateTime referenceDate)
        {
            // Note: if field calibration has never been performed,
            // reference date will be Unix epoch (January 1, 1970, 00:00 UTC)
            var dateString = referenceDate.Year < 2000 ? 
                valueUnavailable : 
                referenceDate.ToString();
            list.Add(new SimpleInfoItem(
                type: SimpleInfoItem.ListType.DeviceInfo,
                title: loader.GetString("TitleFieldCalibrationDate"),
                subtitle: dateString));

            list.Add(new SimpleInfoItem(
                type: SimpleInfoItem.ListType.DeviceInfo,
                title: loader.GetString("TitleFieldCalibrationDue"),
                subtitle: (device?.FieldCalibrationDue == true) ? valueTrue : valueFalse));
        }
        return list;
    }
}