using AsbCloudDb.Model;
using AsbSaubReport.Model;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AsbSaubReport
{
    public class ReportDataSourcePgCloud : IReportDataSource
    {
        private readonly AsbCloudDbContext context;

        private readonly int? idTelemetry;
        private readonly WellInfoReport info;

        private readonly Dictionary<int, TelemetryEvent> events;
        private readonly Dictionary<int, TelemetryUser> users;
        private readonly Dictionary<int, string> categories = new Dictionary<int, string>
        {
            {1, "Авария"},
            {2, "Предупреждение"},
            {3, "Информация"},
        };

        public ReportDataSourcePgCloud(AsbCloudDbContext context, int idWell)
        {
            this.context = context;
            var well = context.Wells
                .Include(w => w.Cluster)
                .ThenInclude(c => c.Deposit)
                .Include(w => w.RelationCompaniesWells)
                .ThenInclude(r => r.Company)
                .Include(w => w.Telemetry)
                .FirstOrDefault(w => w.Id == idWell);

            idTelemetry = well?.IdTelemetry;
            if (idTelemetry is null)
                throw new ArgumentException($"Well {idWell} doesn't contain telemetry", nameof(idWell));

            events = context.TelemetryEvents
             .Where(e => e.IdTelemetry == idTelemetry)
             .ToDictionary(e => e.IdEvent, e => e);

            users = context.TelemetryUsers
                .Where(u => u.IdTelemetry == idTelemetry)
                .ToDictionary(u => u.IdUser, u => u);

            info = new WellInfoReport
            {
                Deposit = well.Cluster.Deposit.Caption,
                Cluster = well.Cluster.Caption,
                Well = well.Caption,
                Customer = well.RelationCompaniesWells.FirstOrDefault(c => c.Company.IdCompanyType == 1)?.Company.Caption,
                DrillingStartDate = well.Telemetry?.Info?.DrillingStartDate ?? default,
                TimeZoneId = well.Telemetry?.Info?.TimeZoneId ?? default,
                TimeZoneOffsetTotalHours = well.Telemetry?.Info?.TimeZoneOffsetTotalHours ?? default,
            };
        }

        public AnalyzeResult Analyze()
        {
            var messagesStat = (from item in context.TelemetryMessages
                                where item.IdTelemetry == idTelemetry
                                group item.Date by item.IdTelemetry into g
                                select new { min = g.Min(), max = g.Max(), count = g.Count() })
                    .FirstOrDefault();

            var dataStat = (from item in context.TelemetryDataSaub
                            where item.IdTelemetry == idTelemetry
                            group item.Date by item.IdTelemetry into g
                            select new { min = g.Min(), max = g.Max(), count = g.Count() })
                    .FirstOrDefault();

            var result = new AnalyzeResult
            {
                MinDate = dataStat?.min ?? messagesStat?.min ?? default,
                MaxDate = dataStat?.max ?? messagesStat?.max ?? default,
                MessagesCount = messagesStat?.count ?? 0,
            };

            return result;
        }

        public IQueryable<DataSaubReport> GetDataSaubItems(DateTime begin, DateTime end)
         => from item in context.TelemetryDataSaub
            where item.IdTelemetry == idTelemetry
                && item.Date >= begin
                && item.Date <= end
            orderby item.Date
            select new DataSaubReport
            {
                Id = item.Id,
                Date = item.Date,
                Mode = item.Mode,
                WellDepth = item.WellDepth,
                BitDepth = item.BitDepth,
                BlockPosition = item.BlockPosition,
                BlockSpeed = item.BlockSpeed,
                BlockSpeedSp = item.BlockSpeedSp,
                BlockSpeedSpDevelop = item.BlockSpeedSpDevelop,
                Pressure = item.Pressure,
                PressureSp = item.PressureSp,
                AxialLoad = item.AxialLoad,
                AxialLoadSp = item.AxialLoadSp,
                AxialLoadLimitMax = item.AxialLoadLimitMax,
                HookWeight = item.HookWeight,
                RotorTorque = item.RotorTorque,
                RotorTorqueSp = item.RotorTorqueSp,
                RotorSpeed = item.RotorSpeed,
                Flow = item.Flow,
                PressureSpDevelop = item.PressureSpDevelop,
            };

        public IQueryable<MessageReport> GetMessages(DateTime begin, DateTime end)
        => from item in context.TelemetryMessages
           where item.IdTelemetry == idTelemetry
               && item.Date >= begin
               && item.Date <= end
           orderby item.Date
           select new MessageReport
           {
               Id = item.Id,
               Date = item.Date,
               Category = events.GetValueOrDefault(item.IdEvent) == null
                    ? $""
                    : categories[events[item.IdEvent].IdCategory],
               User = item.IdTelemetryUser == null
                    ? ""
                    : users.GetValueOrDefault((int)item.IdTelemetryUser) == null
                        ? $"User id{item.IdTelemetryUser}"
                        : users[(int)item.IdTelemetryUser].MakeDisplayName(),
               Text = events.GetValueOrDefault(item.IdEvent) == null 
                   ? $"Стбытие {item.IdEvent} {item.Arg0} {item.Arg1} {item.Arg2} {item.Arg3}" 
                   : events[item.IdEvent].MakeMessageText(item)
           };

        public WellInfoReport GetWellInfo()
        => info;
    }
}