//------------------------------------------------------------------------------
//  此代码版权声明为全文件覆盖，如有原作者特别声明，会在下方手动补充
//  此代码版权（除特别声明外的代码）归作者本人Diego所有
//  源代码使用协议遵循本仓库的开源协议及附加协议
//  Gitee源代码仓库：https://gitee.com/diego2098/ThingsGateway
//  Github源代码仓库：https://github.com/kimdiego2098/ThingsGateway
//  使用文档：https://thingsgateway.cn/
//  QQ群：605534569
//------------------------------------------------------------------------------

using PooledAwait;

using System.Text;

using ThingsGateway.Foundation.Extension.String;

namespace ThingsGateway.Foundation;

/// <inheritdoc/>
[PluginOption(Singleton = true)]
public class DtuPlugin : PluginBase, ITcpReceivingPlugin
{
    /// <summary>
    /// 心跳字符串
    /// </summary>
    public string Heartbeat
    {
        get
        {
            return _heartbeat;
        }
        set
        {
            _heartbeat = value;
            if (!heartbeatHex)
                HeartbeatByte = (Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
            else
                HeartbeatByte = (_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
        }
    }
    private string _heartbeat;
    private Memory<byte> HeartbeatByte = new();


    private bool heartbeatHex;
    public bool HeartbeatHex
    {
        get
        {
            return heartbeatHex;
        }
        set
        {
            heartbeatHex = value;
            if (!heartbeatHex)
                HeartbeatByte = (Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
            else
                HeartbeatByte = (_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
        }
    }
    public bool DtuIdHex { get; set; }

    /// <inheritdoc/>
    public Task OnTcpReceiving(ITcpSession client, BytesReaderEventArgs e)
    {
        return OnTcpReceiving(this, client, e);


        static async PooledTask OnTcpReceiving(DtuPlugin @this, ITcpSession client, BytesReaderEventArgs e)
        {
            var len = @this.HeartbeatByte.Length;
            if (client is TcpSessionClientChannel socket && socket.Service is ITcpServiceChannel tcpServiceChannel)
            {
                if (!socket.Id.StartsWith("ID="))
                {
                    var id = @this.DtuIdHex ? $"ID={e.Reader.ToHexString()}" : $"ID={e.Reader.TotalSequence.ToString(Encoding.UTF8)}";
                    if (tcpServiceChannel.TryGetClient(id, out var oldClient))
                    {
                        try
                        {
                            await oldClient.CloseAsync().ConfigureAwait(false);
                            oldClient.Dispose();
                        }
                        catch
                        {
                        }
                    }
                    await socket.ResetIdAsync(id, client.ClosedToken).ConfigureAwait(false);
                    client.Logger?.Info(string.Format(AppResource.DtuConnected, id));
                    e.Reader.Advance((int)e.Reader.BytesRemaining);
                    e.Handled = true;
                }

                if (!socket.Service.ClientExists(socket.Id))
                {
                    try
                    {
                        await socket.CloseAsync().ConfigureAwait(false);
                        socket.Dispose();
                    }
                    catch
                    {
                    }

                    await e.InvokeNext().ConfigureAwait(false);//如果本插件无法处理当前数据，请将数据转至下一个插件。
                    return;
                }

                if (len > 0)
                {
                    if (@this.HeartbeatByte.Span.SequenceEqual(e.Reader.TotalSequence.Slice(0, (int)Math.Min(len, e.Reader.BytesRemaining + e.Reader.BytesRead)).First.Span))
                    {
                        if (DateTimeOffset.Now - socket.LastSentTime < TimeSpan.FromMilliseconds(200))
                        {
                            await Task.Delay(200, client.ClosedToken).ConfigureAwait(false);
                        }
                        //回应心跳包
                        await socket.SendAsync(@this.HeartbeatByte, socket.ClosedToken).ConfigureAwait(false);
                        e.Reader.Advance((int)Math.Min(len, e.Reader.BytesRemaining));
                        e.Handled = true;
                        if (socket.Logger?.LogLevel <= LogLevel.Trace)
                            socket.Logger?.Trace($"{socket}- Heartbeat");
                    }
                }
            }
            await e.InvokeNext().ConfigureAwait(false);//如果本插件无法处理当前数据，请将数据转至下一个插件。
            return;
        }
    }


}
