using System;
using CncModels.Constants;
using CncModels.Dto;
using CncModels.Dto.CollectAddress;
using CncService;
using CncService.Impl;
using Xunit;

namespace CncService.Tests
{
    /// <summary>
    /// CollectAddressService 采集地址测试
    /// 测试场景：CRUD、删除约束（关联机床）、品牌校验、参数校验
    /// </summary>
    [Collection("Database")]
    public class CollectAddressServiceTests : IDisposable
    {
        private readonly CollectAddressService _service;

        public CollectAddressServiceTests()
        {
            TestDb.TruncateAll();
            _service = ServiceFactory.CreateCollectAddressService();
        }

        public void Dispose()
        {
            TestDb.TruncateAll();
        }

        /// <summary>辅助方法：插入测试采集地址</summary>
        private int InsertTestAddress(string name = "测试地址")
        {
            return _service.Create(new CreateCollectAddressRequest
            {
                Name = name,
                Url = "http://192.168.1.100/api/data",
                BrandId = 1,
                CollectInterval = 30
            });
        }

        // ======== GetList ========

        [Fact]
        public void GetList_无数据_返回空列表()
        {
            var result = _service.GetList(new CollectAddressQuery { Page = 1, PageSize = 20 });
            Assert.NotNull(result);
            Assert.Equal(0, result.Total);
        }

        [Fact]
        public void GetList_有数据_返回分页结果()
        {
            InsertTestAddress("地址1");
            InsertTestAddress("地址2");

            var result = _service.GetList(new CollectAddressQuery { Page = 1, PageSize = 20 });
            Assert.Equal(2, result.Total);
        }

        // ======== GetById ========

        [Fact]
        public void GetById_存在的ID_返回详情()
        {
            var id = InsertTestAddress();
            var detail = _service.GetById(id);

            Assert.NotNull(detail);
            Assert.Equal("测试地址", detail.Name);
            Assert.Equal("http://192.168.1.100/api/data", detail.Url);
            Assert.Equal(1, detail.BrandId);
            Assert.Equal("FANUC", detail.BrandName);
        }

        [Fact]
        public void GetById_不存在的ID_抛出NotFound异常()
        {
            var ex = Assert.Throws<BusinessException>(() => _service.GetById(99999));
            Assert.Equal(ErrorCode.NotFound, ex.Code);
        }

        // ======== Create ========

        [Fact]
        public void Create_正常新增_返回自增ID()
        {
            var id = InsertTestAddress();
            Assert.True(id > 0);
        }

        [Fact]
        public void Create_请求为null_抛出BadRequest异常()
        {
            var ex = Assert.Throws<BusinessException>(() => _service.Create(null));
            Assert.Equal(ErrorCode.BadRequest, ex.Code);
        }

        [Fact]
        public void Create_品牌不存在_抛出NotFound异常()
        {
            var ex = Assert.Throws<BusinessException>(() => _service.Create(new CreateCollectAddressRequest
            {
                Name = "测试",
                Url = "http://test",
                BrandId = 99999,
                CollectInterval = 30
            }));
            Assert.Equal(ErrorCode.NotFound, ex.Code);
        }

        // ======== Update ========

        [Fact]
        public void Update_正常修改_返回true()
        {
            var id = InsertTestAddress();
            var result = _service.Update(id, new UpdateCollectAddressRequest
            {
                Name = "修改后地址",
                Url = "http://new-url",
                BrandId = 1,
                CollectInterval = 60
            });
            Assert.True(result);

            var updated = _service.GetById(id);
            Assert.Equal("修改后地址", updated.Name);
            Assert.Equal(60, updated.CollectInterval);
        }

        [Fact]
        public void Update_不存在的ID_抛出NotFound异常()
        {
            var ex = Assert.Throws<BusinessException>(() => _service.Update(99999, new UpdateCollectAddressRequest
            {
                Name = "测试"
            }));
            Assert.Equal(ErrorCode.NotFound, ex.Code);
        }

        [Fact]
        public void Update_请求为null_抛出BadRequest异常()
        {
            var id = InsertTestAddress();
            var ex = Assert.Throws<BusinessException>(() => _service.Update(id, null));
            Assert.Equal(ErrorCode.BadRequest, ex.Code);
        }

        [Fact]
        public void Update_Name为null_保留原值()
        {
            var id = InsertTestAddress();
            _service.Update(id, new UpdateCollectAddressRequest
            {
                Name = null,
                Url = null,
                BrandId = 0,
                CollectInterval = 0
            });
            var updated = _service.GetById(id);
            Assert.Equal("测试地址", updated.Name);
            Assert.Equal("http://192.168.1.100/api/data", updated.Url);
        }

        // ======== Delete ========

        [Fact]
        public void Delete_无关联机床_返回true()
        {
            var id = InsertTestAddress();
            var result = _service.Delete(id);
            Assert.True(result);
        }

        [Fact]
        public void Delete_有关联机床_返回false()
        {
            var addressId = InsertTestAddress();
            // 关联机床
            TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
                VALUES ('M001', '机床1', 1, @addressId, '0.0.0.0', 1, 1, NOW(), NOW())",
                new { addressId });

            var result = _service.Delete(addressId);
            Assert.False(result);
        }

        // ======== ToggleEnabled ========

        [Fact]
        public void ToggleEnabled_切换启用状态()
        {
            var id = InsertTestAddress();
            var before = _service.GetById(id);
            var beforeState = before.IsEnabled;

            _service.ToggleEnabled(id);

            var after = _service.GetById(id);
            Assert.NotEqual(beforeState, after.IsEnabled);
        }
    }
}
