using BluetoothLENet;
using InABox.Core;

namespace InABox.Avalonia.Platform.Desktop;

public class Desktop_Bluetooth : IBluetooth, IDisposable
{
    public Logger? Logger { get; set; }

    private BLE _adapter;
    
    public Action<IBluetoothDevice>? DeviceFound { get; set; }
    public CoreObservableCollection<IBluetoothDevice> Devices { get; } = new();

    public event EventHandler? Changed;
    
    public Desktop_Bluetooth()
    {
        Devices.CollectionChanged += (_,_) => Changed?.Invoke(this, EventArgs.Empty);
        
        _adapter = new BLE();
        _adapter.Changed += (_,_) =>
        {
            var found = _adapter.Devices.Select(x => x.MacAddress).ToArray();
            var cache = Devices.OfType<Desktop_BluetoothDevice>().Select(x => x.ID).ToArray();
            if (found.Except(cache).Any() || cache.Except(found).Any())
            {
                var devices = _adapter.Devices
                    .ToArray()
                    .Select(x => new Desktop_BluetoothDevice(x));
                Devices.ReplaceRange(devices);
            }
        };
    }

    public async Task<bool> IsAvailable()
    {
        return await Task.FromResult(true);   
    }
    
    public async Task<bool> StartScanningAsync(Guid configServiceId)
    {
        if (await IsAvailable())
            return await _adapter.StartScanningAsync(configServiceId);
        return false;
    }

    public async Task<bool> StopScanningAsync()
    {
        if (await IsAvailable())
            return await _adapter.StopScanningAsync();
        return false;
    }

    public async Task<IConnectedBluetoothDevice?> Connect(IBluetoothDevice device)
    {
        if (await IsAvailable())
        {
            if (device is Desktop_BluetoothDevice d)
            {
                var result = await _adapter.Connect(d.Device);
                if (result == ConnectDeviceResult.Ok)
                    return new Desktop_ConnectedBluetoothDevice(d.Device);
            }
        }
        return null;
        
    }

    public async Task<bool> Disconnect(IConnectedBluetoothDevice device)
    {
        if (await IsAvailable())
        {
            if (device is Desktop_BluetoothDevice { Device: not null } d)
            {
                _adapter.Disconnect(d.Device);
            }
        }
        return true;
    }

    public void Dispose()
    {
        foreach (var device in Devices)
            device.Dispose();
        Devices.Clear();
    }
}
