using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace server.Controllers;

/// <summary>
/// 数据控制器
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    private readonly Database.UserManager _userManager;

    // 固定的实验板IP,端口,MAC地址
    private const string BOARD_IP = "169.254.109.0";

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

    /// <summary>
    /// 获取本机IP地址（优先选择与实验板同网段的IP）
    /// </summary>
    /// <returns>本机IP地址</returns>
    private IPAddress GetLocalIPAddress()
    {
        try
        {
            var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray();

            // 优先选择与实验板IP前三段相同的IP
            var sameSegmentIP = System.Net.NetworkInformation.NetworkInterface
                .GetAllNetworkInterfaces()
                .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up
                              && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback)
                .SelectMany(nic => nic.GetIPProperties().UnicastAddresses)
                .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                .Select(addr => addr.Address)
                .FirstOrDefault(addr =>
                {
                    var segments = addr.ToString().Split('.');
                    return segments.Length == 4 &&
                           segments[0] == boardIpSegments[0] &&
                           segments[1] == boardIpSegments[1] &&
                           segments[2] == boardIpSegments[2];
                });

            if (sameSegmentIP != null)
                return sameSegmentIP;

            // 如果没有找到同网段的IP，返回第一个可用的IP
            return System.Net.NetworkInformation.NetworkInterface
                .GetAllNetworkInterfaces()
                .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up
                              && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback)
                .SelectMany(nic => nic.GetIPProperties().UnicastAddresses)
                .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                .Select(addr => addr.Address)
                .FirstOrDefault() ?? IPAddress.Loopback;
        }
        catch (Exception ex)
        {
            logger.Error(ex, "获取本机IP地址失败");
            return IPAddress.Loopback;
        }
    }

    /// <summary>
    /// 用户登录，获取 JWT 令牌
    /// </summary>
    /// <param name="name">用户名</param>
    /// <param name="password">用户密码</param>
    /// <returns>JWT 令牌字符串</returns>
    [HttpPost("Login")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult Login(string name, string password)
    {
        // 验证用户密码
        var ret = _userManager.CheckUserPassword(name, password);
        if (!ret.IsSuccessful) return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
        if (!ret.Value.HasValue) return BadRequest("用户名或密码错误");
        var user = ret.Value.Value;

        // 生成 JWT
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes("my secret key 1234567890my secret key 1234567890");
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.Name, user.Name),
                new Claim(ClaimTypes.Email, user.EMail),
                new Claim(ClaimTypes.Role, user.Permission.ToString())
            }),
            Expires = DateTime.UtcNow.AddHours(1),
            SigningCredentials = new SigningCredentials(
                new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            Audience = "dlut.edu.cn",
            Issuer = "dlut.edu.cn",
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var jwt = tokenHandler.WriteToken(token);

        return Ok(jwt);
    }

    /// <summary>
    /// 测试用户认证，需携带有效 JWT
    /// </summary>
    /// <returns>认证成功信息</returns>
    [Authorize]
    [HttpGet("TestAuth")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public IActionResult TestAuth()
    {
        return Ok("认证成功！");
    }

    /// <summary>
    /// 测试管理员用户认证，需携带有效 JWT
    /// </summary>
    /// <returns>认证成功信息</returns>
    [Authorize("Admin")]
    [HttpGet("TestAdminAuth")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public IActionResult TestAdminAuth()
    {
        return Ok("认证成功！");
    }

    /// <summary>
    /// 获取当前用户信息
    /// </summary>
    /// <returns>用户信息，包括ID、用户名、邮箱和板卡ID</returns>
    [Authorize]
    [HttpGet("GetUserInfo")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(UserInfo), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public IActionResult GetUserInfo()
    {
        // Get User Name
        var userName = User.Identity?.Name;
        if (string.IsNullOrEmpty(userName))
            return Unauthorized("未找到用户名信息");

        // Get User Info
        var ret = _userManager.GetUserByName(userName);
        if (!ret.IsSuccessful)
            return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");

        if (!ret.Value.HasValue)
            return BadRequest("用户不存在");

        var user = ret.Value.Value;
        return Ok(new UserInfo
        {
            ID = user.ID,
            Name = user.Name,
            EMail = user.EMail,
            BoardID = user.BoardID,
            BoardExpireTime = user.BoardExpireTime,
        });
    }

    /// <summary>
    /// 注册新用户
    /// </summary>
    /// <param name="name">用户名（不超过255个字符）</param>
    /// <param name="email">邮箱地址</param>
    /// <param name="password">用户密码</param>
    /// <returns>操作结果，成功返回 true，失败返回错误信息</returns>
    [HttpPost("SignUpUser")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult SignUpUser(string name, string email, string password)
    {
        // 验证输入参数
        if (string.IsNullOrWhiteSpace(name))
            return BadRequest("用户名不能为空");

        if (name.Length > 255)
            return BadRequest("用户名不能超过255个字符");

        if (string.IsNullOrWhiteSpace(email))
            return BadRequest("邮箱不能为空");

        if (string.IsNullOrWhiteSpace(password))
            return BadRequest("密码不能为空");

        try
        {
            var ret = _userManager.AddUser(name, email, password);
            return Ok(ret);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "注册用户时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "注册失败，请稍后重试");
        }
    }

    /// <summary>
    /// 获取一个空闲的实验板（普通用户权限）
    /// </summary>
    /// <param name="durationHours">绑定持续时间（小时），默认为1小时</param>
    [Authorize]
    [HttpGet("GetAvailableBoard")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(Database.Board), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async ValueTask<IActionResult> GetAvailableBoard(int durationHours = 1)
    {
        try
        {
            var userName = User.Identity?.Name;
            if (string.IsNullOrEmpty(userName))
                return Unauthorized("未找到用户名信息");

            var userRet = _userManager.GetUserByName(userName);
            if (!userRet.IsSuccessful || !userRet.Value.HasValue)
                return BadRequest("用户不存在");

            var user = userRet.Value.Value;
            var expireTime = DateTime.UtcNow.AddHours(durationHours);

            var boardOpt = _userManager.GetAvailableBoard(user.ID, expireTime);
            if (!boardOpt.HasValue)
                return NotFound("没有可用的实验板");

            var boardInfo = boardOpt.Value;
            if (!(await ArpClient.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
            {
                logger.Error($"无法配置ARP，实验板可能会无法连接");
            }

            return Ok(boardInfo);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "获取空闲实验板时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "获取失败，请稍后重试");
        }
    }

    /// <summary>
    /// 解除当前用户绑定的实验板（普通用户权限）
    /// </summary>
    [Authorize]
    [HttpPost("UnbindBoard")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult UnbindBoard()
    {
        try
        {
            var userName = User.Identity?.Name;
            if (string.IsNullOrEmpty(userName))
                return Unauthorized("未找到用户名信息");

            var userRet = _userManager.GetUserByName(userName);
            if (!userRet.IsSuccessful || !userRet.Value.HasValue)
                return BadRequest("用户不存在");

            var user = userRet.Value.Value;
            var result = _userManager.UnbindUserFromBoard(user.ID);
            return Ok(result > 0);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "解除实验板绑定时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "解除失败，请稍后重试");
        }
    }

    /// <summary>
    /// 用户根据实验板ID获取实验板信息（普通用户权限）
    /// </summary>
    [Authorize]
    [HttpGet("GetBoardByID")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(Database.Board), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async Task<IActionResult> GetBoardByID(Guid id)
    {
        try
        {
            var ret = _userManager.GetBoardByID(id);
            if (!ret.IsSuccessful)
                return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
            if (!ret.Value.HasValue)
                return NotFound("未找到对应的实验板");

            var boardInfo = ret.Value.Value;
            if (!(await ArpClient.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
            {
                logger.Error($"无法配置ARP，实验板可能会无法连接");
            }

            return Ok(boardInfo);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "获取实验板信息时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "获取失败，请稍后重试");
        }
    }

    /// <summary>
    /// 新增板子（管理员权限）
    /// </summary>
    [Authorize("Admin")]
    [HttpPost("AddBoard")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(Guid), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult AddBoard(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            return BadRequest("板子名称不能为空");
        try
        {
            var ret = _userManager.AddBoard(name);
            return Ok(ret);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "新增板子时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "新增失败，请稍后重试");
        }
    }

    /// <summary>
    /// 删除板子（管理员权限）
    /// </summary>
    [Authorize("Admin")]
    [HttpDelete("DeleteBoard")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult DeleteBoard(Guid id)
    {
        if (id == Guid.Empty)
            return BadRequest("板子Guid不能为空");

        try
        {
            var ret = _userManager.DeleteBoardByID(id);
            return Ok(ret);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "删除板子时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "删除失败，请稍后重试");
        }
    }

    /// <summary>
    /// 获取全部板子（管理员权限）
    /// </summary>
    [Authorize("Admin")]
    [HttpGet("GetAllBoards")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(Database.Board[]), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult GetAllBoards()
    {
        try
        {
            var boards = _userManager.GetAllBoard();
            return Ok(boards);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "获取全部板子时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "获取失败，请稍后重试");
        }
    }

    /// <summary>
    /// 更新板卡名称（管理员权限）
    /// </summary>
    [Authorize("Admin")]
    [HttpPost("UpdateBoardName")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult UpdateBoardName(Guid boardId, string newName)
    {
        if (boardId == Guid.Empty)
            return BadRequest("板子Guid不能为空");
        if (string.IsNullOrWhiteSpace(newName))
            return BadRequest("新名称不能为空");
        try
        {
            var result = _userManager.UpdateBoardName(boardId, newName);
            return Ok(result);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "更新板卡名称时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "更新失败，请稍后重试");
        }
    }

    /// <summary>
    /// 更新板卡状态（管理员权限）
    /// </summary>
    [Authorize("Admin")]
    [HttpPost("UpdateBoardStatus")]
    [EnableCors("Users")]
    [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult UpdateBoardStatus(Guid boardId, Database.BoardStatus newStatus)
    {
        if (boardId == Guid.Empty)
            return BadRequest("板子Guid不能为空");
        try
        {
            var result = _userManager.UpdateBoardStatus(boardId, newStatus);
            return Ok(result);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "更新板卡状态时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "更新失败，请稍后重试");
        }
    }

    [HttpPost("AddEmptyBoard")]
    [EnableCors("Development")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public IActionResult AddEmptyBoard()
    {
        try
        {
            var boardId = _userManager.AddBoard("Test");
            var result = _userManager.UpdateBoardStatus(boardId, Database.BoardStatus.Available);
            return Ok();
        }
        catch (Exception ex)
        {
            logger.Error(ex, "新增板子时发生异常");
            return StatusCode(StatusCodes.Status500InternalServerError, "新增失败，请稍后重试");
        }
    }

    /// <summary>
    /// [TODO:description]
    /// </summary>
    public class UserInfo
    {
        /// <summary>
        /// 用户的唯一标识符
        /// </summary>
        public Guid ID { get; set; }

        /// <summary>
        /// 用户的名称
        /// </summary>
        public required string Name { get; set; }

        /// <summary>
        /// 用户的电子邮箱
        /// </summary>
        public required string EMail { get; set; }

        /// <summary>
        /// 用户关联的板卡ID
        /// </summary>
        public Guid BoardID { get; set; }

        /// <summary>
        /// 用户绑定板子的过期时间
        /// </summary>
        public DateTime? BoardExpireTime { get; set; }
    }
}
