using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using Xunit;
using CncModels.Entity;
using CncCollector.Core;

namespace CncCollector.Tests
{
    /// <summary>
    /// DataParser 单元测试
    /// 覆盖：正常解析、空JSON、缺失字段、非法数值、多品牌映射
    /// </summary>
    public class DataParserTests
    {
        /// <summary>创建标准 FANUC 品牌配置</summary>
        private static Brand CreateFanucBrand()
        {
            return new Brand { DeviceField = "device", TagsPath = "tags" };
        }

        /// <summary>创建16条标准 FANUC 字段映射</summary>
        private static List<BrandFieldMapping> CreateFanucMappings()
        {
            return new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "program_name", FieldName = "Tag5", DataType = "string" },
                new BrandFieldMapping { StandardField = "part_count", FieldName = "Tag8", DataType = "number" },
                new BrandFieldMapping { StandardField = "runtime", FieldName = "Tag9", DataType = "number" },
                new BrandFieldMapping { StandardField = "start_value", FieldName = "Tag11", DataType = "number" },
                new BrandFieldMapping { StandardField = "angle", FieldName = "Tag14", DataType = "number" },
                new BrandFieldMapping { StandardField = "feed", FieldName = "Tag17", DataType = "number" },
                new BrandFieldMapping { StandardField = "rpm", FieldName = "Tag18", DataType = "number" },
                new BrandFieldMapping { StandardField = "spindle", FieldName = "Tag19", DataType = "number" },
                new BrandFieldMapping { StandardField = "speed", FieldName = "Tag20", DataType = "number" },
                new BrandFieldMapping { StandardField = "temperature", FieldName = "Tag21", DataType = "number" },
                new BrandFieldMapping { StandardField = "mass", FieldName = "Tag22", DataType = "number" },
                new BrandFieldMapping { StandardField = "height", FieldName = "Tag23", DataType = "number" },
                new BrandFieldMapping { StandardField = "width", FieldName = "Tag24", DataType = "number" },
                new BrandFieldMapping { StandardField = "length", FieldName = "Tag25", DataType = "number" },
                new BrandFieldMapping { StandardField = "custom_code", FieldName = "Tag26", DataType = "string" },
                new BrandFieldMapping { StandardField = "io_status", FieldName = "_io_status", DataType = "number" }
            };
        }

        /// <summary>构造标准 FANUC 设备 JSON 对象</summary>
        private static JObject BuildFanucDeviceJson()
        {
            var json = @"[
              {
                ""device"": ""CNC-A001"",
                ""desc"": ""测试机床"",
                ""tags"": [
                  { ""id"": ""_io_status"", ""value"": ""1.00000"" },
                  { ""id"": ""Tag5"", ""value"": ""O0001"" },
                  { ""id"": ""Tag8"", ""value"": ""1219.00000"" },
                  { ""id"": ""Tag9"", ""value"": ""3.00000"" },
                  { ""id"": ""Tag11"", ""value"": ""1.00000"" },
                  { ""id"": ""Tag14"", ""value"": ""100.00000"" },
                  { ""id"": ""Tag17"", ""value"": ""300.00000"" },
                  { ""id"": ""Tag18"", ""value"": ""60.00000"" },
                  { ""id"": ""Tag19"", ""value"": ""450.00000"" },
                  { ""id"": ""Tag20"", ""value"": ""60.00000"" },
                  { ""id"": ""Tag21"", ""value"": ""25.00000"" },
                  { ""id"": ""Tag22"", ""value"": ""23558160.00000"" },
                  { ""id"": ""Tag23"", ""value"": ""18224.00000"" },
                  { ""id"": ""Tag24"", ""value"": ""6848959.00000"" },
                  { ""id"": ""Tag25"", ""value"": ""699.00000"" },
                  { ""id"": ""Tag26"", ""value"": ""G01"" }
                ]
              }
            ]";
            var arr = JArray.Parse(json);
            return arr[0] as JObject;
        }

        // ===== 正常解析测试 =====

        [Fact]
        public void ParseDevice_正常FANUC数据_解析出所有映射字段()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = CreateFanucBrand();
            var mappings = CreateFanucMappings();

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.NotNull(result);
            Assert.Equal(16, result.Count);

            // 验证字符串字段
            Assert.Equal("O0001", result["program_name"].StringValue);
            Assert.Equal("G01", result["custom_code"].StringValue);

            // 验证数值字段
            Assert.True(result["part_count"].NumericValue.HasValue);
            Assert.Equal(1219m, result["part_count"].NumericValue.Value);
            Assert.True(result["runtime"].NumericValue.HasValue);
            Assert.Equal(3m, result["runtime"].NumericValue.Value);

            // 验证所有映射字段都存在
            foreach (var key in mappings.Select(m => m.StandardField))
            {
                Assert.True(result.ContainsKey(key), $"字段 {key} 未在结果中找到");
            }
        }

        [Fact]
        public void ParseDevice_数值型字段_正确解析为decimal()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = CreateFanucBrand();
            var mappings = new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "part_count", FieldName = "Tag8", DataType = "number" }
            };

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.True(result["part_count"].NumericValue.HasValue);
            Assert.Equal(1219m, result["part_count"].NumericValue.Value);
            Assert.Equal("1219.00000", result["part_count"].StringValue);
        }

        [Fact]
        public void ParseDevice_字符串型字段_保留原始值()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = CreateFanucBrand();
            var mappings = new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "program_name", FieldName = "Tag5", DataType = "string" }
            };

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.Equal("O0001", result["program_name"].StringValue);
        }

        // ===== 空值和null 测试 =====

        [Fact]
        public void ParseDevice_deviceObj为null_返回空字典()
        {
            var brand = CreateFanucBrand();
            var mappings = CreateFanucMappings();

            var result = DataParser.ParseDevice(null, brand, mappings);

            Assert.NotNull(result);
            Assert.Empty(result);
        }

        [Fact]
        public void ParseDevice_mappings为null_返回空字典()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = CreateFanucBrand();

            var result = DataParser.ParseDevice(deviceObj, brand, null);

            Assert.NotNull(result);
            Assert.Empty(result);
        }

        [Fact]
        public void ParseDevice_mappings为空列表_返回空字典()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = CreateFanucBrand();

            var result = DataParser.ParseDevice(deviceObj, brand, new List<BrandFieldMapping>());

            Assert.NotNull(result);
            Assert.Empty(result);
        }

        // ===== 缺失字段测试 =====

        [Fact]
        public void ParseDevice_tags路径不存在_返回空字典()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = new Brand { DeviceField = "device", TagsPath = "nonexistent_path" };
            var mappings = CreateFanucMappings();

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.Empty(result);
        }

        [Fact]
        public void ParseDevice_部分字段不存在于tags_只返回存在的字段()
        {
            var deviceObj = BuildFanucDeviceJson();
            var brand = CreateFanucBrand();
            var mappings = new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "program_name", FieldName = "Tag5", DataType = "string" },
                new BrandFieldMapping { StandardField = "missing_field", FieldName = "Tag999", DataType = "string" },
                new BrandFieldMapping { StandardField = "part_count", FieldName = "Tag8", DataType = "number" }
            };

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.Equal(2, result.Count);
            Assert.True(result.ContainsKey("program_name"));
            Assert.True(result.ContainsKey("part_count"));
            Assert.False(result.ContainsKey("missing_field"));
        }

        // ===== 非法数值测试 =====

        [Fact]
        public void ParseDevice_数值字段值非法_NumericValue为null()
        {
            var json = @"[{ ""device"": ""D1"", ""tags"": [{ ""id"": ""Tag8"", ""value"": ""not_a_number"" }] }]";
            var deviceObj = JArray.Parse(json)[0] as JObject;
            var brand = new Brand { DeviceField = "device", TagsPath = "tags" };
            var mappings = new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "part_count", FieldName = "Tag8", DataType = "number" }
            };

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.True(result.ContainsKey("part_count"));
            Assert.Null(result["part_count"].NumericValue);
            Assert.Equal("not_a_number", result["part_count"].StringValue);
        }

        [Fact]
        public void ParseDevice_数值字段为空字符串_NumericValue为null()
        {
            var json = @"[{ ""device"": ""D1"", ""tags"": [{ ""id"": ""Tag8"", ""value"": """" }] }]";
            var deviceObj = JArray.Parse(json)[0] as JObject;
            var brand = new Brand { DeviceField = "device", TagsPath = "tags" };
            var mappings = new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "part_count", FieldName = "Tag8", DataType = "number" }
            };

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.True(result.ContainsKey("part_count"));
            Assert.Null(result["part_count"].NumericValue);
        }

        // ===== ExtractDeviceCode 测试 =====

        [Fact]
        public void ExtractDeviceCode_正常JSON_返回device值()
        {
            var json = @"{ ""device"": ""fanake_1.8"" }";
            var obj = JObject.Parse(json);

            var code = DataParser.ExtractDeviceCode(obj);

            Assert.Equal("fanake_1.8", code);
        }

        [Fact]
        public void ExtractDeviceCode_自定义字段名_返回正确值()
        {
            var json = @"{ ""name"": ""myDevice"" }";
            var obj = JObject.Parse(json);

            var code = DataParser.ExtractDeviceCode(obj, "name");

            Assert.Equal("myDevice", code);
        }

        [Fact]
        public void ExtractDeviceCode_null对象_返回null()
        {
            var code = DataParser.ExtractDeviceCode(null);
            Assert.Null(code);
        }

        [Fact]
        public void ExtractDeviceCode_无device字段_返回null()
        {
            var json = @"{ ""other"": ""x"" }";
            var obj = JObject.Parse(json);

            var code = DataParser.ExtractDeviceCode(obj);

            Assert.Null(code);
        }

        // ===== 多品牌/不同结构测试 =====

        [Fact]
        public void ParseDevice_不同TagsPath_正确解析()
        {
            var json = @"[{ ""device"": ""M1"", ""data"": [{ ""id"": ""prog"", ""value"": ""P001"" }] }]";
            var deviceObj = JArray.Parse(json)[0] as JObject;
            var brand = new Brand { DeviceField = "device", TagsPath = "data" };
            var mappings = new List<BrandFieldMapping>
            {
                new BrandFieldMapping { StandardField = "program_name", FieldName = "prog", DataType = "string" }
            };

            var result = DataParser.ParseDevice(deviceObj, brand, mappings);

            Assert.Single(result);
            Assert.Equal("P001", result["program_name"].StringValue);
        }
    }
}
