using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using XYY.Data.Model.Standard.Tracking;

namespace XYY.Service.Standard.First.DB
{

    public interface ITrackingLogDB
    {
        bool ManyInsert(List<TrackingTraceLog> list, out bool IsRepeat);

        bool ManyUpdate(List<TrackingTraceMeessageSendResult> list);
        bool ManyUpdate(List<TrackingTraceLog> list);
        List<TrackingTraceLog> GetOnlineErrors();
    }

    public class TrackingLogDB : ITrackingLogDB
    {
        ElasticClient Client;
        public TrackingLogDB(string connfig)
        {
            string esNodeUrl = connfig;
            string indexName = "l_log";
            Uri node = new Uri(esNodeUrl);
            ConnectionSettings settings = new ConnectionSettings(node).DefaultMappingFor<TrackingTraceLog>(x =>
            x.IdProperty(i => i.Key).IndexName(indexName).TypeName("log"));
            //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 List<TrackingTraceLog> GetOnlineErrors()
        {
            List<TrackingTraceLog> logs = new List<TrackingTraceLog>();
            var serahResult = Client.Search<TrackingTraceLog>(s => s.Size(2000).Query(q =>

                 q.Bool(b1 =>
                     b1.Filter(f =>
                         f.Bool(b2 =>
                             b2.Must(m =>
                                 m.Term(t => t.TrackingEventType
                                 , 7)
                             , m =>
                                 m.Match(t => t.Field(f => f.SendMessage).Query("Api 返回结果:单次数量不能超过100条")
                             )))
             ))).Scroll("5m"));

            while (serahResult.Documents.Any())
            {
                foreach (var doc in serahResult.Documents)
                {
                    logs.Add(doc);
                }
                serahResult = Client.Scroll<TrackingTraceLog>("10m", serahResult.ScrollId);
            }
            return logs;
        }

        public bool ManyInsert(List<TrackingTraceLog> list, out bool IsRepeat)
        {
            var descriptor = new BulkDescriptor();
            var descriptResult = descriptor.CreateMany(list);
            var result = Client.Bulk(descriptor);
            IsRepeat = false;
            if (result.Errors || result.ServerError != null || result.ItemsWithErrors.Count() > 0)
            {
                if (result.ItemsWithErrors.Count(x => x.Status == 201 || x.Status == 409) == result.ItemsWithErrors.Count())
                {
                    IsRepeat = true;
                }
                else
                {
                    return false;
                }
                return false;
            }
            else
            {
                return true;
            }
        }

        public bool ManyUpdate(List<TrackingTraceMeessageSendResult> list)
        {
            List<TrackingTraceLog> updateList = new List<TrackingTraceLog>();
            var manyOld = Client.GetMany<TrackingTraceLog>(list.Select(x => x.Key));
            foreach (var item in manyOld)
            {
                var target = list.First(x => x.Key == item.Id);
                item.Source.SendTime = target.SendTime;
                item.Source.SendMessage = target.IsSuccess ? "ok" : target.ErrorMessage;
                item.Source.StepName = StepName.SendUser;
                updateList.Add(item.Source);
            }
            var descriptor = new BulkDescriptor();
            var descriptResult = descriptor.UpdateMany(updateList, (x, y) => new BulkUpdateOperation<TrackingTraceLog, TrackingTraceLog>(y, y));
            var result = Client.Bulk(descriptor);
            if (result.Errors || result.ServerError != null || result.ItemsWithErrors.Count() > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public bool ManyUpdate(List<TrackingTraceLog> list)
        {
            var descriptor = new BulkDescriptor();
            var descriptResult = descriptor.UpdateMany(list, (x, y) => new BulkUpdateOperation<TrackingTraceLog, TrackingTraceLog>(y, y));
            var result = Client.Bulk(descriptor);
            if (result.Errors || result.ServerError != null || result.ItemsWithErrors.Count() > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}
