using System.Collections.Generic;
using CncModels.Constants;
using CncModels.Dto;
using CncModels.Dto.CollectAddress;
using CncModels.Dto.Machine;
using CncService;
using CncWebApi.Controllers;
using Xunit;

namespace CncWebApi.Tests
{
    /// <summary>
    /// MachineController单元测试
    /// 机床CRUD + 启停
    /// </summary>
    [Collection("Database")]
    public class MachineControllerTests
    {
        private readonly MachineController _controller;

        public MachineControllerTests()
        {
            TestDb.TruncateAll();
            // 预置一个采集地址（机床外键依赖）
            TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
                VALUES ('测试地址', 'http://192.168.1.1', 1, 5, 1, NOW(), NOW())");
            _controller = ControllerFactory.CreateMachineController();
        }

        /// <summary>
        /// 辅助：创建机床请求
        /// </summary>
        private CreateMachineRequest CreateRequest(string code = "CNC001", string name = "机床1") => new CreateMachineRequest
        {
            DeviceCode = code,
            Name = name,
            WorkshopId = 1,
            CollectAddressId = 1,
            IpAddress = "192.168.1.100",
            BrandId = 1
        };

        #region GetList - 机床列表

        /// <summary>
        /// 测试：空数据库返回空列表
        /// </summary>
        [Fact]
        public void GetList_EmptyDb_ShouldReturnEmpty()
        {
            var result = _controller.GetList(new MachineQuery());
            var response = ControllerFactory.Extract<PagedResult<MachineListItem>>(result);
            ControllerFactory.AssertSuccess(response);
            Assert.Empty(response.Data.Items);
        }

        /// <summary>
        /// 测试：新增机床后列表有数据
        /// </summary>
        [Fact]
        public void GetList_AfterCreate_ShouldReturnOne()
        {
            _controller.Create(CreateRequest());
            var result = _controller.GetList(new MachineQuery());
            var response = ControllerFactory.Extract<PagedResult<MachineListItem>>(result);
            Assert.Single(response.Data.Items);
        }

        /// <summary>
        /// 测试：分页参数生效
        /// </summary>
        [Fact]
        public void GetList_Pagination_ShouldWork()
        {
            // 新增3台机床
            for (int i = 1; i <= 3; i++)
                _controller.Create(CreateRequest($"C{i:00}", $"机床{i}"));

            var result = _controller.GetList(new MachineQuery { Page = 1, PageSize = 2 });
            var response = ControllerFactory.Extract<PagedResult<MachineListItem>>(result);
            Assert.Equal(2, response.Data.Items.Count);
            Assert.Equal(3, response.Data.Total);
        }

        #endregion

        #region GetById - 机床详情

        /// <summary>
        /// 测试：获取机床详情成功
        /// </summary>
        [Fact]
        public void GetById_Existing_ShouldReturnDetail()
        {
            _controller.Create(CreateRequest());
            int id = TestDb.QuerySingle<int>("SELECT MAX(id) FROM cnc_machine");

            var result = _controller.GetById(id);
            var response = ControllerFactory.Extract<MachineDetailResponse>(result);
            ControllerFactory.AssertSuccess(response);
            Assert.Equal("CNC001", response.Data.DeviceCode);
        }

        /// <summary>
        /// 测试：获取不存在的机床抛出异常
        /// </summary>
        [Fact]
        public void GetById_NotExisting_ShouldThrow()
        {
            Assert.Throws<BusinessException>(() => _controller.GetById(999));
        }

        #endregion

        #region Create - 新增机床

        /// <summary>
        /// 测试：新增机床成功
        /// </summary>
        [Fact]
        public void Create_ValidRequest_ShouldReturnId()
        {
            var result = _controller.Create(CreateRequest());
            var response = ControllerFactory.Extract<object>(result);
            ControllerFactory.AssertSuccess(response);
            Assert.NotNull(response.Data);
        }

        /// <summary>
        /// 测试：重复设备编码抛出异常
        /// </summary>
        [Fact]
        public void Create_DuplicateCode_ShouldThrow()
        {
            _controller.Create(CreateRequest("CNC001", "机床1"));
            var ex = Assert.Throws<BusinessException>(() => _controller.Create(CreateRequest("CNC001", "机床2")));
            Assert.Equal("设备编码已存在", ex.Message);
        }

        #endregion

        #region Update - 编辑机床

        /// <summary>
        /// 测试：编辑机床成功
        /// </summary>
        [Fact]
        public void Update_ValidRequest_ShouldSuccess()
        {
            _controller.Create(CreateRequest());
            int id = TestDb.QuerySingle<int>("SELECT MAX(id) FROM cnc_machine");

            var result = _controller.Update(id, new UpdateMachineRequest
            {
                Name = "机床已改名",
                WorkshopId = 1,
                CollectAddressId = 1,
                IpAddress = "192.168.1.200",
                BrandId = 1
            });

            ControllerFactory.AssertSuccess(ControllerFactory.Extract<object>(result));
            var detail = ControllerFactory.Extract<MachineDetailResponse>(_controller.GetById(id));
            Assert.Equal("机床已改名", detail.Data.Name);
        }

        #endregion

        #region Delete - 删除机床

        /// <summary>
        /// 测试：删除机床成功
        /// </summary>
        [Fact]
        public void Delete_Existing_ShouldSuccess()
        {
            _controller.Create(CreateRequest());
            int id = TestDb.QuerySingle<int>("SELECT MAX(id) FROM cnc_machine");

            var result = _controller.Delete(id);
            ControllerFactory.AssertSuccess(ControllerFactory.Extract<object>(result));
            Assert.Throws<BusinessException>(() => _controller.GetById(id));
        }

        #endregion

        #region ToggleEnabled - 启停

        /// <summary>
        /// 测试：切换机床启用状态
        /// </summary>
        [Fact]
        public void ToggleEnabled_ShouldSuccess()
        {
            _controller.Create(CreateRequest());
            int id = TestDb.QuerySingle<int>("SELECT MAX(id) FROM cnc_machine");

            var result = _controller.ToggleEnabled(id);
            ControllerFactory.AssertSuccess(ControllerFactory.Extract<object>(result));
        }

        #endregion
    }
}
