namespace MinicsUI.Connector;

public class HubSender(HubReceiver receiver, Hardwares hardwares) : SenderBase, IEnableDeviceNotify
{
    public bool Initialize(string ip, int port, string hub, int retry = 40)
    {
        StartConsole();

        if (_hubConnection is not null)
            return false;

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

        temp.On<byte, Mini8Data>("UpdateMini8", UpdateMini8);
        temp.On<byte, byte, ChannelData>("UpdateSingleChannel", receiver.UpdateSingleChannel);
        temp.On<byte, List<ChannelData>>("UpdateChannel", receiver.UpdateChannels);
        temp.On<TemperatureConfig>("UpdateFiles", receiver.UpdateFiles);
        temp.On("ClearFiles", receiver.ClearFiles);
        temp.On<byte, Mini8Address>("UpdateAddress", receiver.UpdateAddress);
        temp.On<TemperatureConfig>("CurrentFile", receiver.CurrentFile);
        temp.On<byte, byte, float>("AlarmNotify", receiver.AlarmNotify);
        temp.On<byte, byte>("AlarmTcBrockenNotify", receiver.AlarmTcBrockenNotify);
        temp.On<byte, bool>("Mini8Connect", receiver.Mini8Connect);
        temp.On<int, DateTime>("UpdateDataBaseInfo", receiver.UpdateDataBaseInfo);
        temp.On<byte, byte, ChannelData>("ChannelDataUpdate", receiver.ChannelDataUpdate);

        //temp.ServerTimeout = TimeSpan.FromSeconds(5.0);


        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 bool SwitchDataBase(out string? dbName)
    {
        if (!Invoke("SwitchDataBase", out dbName) || dbName is null)
            return false;
        return true;
    }

    public async Task<bool> ClearDataBase()
    {
        return await Send("ClearDataBase");
    }

    public async Task<bool> UpdateDataBaseRange(int range)
    {
        return await Send("UpdateDataBaseRange", range);
    }
    public async Task<bool> RequestHardwares()
    {
        hardwares.Mini8s.Clear();
        hardwares.Mini8Channels.Clear();

        return await Send("QueryHardwares");
    }

    public bool FullyReset()
    {
        return Send("FullyReset").Result;
    }

    public async Task<bool> RequestConfigFiles()
    {
        return await Send("QueryConfigFiles");
    }

    public bool SaveSetValue(Channel channelSet)
    {
        ChannelData channelData = new();
        channelSet.Adapt(channelData);
        if (!Invoke("SaveSetValue", channelData, out bool result))
            return false;

        return result;
    }

    public bool EnableChannel(byte mini8Index, byte channelIndex, Inhibit inhibit)
    {
        if (!Invoke("EnableChannel", mini8Index, channelIndex, inhibit, out bool result))
            return false;

        return result;
    }

    public bool SwitchChannelMode(byte mini8Index, byte channelIndex, ChannelMode channelMode)
    {
        if (!Invoke("SwitchChannelMode", mini8Index, channelIndex, channelMode, out bool result))
            return false;

        return result;
    }


    public bool ReconnectMini8(byte mini8Index)
    {
        if (!Invoke("ReconnectMini8", mini8Index, out bool result))
            return false;
        return result;
    }

    public bool SelectPID(byte mini8Index, byte channelIndex, ActiveTuneSet activeTuneSet)
    {
        if (!Invoke("SelectPID", mini8Index, channelIndex, activeTuneSet, out bool result))
            return false;

        return result;
    }

    public bool EnableAT(byte mini8Index, byte channelIndex, bool isEnable)
    {
        if (!Invoke("EnableAT", mini8Index, channelIndex, isEnable, out bool result))
            return false;

        return result;
    }

    public bool SendSetValue(Channel channelSet)
    {
        ChannelData channelData = new();
        channelSet.Adapt(channelData);

        if (!Invoke("SendSetValue", channelData, out bool success))
            return false;

        return success;
    }

    public bool SetConfigFile(string fileName)
    {
        if (!Invoke("SetConfigFile", fileName, out bool success))
            return false;

        return success;
    }

    public bool QueryMini8Data(out TempConfig? config)
    {
        config = null;
        if (!Invoke("QueryMini8Data", out TemperatureConfig? temp) || temp is null)
            return false;
        config = new();
        temp.Adapt(config);

        return true;
    }

    public bool LoadNewFile(string filePath)
    {
        if (!Invoke("LoadNewFile", filePath, out bool success))
            return false;

        return success;
    }

    public bool RemoveFile(string fileName)
    {
        if (!Invoke("RemoveFile", fileName, out bool success))
            return false;

        return success;
    }

    public bool SaveConfig(string fileName, TempConfig tempConfig, bool saveAsNew)
    {
        TemperatureConfig temperatureConfig = new();
        tempConfig.Adapt(temperatureConfig);

        if (!Invoke("SaveConfig", fileName, temperatureConfig, saveAsNew, out bool success))
            return false;

        return success;
    }

    public bool RequestLogin(string userName, string password, out UserAuthority userAuthority)
    {
        if (Invoke("TryLogin", userName, password, out userAuthority))
            return true;

        userAuthority = UserAuthority.Deinded;
        return false;
    }

    public bool RequestShutdown()
    {
        Invoke("ShutDown", out bool success);

        return success;
    }

    private void UpdateMini8(byte key, Mini8Data value)
    {
        if (!hardwares.Mini8s.TryGetValue(key, out Mini8Info? mini8) || mini8 is null)
        {
            mini8 = new(this);
            hardwares.Mini8s[key] = mini8;
        }

        mini8.Status = value.Enable switch
        {
            true => Mini8Status.Normal,
            false => Mini8Status.Disabled
        };

        value.Adapt(mini8);
    }

    void IEnableDeviceNotify.EnableDevice(byte mini8Index, bool isEnable)
    {
        Send("EnableDisableDevice", mini8Index, isEnable).Wait();
    }
}