using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Peripherals.DebuggerClient;

namespace server.Controllers;

/// <summary>
/// FPGA调试器控制器，提供信号捕获、触发、数据读取等调试相关API
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class DebuggerController : ControllerBase
{
    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    private readonly Database.UserManager _userManager;

    public DebuggerController(Database.UserManager userManager)
    {
        this._userManager = userManager;
    }

    /// <summary>
    /// 获取当前用户绑定的调试器实例
    /// </summary>
    private DebuggerClient? GetDebugger()
    {
        try
        {
            var userName = User.Identity?.Name;
            if (string.IsNullOrEmpty(userName))
                return null;

            var userRet = _userManager.GetUserByName(userName);
            if (!userRet.IsSuccessful || !userRet.Value.HasValue)
                return null;

            var user = userRet.Value.Value;
            if (user.BoardID == Guid.Empty)
                return null;

            var boardRet = _userManager.GetBoardByID(user.BoardID);
            if (!boardRet.IsSuccessful || !boardRet.Value.HasValue)
                return null;

            var board = boardRet.Value.Value;
            return new DebuggerClient(board.IpAddr, board.Port, 1);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "获取调试器实例时发生异常");
            return null;
        }
    }

    /// <summary>
    /// 设置指定信号线的捕获模式
    /// </summary>
    /// <param name="wireNum">信号线编号（0~511）</param>
    /// <param name="mode">捕获模式</param>
    [HttpPost("SetMode")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> SetMode(UInt32 wireNum, CaptureMode mode)
    {
        if (wireNum > 512)
        {
            return BadRequest($"最多只能建立512位信号线");
        }

        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            var result = await debugger.SetMode(wireNum, mode);
            if (!result.IsSuccessful)
            {
                logger.Error($"设置捕获模式失败: {result.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "设置捕获模式失败");
            }

            return Ok(result.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "设置捕获模式时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 为每个通道中的每根线设置捕获模式
    /// </summary>
    /// <param name="config">调试器配置信息，包含所有通道的捕获模式设置</param>
    [HttpPost("SetChannelsMode")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> SetChannelsMode([FromBody] DebuggerConfig config)
    {
        if (config == null || config.channelConfigs == null)
            return BadRequest("配置无效");

        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            foreach (var channel in config.channelConfigs)
            {
                // 检查每个通道的配置
                if (channel.wireWidth > 32 ||
                    channel.wireStartIndex > 32 ||
                    channel.wireStartIndex + channel.wireWidth > 32)
                {
                    return BadRequest($"通道 {channel.name} 配置错误");
                }

                for (uint i = 0; i < channel.wireWidth; i++)
                {
                    var result = await debugger.SetMode(channel.wireStartIndex * (channel.parentPort * 32) + i, channel.mode);
                    if (!result.IsSuccessful)
                    {
                        logger.Error($"设置通道 {channel.name} 第 {i} 根线捕获模式失败: {result.Error}");
                        return StatusCode(StatusCodes.Status500InternalServerError, $"设置通道 {channel.name} 第 {i} 根线捕获模式失败");
                    }
                }
            }

            return Ok(true);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "为每个通道中的每根线设置捕获模式时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 启动触发器，开始信号捕获
    /// </summary>
    [HttpPost("StartTrigger")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> StartTrigger()
    {
        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            var result = await debugger.StartTrigger();
            if (!result.IsSuccessful)
            {
                logger.Error($"启动触发器失败: {result.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "启动触发器失败");
            }

            return Ok(result.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "启动触发器时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 读取触发器状态标志
    /// </summary>
    [HttpGet("ReadFlag")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(byte), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> ReadFlag()
    {
        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            var result = await debugger.ReadFlag();
            if (!result.IsSuccessful)
            {
                logger.Error($"读取触发器状态标志失败: {result.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "读取触发器状态标志失败");
            }

            return Ok(result.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "读取触发器状态标志时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 清除触发器状态标志
    /// </summary>
    [HttpPost("ClearFlag")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> ClearFlag()
    {
        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            var result = await debugger.ClearFlag();
            if (!result.IsSuccessful)
            {
                logger.Error($"清除触发器状态标志失败: {result.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "清除触发器状态标志失败");
            }

            return Ok(result.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "清除触发器状态标志时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 读取捕获数据（等待触发完成后返回各通道采样数据）
    /// </summary>
    /// <param name="config">调试器配置信息，包含采样深度、端口数、通道配置等</param>
    /// <param name="cancellationToken">取消操作的令牌</param>
    [HttpPost("ReadData")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(ChannelCaptureData[]), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> ReadData([FromBody] DebuggerConfig config, CancellationToken cancellationToken)
    {
        // 检查每个通道的配置
        foreach (var channel in config.channelConfigs)
        {
            if (channel.wireWidth > 32 ||
                channel.wireStartIndex > 32 ||
                channel.wireStartIndex + channel.wireWidth > 32)
            {
                return BadRequest($"通道 {channel.name} 配置错误");
            }
        }

        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            // 等待捕获标志位
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var flagResult = await debugger.ReadFlag();
                if (!flagResult.IsSuccessful)
                {
                    logger.Error($"读取捕获标志失败: {flagResult.Error}");
                    return StatusCode(StatusCodes.Status500InternalServerError, "读取捕获标志失败");
                }
                if (flagResult.Value == 1)
                {
                    var clearResult = await debugger.ClearFlag();
                    if (!clearResult.IsSuccessful)
                    {
                        logger.Error($"清除捕获标志失败: {clearResult.Error}");
                        return StatusCode(StatusCodes.Status500InternalServerError, "清除捕获标志失败");
                    }
                    break;
                }
                await Task.Delay(500, cancellationToken);
            }

            var dataResult = await debugger.ReadData(config.totalPortNum);
            if (!dataResult.IsSuccessful)
            {
                logger.Error($"读取捕获数据失败: {dataResult.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "读取捕获数据失败");
            }

            var freshResult = await debugger.Refresh();
            if (!freshResult.IsSuccessful)
            {
                logger.Error($"刷新调试器状态失败: {freshResult.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "刷新调试器状态失败");
            }

            var rawData = dataResult.Value;
            // logger.Debug($"rawData: {BitConverter.ToString(rawData)}");
            int depth = (int)config.captureDepth;
            int portDataLen = 4 * depth;
            int portNum = (int)config.totalPortNum;
            var channelDataList = new List<ChannelCaptureData>();

            foreach (var channel in config.channelConfigs)
            {
                int port = (int)channel.parentPort;
                int wireStart = (int)channel.wireStartIndex;
                int wireWidth = (int)channel.wireWidth;

                // 每个port的数据长度
                int portOffset = port * portDataLen;

                var channelUintArr = new UInt32[depth];
                for (int i = 0; i < depth; i++)
                {
                    // 取出该port的第i个采样点的4字节
                    int sampleOffset = portOffset + i * 4;
                    if (sampleOffset + 4 > rawData.Length)
                    {
                        logger.Error($"数据越界: port {port}, sample {i}");
                        return StatusCode(StatusCodes.Status500InternalServerError, "数据越界");
                    }
                    var sampleBytes = rawData[sampleOffset..(sampleOffset + 4)];
                    UInt32 sample = Common.Number.BytesToUInt32(sampleBytes, true).Value;
                    // 提取wireWidth位
                    UInt32 mask = (wireWidth == 32) ? 0xFFFFFFFF : ((1u << wireWidth) - 1u);
                    channelUintArr[i] = (sample >> wireStart) & mask;
                }
                var channelBytes = new byte[4 * depth];
                Buffer.BlockCopy(channelUintArr, 0, channelBytes, 0, channelBytes.Length);
                // logger.Debug($"{channel.name} HexData: {BitConverter.ToString(channelBytes)}");
                var base64 = Convert.ToBase64String(channelBytes);
                channelDataList.Add(new ChannelCaptureData { name = channel.name, data = base64 });
            }

            return Ok(channelDataList.ToArray());
        }
        catch (OperationCanceledException)
        {
            logger.Info("读取捕获数据请求被取消");
            return StatusCode(StatusCodes.Status499ClientClosedRequest, "客户端已取消请求");
        }
        catch (Exception ex)
        {
            logger.Error(ex, "读取捕获数据时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 刷新调试器状态（重置采集状态等）
    /// </summary>
    [HttpPost("Refresh")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> Refresh()
    {
        try
        {
            var debugger = GetDebugger();
            if (debugger == null)
                return BadRequest("用户未绑定有效的实验板");

            var result = await debugger.Refresh();
            if (!result.IsSuccessful)
            {
                logger.Error($"刷新调试器状态失败: {result.Error}");
                return StatusCode(StatusCodes.Status500InternalServerError, "刷新调试器状态失败");
            }

            return Ok(result.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "刷新调试器状态时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "操作失败，请稍后重试");
        }
    }

    /// <summary>
    /// 表示单个信号通道的配置信息
    /// </summary>
    public class ChannelConfig
    {
        /// <summary>
        /// 通道名称
        /// </summary>
        required public string name;
        /// <summary>
        /// 通道显示颜色（如前端波形显示用）
        /// </summary>
        required public string color;
        /// <summary>
        /// 通道信号线宽度（位数）
        /// </summary>
        required public UInt32 wireWidth;
        /// <summary>
        /// 信号线在父端口中的起始索引（bit）
        /// </summary>
        required public UInt32 wireStartIndex;
        /// <summary>
        /// 父端口编号
        /// </summary>
        required public UInt32 parentPort;
        /// <summary>
        /// 捕获模式（如上升沿、下降沿等）
        /// </summary>
        required public CaptureMode mode;
    }

    /// <summary>
    /// 调试器整体配置信息
    /// </summary>
    public class DebuggerConfig
    {
        /// <summary>
        /// 时钟频率
        /// </summary>
        required public UInt32 clkFreq;
        /// <summary>
        /// 总端口数量
        /// </summary>
        required public UInt32 totalPortNum;
        /// <summary>
        /// 捕获深度（采样点数）
        /// </summary>
        required public UInt32 captureDepth;
        /// <summary>
        /// 触发器数量
        /// </summary>
        required public UInt32 triggerNum;
        /// <summary>
        /// 所有信号通道的配置信息
        /// </summary>
        required public ChannelConfig[] channelConfigs;
    }

    /// <summary>
    /// 单个通道的捕获数据
    /// </summary>
    public class ChannelCaptureData
    {
        /// <summary>
        /// 通道名称
        /// </summary>
        required public string name;
        /// <summary>
        /// 通道捕获到的数据（Base64编码的UInt32数组）
        /// </summary>
        required public string data;
    }
}
