using Device;
using Microsoft.AspNetCore.SignalR.Client;
using ServiceBase;

namespace EEMSUIClientCore;

public class HubBase : IDisposable
{
    private IUIProvider? _provider;
    private static HubConnection? _HubConnection;

    public bool Initialize(IUIProvider provider)
    {
        if (_HubConnection is not null)
            return false;
        if (_provider is not null)
            return false;

        _provider = provider;

        return true;
    }

    public bool Open(string ip, int port, string hub, int retry = 40)
    {
        if (_provider is null)
            return false;

        HubConnection temp = new HubConnectionBuilder()
            .WithUrl($"http://{ip}:{port}/{hub}")
            .WithAutomaticReconnect()
            .Build();

        temp.On<IEnumerable<DeviceInfo>>("UpdateDeviceList", _provider.UpdateDeviceList);
        temp.On<DeviceInfo>("UpdateDevice", _provider.UpdateDevice);

        for (int i = 1; i <= retry; i++)
        {
            try
            {
                temp.StartAsync().Wait();
                _HubConnection = temp;
                break;
            }
            catch
            {
                if (i == retry)
                    return false;
                Thread.Sleep(1000);
            }
        }
        return true;
    }

    public static bool CheckConnect()
    {
        if (_HubConnection is null)
            return false;
        if (_HubConnection.State != HubConnectionState.Connected)
            return false;

        return true;
    }

    public static async Task<bool> Send(string name)
    {
        if (!CheckConnect())
            return false;

        try
        {
            await _HubConnection!.SendAsync(name);
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static async Task<bool> Send<T1>(string name, T1 para1)
    {
        if (!CheckConnect())
            return false;

        try
        {
            await _HubConnection!.SendAsync(name, para1);
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static async Task<bool> Send<T1, T2>(string name, T1 para1, T2 para2)
    {
        if (!CheckConnect())
            return false;

        try
        {
            await _HubConnection!.SendAsync(name, para1, para2);
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static async Task<bool> Send<T1, T2, T3>(string name, T1 para1, T2 para2, T3 para3)
    {
        if (!CheckConnect())
            return false;

        try
        {
            await _HubConnection!.SendAsync(name, para1, para2, para3);
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static async Task<bool> Send<T1, T2, T3, T4>(string name, T1 para1, T2 para2, T3 para3, T4 para4)
    {
        if (!CheckConnect())
            return false;

        try
        {
            await _HubConnection!.SendAsync(name, para1, para2, para3, para4);
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static bool Invoke<T_Return>(string name, out T_Return? returnValue)
    {
        returnValue = default;

        if (!CheckConnect())
            return false;

        try
        {
            returnValue = _HubConnection!.InvokeAsync<T_Return>(name).Result;
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static bool Invoke<T_Return, T_para1>(string name, T_para1 para1, out T_Return? returnValue)
    {
        returnValue = default;

        if (!CheckConnect())
            return false;

        try
        {
            returnValue = _HubConnection!.InvokeAsync<T_Return>(name, para1).Result;
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static bool Invoke<T_Return, T_para1, T_Para2>(string name, T_para1 para1, T_Para2 para2, out T_Return? returnValue)
    {
        returnValue = default;

        if (!CheckConnect())
            return false;

        try
        {
            returnValue = _HubConnection!.InvokeAsync<T_Return>(name, para1, para2).Result;
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static bool Invoke<T_Return, T_para1, T_Para2, T_Para3>(string name, T_para1 para1, T_Para2 para2, T_Para3 para3, out T_Return? returnValue)
    {
        returnValue = default;

        if (!CheckConnect())
            return false;

        try
        {
            returnValue = _HubConnection!.InvokeAsync<T_Return>(name, para1, para2, para3).Result;
        }
        catch
        {
            return false;
        }

        return true;
    }

    public void Dispose()
    {
        _HubConnection?.StopAsync().Wait();
        _HubConnection = null;
    }
}