using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Database;
using server.Services;

namespace server.Controllers;

/// <summary>
/// JTAG 控制器 - 提供 JTAG 相关的 API 操作
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize] // 添加用户认证要求
public class JtagController : ControllerBase
{
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    private readonly ProgressTrackerService _tracker;
    private readonly UserManager _userManager;
    private readonly ResourceManager _resourceManager;

    private const string BITSTREAM_PATH = "bitstream/Jtag";

    public JtagController(
        ProgressTrackerService tracker, UserManager userManager, ResourceManager resourceManager)
    {
        _tracker = tracker;
        _userManager = userManager;
        _resourceManager = resourceManager;
    }

    /// <summary>
    /// 控制器首页信息
    /// </summary>
    /// <returns>控制器描述信息</returns>
    [HttpGet]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
    public string Index()
    {
        logger.Info($"User {User.Identity?.Name} accessed Jtag controller index");
        return "This is Jtag Controller";
    }

    /// <summary>
    /// 获取 JTAG 设备的 ID Code
    /// </summary>
    /// <param name="address">JTAG 设备地址</param>
    /// <param name="port">JTAG 设备端口</param>
    /// <returns>设备的 ID Code</returns>
    [HttpGet("GetDeviceIDCode")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(uint), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async ValueTask<IResult> GetDeviceIDCode(string address, int port)
    {
        logger.Info($"User {User.Identity?.Name} requesting device ID code from {address}:{port}");

        try
        {
            var jtagCtrl = new Peripherals.JtagClient.Jtag(address, port);
            var ret = await jtagCtrl.ReadIDCode();

            if (ret.IsSuccessful)
            {
                logger.Info($"User {User.Identity?.Name} successfully got device {address} ID code: 0x{ret.Value:X8}");
                return TypedResults.Ok(ret.Value);
            }
            else
            {
                logger.Error($"User {User.Identity?.Name} failed to get device {address} ID code: {ret.Error}");
                return TypedResults.InternalServerError(ret.Error);
            }
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"User {User.Identity?.Name} encountered exception while getting device {address} ID code");
            return TypedResults.InternalServerError(ex);
        }
    }

    /// <summary>
    /// 读取 JTAG 设备的状态寄存器
    /// </summary>
    /// <param name="address">JTAG 设备地址</param>
    /// <param name="port">JTAG 设备端口</param>
    /// <returns>状态寄存器的原始值、二进制表示和解码值</returns>
    [HttpGet("ReadStatusReg")]
    [EnableCors("Users")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async ValueTask<IResult> ReadStatusReg(string address, int port)
    {
        logger.Info($"User {User.Identity?.Name} requesting status register from {address}:{port}");

        try
        {
            var jtagCtrl = new Peripherals.JtagClient.Jtag(address, port);
            var ret = await jtagCtrl.ReadStatusReg();

            if (ret.IsSuccessful)
            {
                var binaryValue = Common.String.Reverse(Convert.ToString(ret.Value, 2).PadLeft(32, '0'));
                var decodeValue = new Peripherals.JtagClient.JtagStatusReg(ret.Value);
                logger.Info($"User {User.Identity?.Name} successfully read device {address} Status Register: \n\t 0b{binaryValue} \n\t {decodeValue}");
                return TypedResults.Ok(new
                {
                    original = ret.Value,
                    binaryValue,
                    decodeValue,
                });
            }
            else
            {
                logger.Error($"User {User.Identity?.Name} failed to read device {address} status register: {ret.Error}");
                return TypedResults.InternalServerError(ret.Error);
            }
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"User {User.Identity?.Name} encountered exception while reading device {address} status register");
            return TypedResults.InternalServerError(ex);
        }
    }

