using Elasticsearch.Net;
using Nest;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace XYY.PerformanceCount.Standard
{
    /// <summary>
    /// 日志计数服务实现
    /// </summary>
    public interface IPerformanceDB
    {
        Task AddLog(MethodPerformanceModel menthodPerformance);
        Task<IReadOnlyCollection<MethodPerformanceModel>> QueryLog(Query query);
    }

    public class ESPerformanceDB : IPerformanceDB
    {
        string indexName = "performance_count_1";
        public ESPerformanceDB(string dbConnection)
        {
            string esNodeUrl = dbConnection;
            Uri node = new Uri(esNodeUrl);
            ConnectionSettings settings = new ConnectionSettings(node).DefaultMappingFor<MethodPerformanceModel>(x =>
            x.IdProperty(i => i.Id).IndexName(indexName).TypeName("doc")).DefaultIndex(indexName);
            //3s超时
            settings.RequestTimeout(new TimeSpan(0, 0, 3));

            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));
            }
        }

        private ElasticClient _client;

        public async Task AddLog(MethodPerformanceModel menthodPerformance)
        {
            await _client.IndexDocumentAsync(menthodPerformance);
        }

        public async Task<IReadOnlyCollection<MethodPerformanceModel>> QueryLog(Query query)
        {
            if (!string.IsNullOrEmpty(query.SearchParameter))
            {
                var sq1 = new Func<QueryContainerDescriptor<MethodPerformanceModel>, QueryContainer>(q => q.Bool(b =>
                             b.Filter(f =>
                                 f.DateRange(r =>
                                     r.Field("startTime")
                                     .GreaterThanOrEquals(query.StartTime)
                                     .LessThan(query.EndTime)
                                     )
                                 ,
                                 f =>
                                    f.Bool(
                                        b2 => b2.Must(
                                            m => m.MatchPhrase(
                                                mp => mp.Field("mehtodName").Query(
                                                    query.MethodName)))),
                                 f =>
                                    f.Range(r =>
                                        r.Field("executionTime")
                                        .GreaterThanOrEquals(query.ExecutionTime)
                                 ),
                                 f =>
                                    f.Bool(
                                        b2 => b2.Must(
                                            m => m.MatchPhrase(
                                                mp => mp.Field("requestParameters").Query(
                                                    query.SearchParameter))))
                             )));
                var result = await _client.SearchAsync<MethodPerformanceModel>(s =>
                     s.Query(sq1).Size(query.Size).From(query.Size * (query.Index - 1)));
                return result.Documents;
            }
            else
            {
                var sq1 = new Func<QueryContainerDescriptor<MethodPerformanceModel>, QueryContainer>(q => q.Bool(b =>
                             b.Filter(f =>
                                 f.DateRange(r =>
                                     r.Field("startTime")
                                     .GreaterThanOrEquals(query.StartTime)
                                     .LessThan(query.EndTime)
                                     )
                                 ,
                                 f =>
                                    f.Range(r =>
                                        r.Field("executionTime")
                                        .GreaterThanOrEquals(query.ExecutionTime)
                                 ),
                                 f =>
                                    f.Bool(
                                        b2 => b2.Must(
                                            m => m.MatchPhrase(
                                                mp => mp.Query(
                                                    query.MethodName))))
                             )));
                var result = await _client.SearchAsync<MethodPerformanceModel>(s =>
                     s.Query(sq1).Size(query.Size).From(query.Size * (query.Index - 1)));
                return result.Documents;
            } 
        }
    }
}
