using System;
using System.Web.Http.Results;
using CncModels.Constants;
using CncModels.Dto;
using CncModels.Dto.Login;
using CncService;
using CncWebApi.Controllers;
using Xunit;

namespace CncWebApi.Tests
{
    /// <summary>
    /// AuthController单元测试
    /// 登录接口，无JWT过滤，验证登录成功/失败场景
    /// </summary>
    [Collection("Database")]
    public class AuthControllerTests
    {
        private readonly AuthController _controller;
        private const string TestPassword = "admin123";

        public AuthControllerTests()
        {
            TestDb.TruncateAll();
            // 设置真实BCrypt密码哈希，确保密码验证可通过
            TestDb.SetRealPasswordHash(TestPassword);
            _controller = ControllerFactory.CreateAuthController();
        }

        #region Login - 登录

        /// <summary>
        /// 测试：正确用户名和密码登录成功
        /// </summary>
        [Fact]
        public void Login_CorrectCredentials_ShouldReturnToken()
        {
            // Arrange
            var request = new LoginRequest
            {
                Username = "admin",
                Password = TestPassword,
                RememberMe = false
            };

            // Act
            var result = _controller.Login(request);

            // Assert
            var response = ControllerFactory.Extract<LoginResponse>(result);
            ControllerFactory.AssertSuccess(response);
            Assert.NotNull(response.Data);
            Assert.False(string.IsNullOrWhiteSpace(response.Data.Token));
            Assert.Equal(8 * 3600, response.Data.ExpiresIn); // 非记住密码，8小时
        }

        /// <summary>
        /// 测试：记住密码时Token过期时间为24小时
        /// </summary>
        [Fact]
        public void Login_RememberMe_ShouldReturn24HourToken()
        {
            // Arrange
            var request = new LoginRequest
            {
                Username = "admin",
                Password = TestPassword,
                RememberMe = true
            };

            // Act
            var result = _controller.Login(request);

            // Assert
            var response = ControllerFactory.Extract<LoginResponse>(result);
            Assert.Equal(24 * 3600, response.Data.ExpiresIn);
        }

        /// <summary>
        /// 测试：错误密码登录失败
        /// </summary>
        [Fact]
        public void Login_WrongPassword_ShouldThrowBusinessException()
        {
            // Arrange
            var request = new LoginRequest
            {
                Username = "admin",
                Password = "wrong_password"
            };

            // Act & Assert
            var ex = Assert.Throws<BusinessException>(() => _controller.Login(request));
            Assert.Equal(ErrorCode.BadRequest, ex.Code);
            Assert.Equal("用户名或密码错误", ex.Message);
        }

        /// <summary>
        /// 测试：错误用户名登录失败
        /// </summary>
        [Fact]
        public void Login_WrongUsername_ShouldThrowBusinessException()
        {
            // Arrange
            var request = new LoginRequest
            {
                Username = "notexist",
                Password = TestPassword
            };

            // Act & Assert
            var ex = Assert.Throws<BusinessException>(() => _controller.Login(request));
            Assert.Equal("用户名或密码错误", ex.Message);
        }

        /// <summary>
        /// 测试：请求为null时抛出参数异常
        /// </summary>
        [Fact]
        public void Login_NullRequest_ShouldThrowBusinessException()
        {
            // Act & Assert
            var ex = Assert.Throws<BusinessException>(() => _controller.Login(null));
            Assert.Equal(ErrorCode.BadRequest, ex.Code);
        }

        /// <summary>
        /// 测试：用户名不区分大小写
        /// </summary>
        [Fact]
        public void Login_CaseInsensitiveUsername_ShouldReturnToken()
        {
            // Arrange
            var request = new LoginRequest
            {
                Username = "ADMIN",
                Password = TestPassword
            };

            // Act
            var result = _controller.Login(request);

            // Assert
            var response = ControllerFactory.Extract<LoginResponse>(result);
            ControllerFactory.AssertSuccess(response);
            Assert.NotNull(response.Data.Token);
        }

        #endregion
    }
}
