using System.Collections;
using System.Net;
using DotNext;

namespace Peripherals.MatrixKeyClient;

class MatrixKeyAddr
{
    public const UInt32 BASE = 0x10_00_00_00;
    public const UInt32 KEY_ENABLE = BASE + 5;
    public const UInt32 KEY_CTRL = BASE + 6;
}

/// <summary>
/// 矩阵键盘外设类，用于控制和管理矩阵键盘的功能。
/// </summary>
public class MatrixKey
{
    readonly int timeout;

    readonly int port;
    readonly string address;
    private IPEndPoint ep;

    /// <summary>
    /// 构造函数，用于初始化矩阵键盘外设实例。
    /// </summary>
    /// <param name="address">设备的IP地址</param>
    /// <param name="port">设备的端口号</param>
    /// <param name="timeout">操作的超时时间（毫秒），默认为1000</param>
    /// <returns>无返回值。</returns>
    public MatrixKey(string address, int port, int timeout = 1000)
    {
        this.address = address;
        this.port = port;
        this.ep = new IPEndPoint(IPAddress.Parse(address), port);
        this.timeout = timeout;
    }

    /// <summary>
    /// 启用矩阵键盘的控制功能。
    /// </summary>
    /// <returns>返回一个包含操作结果的异步任务</returns>
    public async ValueTask<Result<bool>> EnableControl()
    {
        if (MsgBus.IsRunning)
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
        else return new(new Exception("Message Bus not work!"));

        var ret = await UDPClientPool.WriteAddr(this.ep, 1, MatrixKeyAddr.KEY_ENABLE, 1, this.timeout);
        if (!ret.IsSuccessful) return new(ret.Error);
        return ret.Value;
    }

    /// <summary>
    /// 禁用矩阵键盘的控制功能。
    /// </summary>
    /// <returns>返回一个包含操作结果的异步任务</returns>
    public async ValueTask<Result<bool>> DisableControl()
    {
        if (MsgBus.IsRunning)
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
        else return new(new Exception("Message Bus not work!"));

        var ret = await UDPClientPool.WriteAddr(this.ep, 1, MatrixKeyAddr.KEY_ENABLE, 0, this.timeout);
        if (!ret.IsSuccessful) return new(ret.Error);
        return ret.Value;
    }

    /// <summary>
    /// 控制矩阵键盘的按键状态。
    /// </summary>
    /// <param name="keyStates">表示按键状态的位数组，长度必须为16</param>
    /// <returns>返回一个包含操作结果的异步任务</returns>
    public async ValueTask<Result<bool>> ControlKey(BitArray keyStates)
    {
        if (MsgBus.IsRunning)
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
        else return new(new Exception("Message Bus not work!"));

        if (keyStates.Length != 16) return new(new ArgumentException(
            $"The number of key should be 16 instead of {keyStates.Length}", nameof(keyStates)));

        var ret = await UDPClientPool.WriteAddr(
            this.ep, 1, MatrixKeyAddr.KEY_CTRL, Common.Number.BitsToNumber(keyStates).Value, this.timeout);
        if (!ret.IsSuccessful) return new(ret.Error);
        return ret.Value;
    }
}
