using Nest;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using XYY.Data.Model.Standard.Tracking;
using System.Net;
using XYY.Common.Standard;

namespace XYY.Service.Standard.First.DB
{

    public class ESFirstDB : IFirstDB
    {
        ElasticClient Client;
        public ESFirstDB(string connfig)
        {
            string esNodeUrl = connfig;
            string indexName = "logistics_frist";
            Uri node = new Uri(esNodeUrl);
            ConnectionSettings settings = new ConnectionSettings(node).DefaultMappingFor<Logistics_TraceGroup>(x =>
            x.IdProperty(i => i.TrackingNumber).IndexName(indexName).TypeName("frist"));
            //600s超时
            settings.RequestTimeout(new TimeSpan(0, 0, 600));

            IIndexState indexState = new IndexState()
            {
                Settings = new IndexSettings()
                {
                    NumberOfReplicas = 0,//副本数
                    NumberOfShards = 1//分片数
                }
            };

            Client = new ElasticClient(settings);

            if (!Client.IndexExists(indexName).Exists)
            {
                Client.CreateIndex(indexName, p => p.InitializeUsing(indexState));
            }
        }

        public async Task<bool> DeleteAndUpdate(List<Logistics_TraceGroup> UpdateTraceGroups)
        {
            var descriptor = new BulkDescriptor();
            descriptor.IndexMany(UpdateTraceGroups);
            var esResult = await Client.BulkAsync(descriptor);
            if (esResult.ItemsWithErrors != null && esResult.ItemsWithErrors.Count() > 0)
            {
                MessageHelper.SendWXMsg("提单轨迹同步失败",
                    $"以下运单轨迹同步失败失败{Newtonsoft.Json.JsonConvert.SerializeObject(esResult.ItemsWithErrors.Select(x => new { TrackingNumber = x.Id, Error = x.Error.ToString() }))}",
                    new string[] { "fanlihang" });
                return false;
            }
            return true;
        }
        public async Task<bool> InsertAndUpdate(List<Logistics_TraceGroup> UpdateTraceGroups2)
        {
            var batchQty = 1000.0;
            for (int i = 0; i < Math.Ceiling(UpdateTraceGroups2.Count / batchQty); i++)
            {
                var UpdateTraceGroups = UpdateTraceGroups2.Skip(i * (int)batchQty).Take((int)batchQty).ToList();
                List<Logistics_TraceGroup> updateList = new List<Logistics_TraceGroup>();
                List<Logistics_TraceGroup> insertList = new List<Logistics_TraceGroup>();
                foreach (var item in UpdateTraceGroups)
                {
                    var response = Client.DocumentExists<Logistics_TraceGroup>(new DocumentPath<Logistics_TraceGroup>(new Id(item.TrackingNumber)));
                    if (response.Exists)
                    {
                        var response2 = await Client.GetAsync<Logistics_TraceGroup>(item.TrackingNumber);
                        if (response2.Source != null && response2.Source.List != null)
                        {
                            for (int j = item.List.Count - 1; j >= 0; j--)
                            {
                                if (response2.Source.List.Any(x => x.TriggerTime == item.List[j].TriggerTime && x.StatusString == item.List[j].StatusString))
                                {
                                    item.List.RemoveAt(j);
                                }
                            }
                            item.List.AddRange(response2.Source.List);
                        }
                        updateList.Add(item);
                    }
                    else
                    {
                        insertList.Add(item);
                    }
                }

                var descriptor = new BulkDescriptor();
                descriptor.CreateMany(insertList);
                descriptor.UpdateMany(updateList, (x, y) => new BulkUpdateOperation<Logistics_TraceGroup, Logistics_TraceGroup>(y, y));
                var result = Client.Bulk(descriptor);
            }
            return true;
        }
    }
    /// <summary>
    /// 补充轨迹的es节点
    /// </summary>
    public class ESFirstDB2 : IFirstDB2
    {
        ElasticClient Client;
        public ESFirstDB2(string connfig)
        {
            string esNodeUrl = connfig;
            string indexName = "logistics_supplement";
            Uri node = new Uri(esNodeUrl);
            ConnectionSettings settings = new ConnectionSettings(node).DefaultMappingFor<Logistics_TraceGroup>(x =>
            x.IdProperty(i => i.TrackingNumber).IndexName(indexName).TypeName("supplement"));
            //600s超时
            settings.RequestTimeout(new TimeSpan(0, 0, 600));

            IIndexState indexState = new IndexState()
            {
                Settings = new IndexSettings()
                {
                    NumberOfReplicas = 0,//副本数
                    NumberOfShards = 1//分片数
                }
            };

            Client = new ElasticClient(settings);

            if (!Client.IndexExists(indexName).Exists)
            {
                Client.CreateIndex(indexName, p => p.InitializeUsing(indexState));
            }
        }

        public async Task<bool> InsertAndUpdate(List<Logistics_TraceGroup> UpdateTraceGroups2)
        {
            var batchQty = 1000.0;
            for (int i = 0; i < Math.Ceiling(UpdateTraceGroups2.Count / batchQty); i++)
            {
                var UpdateTraceGroups = UpdateTraceGroups2.Skip(i * (int)batchQty).Take((int)batchQty).ToList();
                List<Logistics_TraceGroup> updateList = new List<Logistics_TraceGroup>();
                List<Logistics_TraceGroup> insertList = new List<Logistics_TraceGroup>();
                foreach (var item in UpdateTraceGroups)
                {
                    var response = Client.DocumentExists<Logistics_TraceGroup>(new DocumentPath<Logistics_TraceGroup>(new Id(item.TrackingNumber)));
                    if (response.Exists)
                    {
                        var response2 = await Client.GetAsync<Logistics_TraceGroup>(item.TrackingNumber);
                        if (response2.Source != null && response2.Source.List != null)
                        {
                            for (int j = item.List.Count - 1; j >= 0; j--)
                            {
                                if (response2.Source.List.Any(x => x.TriggerTime == item.List[j].TriggerTime && x.StatusString == item.List[j].StatusString))
                                {
                                    item.List.RemoveAt(j);
                                }
                            }
                            item.List.AddRange(response2.Source.List);
                        }
                        updateList.Add(item);
                    }
                    else
                    {
                        insertList.Add(item);
                    }
                }

                var descriptor = new BulkDescriptor();
                descriptor.CreateMany(insertList);
                descriptor.UpdateMany(updateList, (x, y) => new BulkUpdateOperation<Logistics_TraceGroup, Logistics_TraceGroup>(y, y));
                var result = Client.Bulk(descriptor);
            }
            return true;
        }
        public async Task<IDeleteResponse> DeleteAsync(string TrackingNumber)
        {
            return await Client.DeleteAsync<Logistics_TraceGroup>(TrackingNumber);
        }
        public async Task<bool> DeleteAndUpdate(List<Logistics_TraceGroup> UpdateTraceGroups)
        {
            var descriptor = new BulkDescriptor();
            descriptor.DeleteMany(UpdateTraceGroups);
            descriptor.CreateMany(UpdateTraceGroups);
            var result = await Client.BulkAsync(descriptor);
            return true;
        }
    }
}
