using System;
using System.Linq;
using CncModels.Constants;
using CncModels.Dto.Brand;
using CncService;
using CncService.Impl;
using Xunit;

namespace CncService.Tests
{
    /// <summary>
    /// BrandService 品牌模板测试
    /// 测试场景：CRUD、复制、删除约束（关联采集地址）、字段映射、标准字段
    /// </summary>
    [Collection("Database")]
    public class BrandServiceTests : IDisposable
    {
        private readonly BrandService _service;

        public BrandServiceTests()
        {
            TestDb.TruncateAll();
            _service = ServiceFactory.CreateBrandService();
        }

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

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

        [Fact]
        public void GetList_返回种子数据品牌()
        {
            var list = _service.GetList();
            Assert.NotNull(list);
            Assert.True(list.Count >= 1, "种子数据至少有1个品牌");
            Assert.Contains(list, b => b.BrandName == "FANUC");
        }

        [Fact]
        public void GetList_品牌列表包含FieldCount()
        {
            // FANUC种子数据默认无字段映射
            var list = _service.GetList();
            var fanuc = list.FirstOrDefault(b => b.BrandName == "FANUC");
            Assert.NotNull(fanuc);
            Assert.Equal(0, fanuc.FieldCount);
        }

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

        [Fact]
        public void GetById_存在的ID_返回品牌详情()
        {
            var detail = _service.GetById(1);
            Assert.NotNull(detail);
            Assert.Equal("FANUC", detail.BrandName);
            Assert.Equal("device", detail.DeviceField);
            Assert.Equal("tags", detail.TagsPath);
        }

        [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 = _service.Create(new CreateBrandRequest
            {
                BrandName = "西门子",
                DeviceField = "siemens_device",
                TagsPath = "siemens_tags"
            });
            Assert.True(id > 0);

            var created = _service.GetById(id);
            Assert.Equal("西门子", created.BrandName);
            Assert.True(created.IsEnabled); // 默认启用
        }

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

        [Fact]
        public void Create_重复品牌名_抛出Conflict异常()
        {
            var ex = Assert.Throws<BusinessException>(() => _service.Create(new CreateBrandRequest
            {
                BrandName = "FANUC",
                DeviceField = "device",
                TagsPath = "tags"
            }));
            Assert.Equal(ErrorCode.Conflict, ex.Code);
        }

        [Fact]
        public void Create_重复品牌名大小写不同_抛出Conflict异常()
        {
            var ex = Assert.Throws<BusinessException>(() => _service.Create(new CreateBrandRequest
            {
                BrandName = "fanuc",
                DeviceField = "device",
                TagsPath = "tags"
            }));
            Assert.Equal(ErrorCode.Conflict, ex.Code);
        }

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

        [Fact]
        public void Update_正常修改_返回true()
        {
            var result = _service.Update(1, new UpdateBrandRequest
            {
                BrandName = "FANUC-修改",
                DeviceField = "new_device",
                TagsPath = "new_tags"
            });
            Assert.True(result);

            var updated = _service.GetById(1);
            Assert.Equal("FANUC-修改", updated.BrandName);
        }

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

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

        [Fact]
        public void Update_字段为null_保留原值()
        {
            var before = _service.GetById(1);
            _service.Update(1, new UpdateBrandRequest
            {
                BrandName = null,
                DeviceField = null,
                TagsPath = null
            });
            var after = _service.GetById(1);
            Assert.Equal(before.BrandName, after.BrandName);
            Assert.Equal(before.DeviceField, after.DeviceField);
            Assert.Equal(before.TagsPath, after.TagsPath);
        }

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

        [Fact]
        public void Delete_无关联采集地址_返回true()
        {
            // 先新增一个品牌
            var id = _service.Create(new CreateBrandRequest
            {
                BrandName = "待删除品牌",
                DeviceField = "del",
                TagsPath = "del"
            });
            var result = _service.Delete(id);
            Assert.True(result);
        }

        [Fact]
        public void Delete_有关联采集地址_返回false()
        {
            // 新增采集地址关联到FANUC(brand_id=1)
            TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
                VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())");

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

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

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

        [Fact]
        public void ToggleEnabled_切换启用状态()
        {
            var before = _service.GetById(1);
            var beforeState = before.IsEnabled;
            _service.ToggleEnabled(1);
            var after = _service.GetById(1);
            Assert.NotEqual(beforeState, after.IsEnabled);
        }

