using System.Net;
using DotNext;
using Peripherals.PowerClient;
using WebProtocol;

namespace Peripherals.HdmiInClient;

static class HdmiInAddr
{
    public const UInt32 BASE = 0xA000_0000;
    public const UInt32 HdmiIn_CTRL = BASE + 0x0; //[0]: rstn, 0 is reset.
    public const UInt32 HdmiIn_READFIFO = BASE + 0x1;
}

public class HdmiIn
{
    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    readonly int timeout = 500;
    readonly int taskID;
    readonly int port;
    readonly string address;
    private IPEndPoint ep;

    // 动态分辨率参数
    private UInt16 _currentWidth = 960;
    private UInt16 _currentHeight = 540;
    private UInt32 _currentFrameLength = 960 * 540 * 2 / 4; // RGB565格式，2字节/像素，按4字节对齐

    /// <summary>
    /// 初始化HDMI输入客户端
    /// </summary>
    /// <param name="address">HDMI输入设备IP地址</param>
    /// <param name="port">HDMI输入设备端口</param>
    /// <param name="taskID">任务ID</param>
    /// <param name="timeout">超时时间（毫秒）</param>
    public HdmiIn(string address, int port, int taskID, int timeout = 500)
    {
        if (timeout < 0)
            throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
        this.address = address;
        this.port = port;
        this.ep = new IPEndPoint(IPAddress.Parse(address), port);
        this.taskID = taskID;
        this.timeout = timeout;
    }

    public async ValueTask<Result<bool>> EnableTrans(bool isEnable)
    {
        var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, HdmiInAddr.HdmiIn_CTRL, (isEnable ? 0x00000001u : 0x00000000u));
        if (!ret.IsSuccessful)
        {
            logger.Error($"Failed to write HdmiIn_CTRL to HdmiIn at {this.address}:{this.port}, error: {ret.Error}");
            return new(ret.Error);
        }
        if (!ret.Value)
        {
            logger.Error($"HdmiIn_CTRL write returned false for HdmiIn at {this.address}:{this.port}");
            return false;
        }
        return true;
    }

    /// <summary>
    /// 读取一帧图像数据
    /// </summary>
    /// <returns>包含图像数据的字节数组</returns>
    public async ValueTask<Result<byte[]>> ReadFrame()
    {
        // 只在第一次或出错时清除UDP缓冲区，避免每帧都清除造成延迟
        // MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);

        logger.Trace($"Reading frame from HdmiIn {this.address}");

        // 使用UDPClientPool读取图像帧数据
        var result = await UDPClientPool.ReadAddr4BytesAsync(
            this.ep,
            this.taskID, // taskID
            HdmiInAddr.HdmiIn_READFIFO,
            (int)_currentFrameLength, // 使用当前分辨率的动态大小
            BurstType.FixedBurst,
            this.timeout);

        if (!result.IsSuccessful)
        {
            logger.Error($"Failed to read frame from HdmiIn {this.address}:{this.port}, error: {result.Error}");
            // 读取失败时清除缓冲区，为下次读取做准备
            try
            {
                MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
            }
            catch (Exception ex)
            {
                logger.Warn($"Failed to clear UDP data after read error: {ex.Message}");
            }
            return new(result.Error);
        }

        logger.Trace($"Successfully read frame from HdmiIn {this.address}:{this.port}, data length: {result.Value.Length} bytes");
        return result.Value;
    }

    public async ValueTask<(byte[] header, byte[] data, byte[] footer)?> GetMJpegFrame()
    {
        // 从HDMI读取RGB24数据
        var readStartTime = DateTime.UtcNow;
        var frameResult = await ReadFrame();
        var readEndTime = DateTime.UtcNow;
        var readTime = (readEndTime - readStartTime).TotalMilliseconds;

        if (!frameResult.IsSuccessful || frameResult.Value == null)
        {
            logger.Warn("HDMI帧读取失败或为空");
            return null;
        }

        var rgb24Data = frameResult.Value;

        // 验证数据长度是否正确 (RGB24为每像素2字节)
        var expectedLength = _currentWidth * _currentHeight * 2;
        if (rgb24Data.Length != expectedLength)
        {
            logger.Warn("HDMI数据长度不匹配，期望: {Expected}, 实际: {Actual}",
                expectedLength, rgb24Data.Length);
        }

        // 将RGB24转换为JPEG（参考Camera版本的处理）
        var jpegStartTime = DateTime.UtcNow;
        var jpegResult = Common.Image.ConvertRGB24ToJpeg(rgb24Data, _currentWidth, _currentHeight, 80);
        var jpegEndTime = DateTime.UtcNow;
        var jpegTime = (jpegEndTime - jpegStartTime).TotalMilliseconds;

        if (!jpegResult.IsSuccessful)
        {
            logger.Error("HDMI RGB24转JPEG失败: {Error}", jpegResult.Error);
            return null;
        }

        var jpegData = jpegResult.Value;

        // 发送MJPEG帧（使用Camera版本的格式）
        var mjpegFrameHeader = Common.Image.CreateMjpegFrameHeader(jpegData.Length);
        var mjpegFrameFooter = Common.Image.CreateMjpegFrameFooter();

        return (mjpegFrameHeader, jpegData, mjpegFrameFooter);
    }

    /// <summary>
    /// 获取当前分辨率
    /// </summary>
    /// <returns>当前分辨率(宽度, 高度)</returns>
    public (int Width, int Height) GetCurrentResolution()
    {
        return (_currentWidth, _currentHeight);
    }

    /// <summary>
    /// 获取当前帧长度
    /// </summary>
    /// <returns>当前帧长度</returns>
    public UInt32 GetCurrentFrameLength()
    {
        return _currentFrameLength;
    }
}