    /// <summary>
    /// 通过 JTAG 下载比特流文件到 FPGA 设备
    /// </summary>
    /// <param name="address">JTAG 设备地址</param>
    /// <param name="port">JTAG 设备端口</param>
    /// <param name="bitstreamId">比特流ID</param>
    /// <param name="cancelToken">取消令牌</param>
    /// <returns>进度跟踪TaskID</returns>
    [HttpPost("DownloadBitstream")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public IResult DownloadBitstream(string address, int port, string bitstreamId, CancellationToken cancelToken)
    {
        logger.Info($"User {User.Identity?.Name} initiating bitstream download to device {address}:{port} using bitstream ID: {bitstreamId}");

        try
        {
            // 获取当前用户名
            var username = User.Identity?.Name;
            if (string.IsNullOrEmpty(username))
            {
                logger.Warn("Anonymous user attempted to download bitstream");
                return TypedResults.Unauthorized();
            }

            // 从数据库获取用户信息
            var userResult = _userManager.GetUserByName(username);
            if (!userResult.IsSuccessful || !userResult.Value.HasValue)
            {
                logger.Error($"User {username} not found in database");
                return TypedResults.BadRequest("用户不存在");
            }

            // 从数据库获取比特流
            var user = userResult.Value.Value;
            var resourceRet = _resourceManager.GetResourceById(bitstreamId);

            if (!resourceRet.HasValue)
            {
                logger.Warn($"User {username} attempted to download non-existent bitstream ID: {bitstreamId}");
                return TypedResults.BadRequest("比特流不存在");
            }

            // 处理比特流数据
            var resource = resourceRet.Value;
            var bitstreamRet = _resourceManager.ReadBytesFromPath(resource.Path);
            if (!bitstreamRet.IsSuccessful)
            {
                logger.Error($"User {username} failed to read bitstream file: {bitstreamRet.Error}");
                return TypedResults.InternalServerError($"比特流读取失败: {bitstreamRet.Error?.Message}");
            }

            var fileBytes = bitstreamRet.Value;
            if (fileBytes == null || fileBytes.Length == 0)
            {
                logger.Warn($"User {username} found empty bitstream data for ID: {bitstreamId}");
                return TypedResults.BadRequest("比特流数据为空，请重新上传");
            }

            logger.Info($"User {username} processing bitstream file of size: {fileBytes.Length} bytes");

            // 定义进度跟踪
            var (taskId, progress) = _tracker.CreateTask(cancelToken);
            progress.Report(10);

            _ = Task.Run(async () =>
            {
                // 定义缓冲区大小: 32KB
                byte[] buffer = new byte[32 * 1024];
                byte[] revBuffer = new byte[32 * 1024];
                long totalBytesProcessed = 0;

                // 使用内存流处理文件
                using (var inputStream = new MemoryStream(fileBytes))
                using (var outputStream = new MemoryStream())
                {
                    int bytesRead;
                    while ((bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        // 反转 32bits
                        var retBuffer = Common.Number.ReverseBytes(buffer, 4);
                        if (!retBuffer.IsSuccessful)
                        {
                            logger.Error($"User {username} failed to reverse bytes: {retBuffer.Error}");
                            progress.Error($"User {username} failed to reverse bytes: {retBuffer.Error}");
                            return;
                        }
                        revBuffer = retBuffer.Value;

                        for (int i = 0; i < revBuffer.Length; i++)
                        {
                            revBuffer[i] = Common.Number.ReverseBits(revBuffer[i]);
                        }

                        await outputStream.WriteAsync(revBuffer, 0, bytesRead);
                        totalBytesProcessed += bytesRead;
                    }

                    // 获取处理后的数据
                    var processedBytes = outputStream.ToArray();
                    logger.Info($"User {username} processed {totalBytesProcessed} bytes for device {address}");

                    progress.Report(20);

                    // 下载比特流
                    var jtagCtrl = new Peripherals.JtagClient.Jtag(address, port);
                    var ret = await jtagCtrl.DownloadBitstream(processedBytes);

                    if (ret.IsSuccessful)
                    {
                        logger.Info($"User {username} successfully downloaded bitstream '{resource.ResourceName}' to device {address}");
                        progress.Finish();
                    }
                    else
                    {
                        logger.Error($"User {username} failed to download bitstream to device {address}: {ret.Error}");
                        progress.Error($"User {username} failed to download bitstream to device {address}: {ret.Error}");
                    }
                }
            });

            return TypedResults.Ok(taskId);
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"User encountered exception while downloading bitstream to device {address}");
            return TypedResults.InternalServerError(ex);
        }
    }

    /// <summary>
    /// 执行边界扫描，获取所有端口状态
    /// </summary>
    /// <param name="address">JTAG 设备地址</param>
    /// <param name="port">JTAG 设备端口</param>
    /// <returns>边界扫描结果</returns>
    [HttpPost("BoundaryScanAllPorts")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async ValueTask<IResult> BoundaryScanAllPorts(string address, int port)
    {
        logger.Info($"User {User.Identity?.Name} initiating boundary scan for all ports on device {address}:{port}");

        try
        {
            var jtagCtrl = new Peripherals.JtagClient.Jtag(address, port);
            var ret = await jtagCtrl.BoundaryScan();

            if (!ret.IsSuccessful)
            {
                logger.Error($"User {User.Identity?.Name} boundary scan failed for device {address}: {ret.Error}");
                if (ret.Error is ArgumentException)
                    return TypedResults.BadRequest(ret.Error);
                else
                    return TypedResults.InternalServerError(ret.Error);
            }

            logger.Info($"User {User.Identity?.Name} successfully completed boundary scan for device {address}");
            return TypedResults.Ok(ret.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"User {User.Identity?.Name} encountered exception during boundary scan for device {address}");
            return TypedResults.InternalServerError(ex);
        }
    }

    /// <summary>
    /// 执行逻辑端口边界扫描
    /// </summary>
    /// <param name="address">JTAG 设备地址</param>
    /// <param name="port">JTAG 设备端口</param>
    /// <returns>逻辑端口状态字典</returns>
    [HttpPost("BoundaryScanLogicalPorts")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(Dictionary<string, bool>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async ValueTask<IResult> BoundaryScanLogicalPorts(string address, int port)
    {
        logger.Info($"User {User.Identity?.Name} initiating logical ports boundary scan on device {address}:{port}");

        try
        {
            var jtagCtrl = new Peripherals.JtagClient.Jtag(address, port);
            var ret = await jtagCtrl.BoundaryScanLogicalPorts();

            if (!ret.IsSuccessful)
            {
                logger.Error($"User {User.Identity?.Name} logical ports boundary scan failed for device {address}: {ret.Error}");
                if (ret.Error is ArgumentException)
                    return TypedResults.BadRequest(ret.Error);
                else
                    return TypedResults.InternalServerError(ret.Error);
            }

            logger.Info($"User {User.Identity?.Name} successfully completed logical ports boundary scan for device {address}, found {ret.Value?.Count} ports");
            return TypedResults.Ok(ret.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"User {User.Identity?.Name} encountered exception during logical ports boundary scan for device {address}");
            return TypedResults.InternalServerError(ex);
        }
    }

    /// <summary>
    /// 设置 JTAG 时钟速度
    /// </summary>
    /// <param name="address">JTAG 设备地址</param>
    /// <param name="port">JTAG 设备端口</param>
    /// <param name="speed">时钟速度 (Hz)</param>
    /// <returns>设置结果</returns>
    [HttpPost("SetSpeed")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async ValueTask<IResult> SetSpeed(string address, int port, UInt32 speed)
    {
        logger.Info($"User {User.Identity?.Name} setting JTAG speed to {speed} Hz for device {address}:{port}");

        try
        {
            var jtagCtrl = new Peripherals.JtagClient.Jtag(address, port);
            var ret = await jtagCtrl.SetSpeed(speed);

            if (!ret.IsSuccessful)
            {
                logger.Error($"User {User.Identity?.Name} failed to set speed for device {address}: {ret.Error}");
                if (ret.Error is ArgumentException)
                    return TypedResults.BadRequest(ret.Error);
                else
                    return TypedResults.InternalServerError(ret.Error);
            }

            logger.Info($"User {User.Identity?.Name} successfully set JTAG speed to {speed} Hz for device {address}");
            return TypedResults.Ok(ret.Value);
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"User {User.Identity?.Name} encountered exception while setting speed for device {address}");
            return TypedResults.InternalServerError(ex);
        }
    }
}