        // ======== Copy ========

        [Fact]
        public void Copy_正常复制_返回新品牌ID()
        {
            var newId = _service.Copy(1);
            Assert.True(newId > 0);
            Assert.NotEqual(1, newId);

            var copied = _service.GetById(newId);
            Assert.Equal("FANUC_Copy", copied.BrandName);
            Assert.Equal("device", copied.DeviceField);
            Assert.Equal("tags", copied.TagsPath);
        }

        [Fact]
        public void Copy_复制带字段映射的品牌()
        {
            // 给FANUC添加字段映射
            TestDb.Execute(@"INSERT INTO cnc_brand_field_mapping (brand_id, standard_field, field_name, match_by, data_type, is_required, created_at)
                VALUES (1, 'Field1', 'field1_name', 'exact', 'string', 1, NOW()),
                       (1, 'Field2', 'field2_name', 'exact', 'int', 0, NOW())");

            var newId = _service.Copy(1);
            var copied = _service.GetById(newId);
            Assert.Equal(2, copied.FieldCount);
        }

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

        // ======== FieldMapping IsEnabled ========
        [Fact]
        public void GetById_映射包含IsEnabled字段()
        {
            // 插入字段映射（含 is_enabled=0 的）
            TestDb.Execute(@"INSERT INTO cnc_brand_field_mapping (brand_id, standard_field, field_name, match_by, data_type, is_required, is_enabled, created_at)
                VALUES (1, 'program_name', 'Tag5', 'id', 'string', 1, 1, NOW()),
                       (1, 'spindle_load', 'Tag21', 'id', 'number', 0, 0, NOW())");
            var detail = _service.GetById(1);
            Assert.NotNull(detail.Mappings);
            Assert.Equal(2, detail.Mappings.Count);
            var disabled = detail.Mappings.FirstOrDefault(m => m.StandardField == "spindle_load");
            Assert.NotNull(disabled);
            Assert.Equal(0, disabled.IsEnabled);
        }

        [Fact]
        public void Copy_复制品牌保留映射启用状态()
        {
            // 插入字段映射（1启用1禁用）
            TestDb.Execute(@"INSERT INTO cnc_brand_field_mapping (brand_id, standard_field, field_name, match_by, data_type, is_required, is_enabled, created_at)
                VALUES (1, 'program_name', 'Tag5', 'id', 'string', 1, 1, NOW()),
                       (1, 'spindle_load', 'Tag21', 'id', 'number', 0, 0, NOW())");
            var newId = _service.Copy(1);
            var copied = _service.GetById(newId);
            Assert.Equal(2, copied.Mappings.Count);
            var enabledMapping = copied.Mappings.First(m => m.StandardField == "program_name");
            var disabledMapping = copied.Mappings.First(m => m.StandardField == "spindle_load");
            Assert.Equal(1, enabledMapping.IsEnabled);
            Assert.Equal(0, disabledMapping.IsEnabled);
        }

        [Fact]
        public void GetById_映射列表区分启用禁用()
        {
            TestDb.Execute(@"INSERT INTO cnc_brand_field_mapping (brand_id, standard_field, field_name, match_by, data_type, is_required, is_enabled, created_at)
                VALUES (1, 'f1', 'Tag1', 'id', 'string', 0, 0, NOW()),
                       (1, 'f2', 'Tag2', 'id', 'string', 0, 1, NOW()),
                       (1, 'f3', 'Tag3', 'id', 'string', 0, 1, NOW())");
            var detail = _service.GetById(1);
            Assert.Equal(3, detail.Mappings.Count);
            Assert.Equal(1, detail.Mappings.Count(m => m.IsEnabled == 0));
            Assert.Equal(2, detail.Mappings.Count(m => m.IsEnabled == 1));
        }

        // ======== GetStandardFields ========

        [Fact]
        public void GetStandardFields_返回16个标准字段()
        {
            var fields = _service.GetStandardFields();
            Assert.NotNull(fields);
            Assert.Equal(16, fields.Count);
        }

        [Fact]
        public void GetStandardFields_字段格式正确()
        {
            var fields = _service.GetStandardFields();
            Assert.Equal("Field1", fields[0].StandardField);
            Assert.Equal("Field16", fields[15].StandardField);
        }
    }
}
