using Pas.ScadaService.Model;
using Spring.Expressions;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System;
using System.Collections.Concurrent;
using NewLife.Serialization;


namespace Pas.ScadaService.Core
{
    public class GopTimeCalc
    {
        /// <summary>
        /// 点位关联
        /// </summary>
        private static readonly ConcurrentDictionary<string, List<ConditionDto>> _changeDic = new ConcurrentDictionary<string, List<ConditionDto>>();
        /// <summary>
        /// 所有时间
        /// </summary>
        private static readonly ConcurrentDictionary<string, Data> AllData = new ConcurrentDictionary<string, Model.Data>();

        private static IFreeSql Db { get; set; }
        /// <summary>
        /// 加载配置
        /// </summary>
        public static void Load(string config, string sql, List<Data> obj)
        {
            var inputObject = System.IO.File.ReadAllText(config);
            var conditionDtoList = inputObject.ToJsonEntity<List<ConditionDto>>();
            foreach (var item in conditionDtoList)
            {
                if (_changeDic.TryGetValue(HandleParam(item.Change.Replace("@(", "").Replace(")", "")), out var value))
                {
                    value.Add(item);
                }
                else
                {
                    _changeDic.TryAdd(HandleParam(item.Change.Replace("@(", "").Replace(")", "")), new List<ConditionDto> { item });
                }
            }
            //初始化数据库
            Db = new FreeSql.FreeSqlBuilder()
                .UseConnectionString(FreeSql.DataType.SqlServer, sql)
                .Build();
            //初始化数据
            InitData(obj);
        }
        /// <summary>
        /// 初始化数据事件
        /// </summary>
        /// <param name="obj"></param>
        private static void InitData(List<Data> obj)
        {
            foreach (var data in obj)
            {
                var key = HandleParam(data.ItemId);
                if (!AllData.ContainsKey(key))
                {
                    AllData.TryAdd(key, data);
                }
            }
            SyncDb(obj);
        }
        /// <summary>
        /// 监听事件
        /// </summary>
        /// <param name="obj"></param>
        public static void ChangeData(List<Data> obj)
        {
            foreach (var data in obj)
            {
                var key = HandleParam(data.ItemId);
                if (AllData.ContainsKey(key))
                {
                    AllData[key] = data;
                }
            }
            SyncDb(obj);
        }
        /// <summary>
        /// 计算点位
        /// </summary>
        /// <param name="obj"></param>
        public static List<CustomLive> CalcPoints(List<Data> obj)
        {
            var result = new List<CustomLive>();
            var resultValue = AllData
                .ToDictionary(data => data.Key,
                    data => GetValue(data.Value.Value.ToString(), data.Value.DataType));
            foreach (var data in obj)
            {
                if (!_changeDic.TryGetValue(HandleParam(data.ItemId), out var conditionDtoList)) continue;
                foreach (var conditionDto in conditionDtoList)
                {
                    var conditionValue = conditionDto.Value;
                    var conditionParams = GetConditionParams(conditionValue);
                    var tagNames = new List<string>();
                    //修正表达式
                    foreach (var conditionParam in conditionParams)
                    {
                        var replace = HandleParam(conditionParam
                            .Replace("@(", "#")
                            .Replace(")", ""));
                        tagNames.Add(replace.Substring(1));
                        conditionValue = conditionValue.Replace(conditionParam, replace);
                    }
                    var value = (bool)ExpressionEvaluator.GetValue(null, conditionValue, resultValue);
                    if (!value) continue;
                    var time = AllData.Where(c => tagNames.Contains(c.Key))
                        .Select(c => HandleTime(c.Value.TimeStamp))
                        .OrderByDescending(DateTime.Parse)
                        .FirstOrDefault();
                    result.Add(new CustomLive
                    {
                        CreateTime = DateTime.Now,
                        GroupName = "",
                        ProduceBatch = "批次未知",
                        TagName = conditionDto.Name,
                        Value = time,
                        Visible = true
                    });
                }
            }

            return result;
        }
        private static object GetValue(string value, string type)
        {
            switch (type.ToLower())
            {
                case "string":
                    return value;
                case "bool":
                    return value=="1" || value.ToLower()== "true";
                case "int":
                    return value.ToInt();
                default:
                    return value.ToDecimal();
            }
        }
        /// <summary>
        /// 处理参数
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        private static string HandleParam(string param)
        {
            return param.Replace(" ", "__").Replace(".", "___");
        }

        private static string HandleTime(string time)
        {
            var last = time.Split(':').Last();
            var lastLength = last.Length + 1;
            return time.Substring(0, time.Length - lastLength) + "." + last;
        }
        /// <summary>
        /// 解析参数
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        private static List<string> GetConditionParams(string condition)
        {
            var pattern = @"\@\((.*?)\)";
            var regex = new Regex(pattern);

            var matches = regex.Matches(condition);

            return (from Match match in matches select match.Groups[0].Value).ToList();
        }

       

        /// <summary>
        /// 同步到数据库
        /// </summary>
        /// <param name="obj"></param>
        private static void SyncDb(List<Model.Data> obj)
        {
           
            var customLives = CalcPoints(obj);
            foreach (var item in customLives)
            {
                if (Db.Queryable<CustomLive>()
                    .Where(c => c.TagName == item.TagName && c.ProduceBatch == "批次未知")
                    .Any())
                {
                    Db.Update<CustomLive>()
                        .Set(a => a.Value, item.Value)
                        .Set(a => a.CreateTime, DateTime.Now)
                        .Where(a => a.TagName == item.TagName)
                        .Where(a => a.ProduceBatch == "批次未知")
                        .ExecuteAffrows();
                }
                else
                {
                    Db.Insert(item).ExecuteAffrows();
                }
            }
        }
    }
}