using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using CncModels.Entity;
using log4net;

namespace CncCollector.Core
{
    /// <summary>
    /// JSON 解析 + 字段映射引擎。
    /// 根据品牌配置从采集到的 JSON 中提取结构化字段数据。
    /// </summary>
    public class DataParser
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(DataParser));

        /// <summary>
        /// 解析后的字段容器
        /// </summary>
        public class ParsedField
        {
            /// <summary>标准字段名（如 program_name）</summary>
            public string StandardField { get; set; }

            /// <summary>字段值（字符串形式）</summary>
            public string StringValue { get; set; }

            /// <summary>数值（如果可解析为 decimal）</summary>
            public decimal? NumericValue { get; set; }

            /// <summary>数据类型（number/string）</summary>
            public string DataType { get; set; }
        }

        /// <summary>
        /// 解析单台设备的 JSON tags 数据
        /// </summary>
        /// <param name="deviceObj">设备 JSON 对象</param>
        /// <param name="brand">品牌配置</param>
        /// <param name="mappings">品牌字段映射列表</param>
        /// <returns>标准字段名 → 解析后的字段值</returns>
        public static Dictionary<string, ParsedField> ParseDevice(JObject deviceObj, Brand brand, List<BrandFieldMapping> mappings)
        {
            var result = new Dictionary<string, ParsedField>();

            if (deviceObj == null || mappings == null || mappings.Count == 0)
                return result;

            // 定位 tags 数组
            string tagsPath = brand?.TagsPath ?? "tags";
            JToken tagsToken = deviceObj.SelectToken(tagsPath);
            if (tagsToken == null || tagsToken.Type != JTokenType.Array)
            {
                _log.Warn($"无法定位 tags 数组（路径: {tagsPath}）");
                return result;
            }

            var tagsArray = tagsToken as JArray;

            // 构建 tag id → value 的快速查找字典
            var tagDict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (var tag in tagsArray)
            {
                string id = tag["id"]?.ToString() ?? "";
                string value = tag["value"]?.ToString() ?? "";
                if (!string.IsNullOrEmpty(id))
                {
                    tagDict[id] = value;
                }
            }

            // 按字段映射表提取
            foreach (var mapping in mappings)
            {
                string tagId = mapping.FieldName; // FieldName 存的是 tag 的 id（如 "Tag5"）
                string standardField = mapping.StandardField;
                string dataType = mapping.DataType ?? "string";

                string rawValue;
                if (!tagDict.TryGetValue(tagId, out rawValue))
                {
                    // 字段不存在，跳过（非必填字段可能不存在）
                    continue;
                }

                var field = new ParsedField
                {
                    StandardField = standardField,
                    DataType = dataType,
                    StringValue = rawValue
                };

                // 数值型：去除 .00000 尾缀
                if (dataType == "number" && !string.IsNullOrEmpty(rawValue))
                {
                    // 尝试解析为 decimal
                    string cleanValue = rawValue.Trim();
                    decimal numVal;
                    if (decimal.TryParse(cleanValue, System.Globalization.NumberStyles.Float,
                        System.Globalization.CultureInfo.InvariantCulture, out numVal))
                    {
                        field.NumericValue = numVal;
                    }
                }

                result[standardField] = field;
            }

            return result;
        }

        /// <summary>
        /// 从设备 JSON 对象中提取 device 字段值
        /// </summary>
        /// <param name="deviceObj">设备 JSON 对象</param>
        /// <param name="deviceField">品牌配置的 device 字段名（默认 "device"）</param>
        /// <returns>device 值</returns>
        public static string ExtractDeviceCode(JObject deviceObj, string deviceField = "device")
        {
            if (deviceObj == null) return null;
            return deviceObj[deviceField]?.ToString();
        }
    }
}
