using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;

namespace server.Controllers;

/// <summary>
/// Jtag API
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class JtagController : ControllerBase
{
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    private const string BITSTREAM_PATH = "bitstream/Jtag";

    /// <summary>
    /// 页面
    /// </summary>
    [HttpGet]
    public string Index()
    {
        return "This is Jtag Controller";
    }

    /// <summary>
    /// 获取Jtag ID Code
    /// </summary>
    /// <param name="address"> 设备地址 </param>
    /// <param name="port"> 设备端口 </param>
    [HttpGet("GetDeviceIDCode")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(uint), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    public async ValueTask<IResult> GetDeviceIDCode(string address, int port)
    {
        var jtagCtrl = new JtagClient.Jtag(address, port);
        var ret = await jtagCtrl.ReadIDCode();

        if (ret.IsSuccessful)
        {
            logger.Info($"Get device {address} ID code: 0x{ret.Value:X4}");
            return TypedResults.Ok(ret.Value);
        }
        else
        {
            logger.Error(ret.Error);
            return TypedResults.InternalServerError(ret.Error);
        }
    }

    /// <summary>
    /// 获取状态寄存器
    /// </summary>
    /// <param name="address"> 设备地址 </param>
    /// <param name="port"> 设备端口 </param>
    [HttpGet("ReadStatusReg")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async ValueTask<IResult> ReadStatusReg(string address, int port)
    {
        var jtagCtrl = new 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 JtagClient.JtagStatusReg(ret.Value);
            logger.Info($"Read device {address} Status Register: \n\t 0b{binaryValue} \n\t {decodeValue}");
            return TypedResults.Ok(new
            {
                original = ret.Value,
                binaryValue,
                decodeValue,
            });
        }
        else
        {
            logger.Error(ret.Error);
            return TypedResults.InternalServerError(ret.Error);
        }
    }

    /// <summary>
    /// 上传比特流文件
    /// </summary>
    /// <param name="address"> 设备地址 </param>
    /// <param name="file">比特流文件</param>
    [HttpPost("UploadBitstream")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
    public async ValueTask<IResult> UploadBitstream(string address, IFormFile file)
    {
        if (file == null || file.Length == 0)
            return TypedResults.BadRequest("未选择文件");

        // 生成安全的文件名（避免路径遍历攻击）
        var fileName = Path.GetRandomFileName();
        var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}");

        // 如果存在文件，则删除原文件再上传
        if (Directory.Exists(uploadsFolder))
        {
            Directory.Delete(uploadsFolder, true);
        }
        Directory.CreateDirectory(uploadsFolder);

        var filePath = Path.Combine(uploadsFolder, fileName);

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }

        logger.Info($"Device {address} Upload Bitstream Successfully");
        return TypedResults.Ok(true);
    }

    /// <summary>
    /// 通过Jtag下载比特流文件
    /// </summary>
    /// <param name="address"> 设备地址 </param>
    /// <param name="port"> 设备端口 </param>
    [HttpPost("DownloadBitstream")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    public async ValueTask<IResult> DownloadBitstream(string address, int port)
    {
        // 检查文件
        var fileDir = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}");
        if (!Directory.Exists(fileDir))
            return TypedResults.BadRequest("Empty bitstream, Please upload it first");

        try
        {
            // 读取文件
            var filePath = Directory.GetFiles(fileDir)[0];

            using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open))
            {
                if (fileStream is null || fileStream.Length <= 0)
                    return TypedResults.BadRequest("Wrong bitstream, Please upload it again");

                // 定义缓冲区大小: 32KB
                byte[] buffer = new byte[32 * 1024];
                byte[] revBuffer = new byte[32 * 1024];
                long totalBytesRead = 0;

                // 使用异步流读取文件
                using (var memoryStream = new MemoryStream())
                {
                    int bytesRead;
                    while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        // 反转 32bits
                        var retBuffer = Common.Number.ReverseBytes(buffer, 4);
                        if (!retBuffer.IsSuccessful)
                            return TypedResults.InternalServerError(retBuffer.Error);
                        revBuffer = retBuffer.Value;

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

                        await memoryStream.WriteAsync(revBuffer, 0, bytesRead);
                        totalBytesRead += bytesRead;
                    }

                    // 将所有数据转换为字节数组（注意：如果文件非常大，可能不适合完全加载到内存）
                    var fileBytes = memoryStream.ToArray();

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

                    if (ret.IsSuccessful)
                    {
                        logger.Info($"Device {address} dowload bitstream successfully");
                        return TypedResults.Ok(ret.Value);
                    }
                    else
                    {
                        logger.Error(ret.Error);
                        return TypedResults.InternalServerError(ret.Error);
                    }
                }

            }

        }
        catch (Exception error)
        {
            return TypedResults.InternalServerError(error);
        }
        finally
        {

        }
    }

    /// <summary>
    /// [TODO:description]
    /// </summary>
    /// <param name="address">[TODO:parameter]</param>
    /// <param name="port">[TODO:parameter]</param>
    /// <returns>[TODO:return]</returns>
    [HttpPost("BoundaryScanAllPorts")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    public async ValueTask<IResult> BoundaryScanAllPorts(string address, int port)
    {
        var jtagCtrl = new JtagClient.Jtag(address, port);
        var ret = await jtagCtrl.BoundaryScan();
        if (!ret.IsSuccessful)
        {
            if (ret.Error is ArgumentException)
                return TypedResults.BadRequest(ret.Error);
            else return TypedResults.InternalServerError(ret.Error);
        }

        return TypedResults.Ok(ret.Value);
    }

    /// <summary>
    /// [TODO:description]
    /// </summary>
    /// <param name="address">[TODO:parameter]</param>
    /// <param name="port">[TODO:parameter]</param>
    /// <returns>[TODO:return]</returns>
    [HttpPost("BoundaryScanLogicalPorts")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(Dictionary<string, bool>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    public async ValueTask<IResult> BoundaryScanLogicalPorts(string address, int port)
    {
        var jtagCtrl = new JtagClient.Jtag(address, port);
        var ret = await jtagCtrl.BoundaryScanLogicalPorts();
        if (!ret.IsSuccessful)
        {
            if (ret.Error is ArgumentException)
                return TypedResults.BadRequest(ret.Error);
            else return TypedResults.InternalServerError(ret.Error);
        }

        return TypedResults.Ok(ret.Value);
    }

    /// <summary>
    /// [TODO:description]
    /// </summary>
    /// <param name="address">[TODO:parameter]</param>
    /// <param name="port">[TODO:parameter]</param>
    /// <param name="speed">[TODO:parameter]</param>
    /// <returns>[TODO:return]</returns>
    [HttpPost("SetSpeed")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
    public async ValueTask<IResult> SetSpeed(string address, int port, UInt32 speed)
    {
        var jtagCtrl = new JtagClient.Jtag(address, port);
        var ret = await jtagCtrl.SetSpeed(speed);
        if (!ret.IsSuccessful)
        {
            if (ret.Error is ArgumentException)
                return TypedResults.BadRequest(ret.Error);
            else return TypedResults.InternalServerError(ret.Error);
        }

        return TypedResults.Ok(ret.Value);
    }
}
