using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Configuration;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Share.Models;

namespace Siger.Middlelayer.Log
{
    public class MongoDbClient
    {
        private readonly IMongoDatabase _database;
        private readonly MongoClient _dbClient;
        private readonly string _dbName;
        private readonly string _dbHost;
        private readonly int _dbPort;
        private readonly TimeSpan _timeout = TimeSpan.FromSeconds(5);

        private static MongoDbClient _client = new MongoDbClient();
        public static MongoDbClient Instance => _client ?? (_client = new MongoDbClient());

        public MongoDbClient()
        {
            _dbHost = ConfigManager.GetValue("MongoDbSetting", "Host", "127.0.0.1");
            _dbPort = ConfigManager.GetValue("MongoDbSetting", "Port", 27017);
            _dbName = ConfigManager.GetValue("MongoDbSetting", "DbName", "siger");
            var maxConnections = ConfigManager.GetValue("MongoDbSetting", "MaxConns", 200);

            var mongoSetting = new MongoClientSettings
            {
                ConnectTimeout = _timeout,
                Server = new MongoServerAddress(_dbHost, _dbPort),
                MaxConnectionPoolSize = maxConnections,
                WaitQueueSize = maxConnections,
                WaitQueueTimeout = _timeout
            };
            _dbClient = new MongoClient(mongoSetting);
            _database = _dbClient.GetDatabase(_dbName);
            RegisterEntities();
        }

        public IEnumerable<ResponseLog> GetLogs(LogModule module, string childmodule, string level, string content,
            DateTime start, DateTime end, out int totalCount, int page = 1, int pagesize = 10, int toexcel = 0)
        {
            var filters = Builders<LogMessage>.Filter.And(Builders<LogMessage>.Filter.Gte("Time", start), Builders<LogMessage>.Filter.Lte("Time", end));
            var moduleFilter = Builders<LogMessage>.Filter.Eq("Module", childmodule.ToInt());
            var levelFilter = Builders<LogMessage>.Filter.Eq("Level", level.ToInt());
            if (!string.IsNullOrWhiteSpace(childmodule))
            {
                filters = Builders<LogMessage>.Filter.And(filters, moduleFilter);
            }
            if (!string.IsNullOrWhiteSpace(level))
            {
                filters = Builders<LogMessage>.Filter.And(filters, levelFilter);
            }
            
            IQueryable<LogMessage> query = null;
            switch (module)
            {
                case LogModule.BigData:
                    query = BigDataLogs.Find(filters).ToList().AsQueryable();
                    break;
                case LogModule.MiddleLayer:
                    query = MiddleLayerLogs.Find(filters).ToList().AsQueryable();
                    break;
                case LogModule.DataAnalysis:
                    query = DataAnalysisLogs.Find(filters).ToList().AsQueryable();
                    break;
                case LogModule.IoT:
                    query = IoTLogs.Find(filters).ToList().AsQueryable();
                    break;
                default:
                    break;
            }

            if (query == null)
            {
                totalCount = 0;
                return new List<ResponseLog>();
            }

            var entities = QueryList(query, content, toexcel, page, pagesize, out totalCount);
            var responses = new List<ResponseLog>();
            foreach (var entity in entities)
            {
                var response = new ResponseLog
                {
                    Id = entity.Id,
                    LevelName = entity.Level.ToString(),
                    Level = (int)entity.Level,
                    Message = entity.Message,
                    Module = ConvertModule(module, entity.Module),
                    Time = entity.Time.ToLocalTime().ToString(ParameterConstant.DateTimeFormat)
                };
                responses.Add(response);
            }

            return responses;
        }

        private static string ConvertModule(LogModule module, Module category)
        {
            try
            {
                switch (module)
                {
                    case LogModule.BigData:
                        return Enum.GetName(typeof(BigDataModule), (int)category);
                    case LogModule.MiddleLayer:
                        return category.ToString();
                    case LogModule.DataAnalysis:
                        return Enum.GetName(typeof(BigDataModule), (int)category);
                    case LogModule.IoT:
                        return Enum.GetName(typeof(IoTModule), (int)category);
                    default:
                        break;
                }
            }
            catch
            {
                return string.Empty;
            }
            return string.Empty;
        }

        private static IEnumerable<LogMessage> QueryList(IQueryable<LogMessage> query, string content, int toexcel, int page, int pagesize, out int totalCount)
        {
            List<LogMessage> entities;
            if (!string.IsNullOrWhiteSpace(content))
            {
                query = query.Where(q => q.Message.Contains(content));
            }

            if (toexcel == 0)
            {
                totalCount = query.Count();
                entities = query.OrderByDescending(s => s.Time).Skip((page - 1) * pagesize).Take(pagesize).ToList();
            }
            else
            {
                totalCount = 0;
                entities = query.OrderByDescending(s => s.Time).ToList();
            }

            return entities;
        }

        public IEnumerable<LogMessage> GetBigDataLatestLogs(int interval, string level, string module, string content)
        {
            var start = DateTime.Now.AddMinutes(-interval);
            var filters = Builders<LogMessage>.Filter.And(Builders<LogMessage>.Filter.Gte("Time", start), Builders<LogMessage>.Filter.Lte("Time", DateTime.Now));
            var moduleFilter = Builders<LogMessage>.Filter.Eq("Module", module);
            var levelFilter = Builders<LogMessage>.Filter.Eq("Level", level);
            if (!string.IsNullOrWhiteSpace(module))
            {
                filters = Builders<LogMessage>.Filter.And(filters, moduleFilter);
            }
            if (!string.IsNullOrWhiteSpace(level))
            {
                filters = Builders<LogMessage>.Filter.And(filters, levelFilter);
            }

            var query1 = BigDataLogs.Find(filters).ToList().AsQueryable();
            if (!string.IsNullOrWhiteSpace(content))
            {
                query1 = query1.Where(q => q.Message.Contains(content));
            }
            var entities = query1.OrderBy(s => s.Time).ToList();
            return entities;
        }

        private IMongoCollection<T> GetCollection<T>(string collectionName)
        {
            return _database.GetCollection<T>(collectionName);
        }

        private void RegisterEntities()
        {
            MiddleLayerLogs = GetCollection<LogMessage>("MiddleLayerLogs");

            BigDataLogs = GetCollection<LogMessage>("BigDataLogs");

            DataAnalysisLogs = GetCollection<LogMessage>("DataAnalysisLogs");

            IoTLogs = GetCollection<LogMessage>("IoTLogs");
        }

        public IMongoCollection<LogMessage> MiddleLayerLogs { get; private set; } //中间层

        public IMongoCollection<LogMessage> BigDataLogs { get; private set; } //大数据

        public IMongoCollection<LogMessage> DataAnalysisLogs { get; private set; } //数分

        public IMongoCollection<LogMessage> IoTLogs { get; private set; } //数采
    }
}
