using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;

using FMSAdmin.Data;
using FMSAdmin.Helpers;
using FMSAdmin.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using FMSAdmin.Models;
using System.Transactions;

namespace FMSApp.Services {
    public class ManualMeterService {
        private readonly ILogger<ManualMeterService> _logger;
        private readonly FMSContext _context;

        private readonly AppSettings _appSettings;
        private readonly StorageHelper _storage;

        public ManualMeterService(
            ILogger<ManualMeterService> logger,
            FMSContext context,
            IOptions<AppSettings> appSettings,
            StorageHelper storage
            ) {
            _logger = logger;
            _context = context;
            _appSettings = appSettings.Value;
            _storage = storage;
        }

        public void Save(BemsMonitoringPointHistoryHourly data) {
            var today = data.CreatedDateTime.Date;
            var nowHour = new DateTime(data.CreatedDateTime.Year, data.CreatedDateTime.Month, data.CreatedDateTime.Day, data.CreatedDateTime.Hour, 0, 0);
            var todayStart = new DateTime(data.CreatedDateTime.Year, data.CreatedDateTime.Month, data.CreatedDateTime.Day, 0, 0, 0);
            var tomorrowStart = todayStart.AddDays(1);

            using (var trans = new TransactionScope()) {
                var facility = _context.CmFacility.Where(x => x.SiteId == data.SiteId && x.FacilityCode == data.FacilityCode).FirstOrDefault();
                if (facility == null) throw new ServiceException("해당 설비정보를 찾을수 없습니다.");

                if (Math.Abs(data.PrevPinValue) < Double.Epsilon) {
                    throw new ServiceException("이전검침값이 입력되지 않았습니다.");
                }
                if (Math.Abs(data.CurrentPinValue) < Double.Epsilon) {
                    throw new ServiceException("검침값이 입력되지 않았습니다.");
                }

                if ((new int[] { 80, 81, 82 }).Contains(facility.FacilityTypeId)) {
                    if (Math.Abs(data.Multiple) < Double.Epsilon) throw new ServiceException("배수가 입력되지 않았습니다.");
                    data.CurrentValue = Math.Round((data.CurrentPinValue - data.PrevPinValue) * data.Multiple, 5);
                } else {
                    data.CurrentValue = Math.Round(data.CurrentPinValue - data.PrevPinValue, 5);
                }

                // save 15min raw data
                var rawData = _context.BemsMonitoringPointHistory15minRawData.Where(
                    x => x.SiteId == data.SiteId
                    && x.FacilityCode == data.FacilityCode
                    && x.PropertyId == data.PropertyId
                    && x.CreatedDateTime == nowHour
                ).FirstOrDefault();
                if (rawData == null) {
                    _context.BemsMonitoringPointHistory15minRawData.Add(new BemsMonitoringPointHistory15minRawData() {
                        SiteId = data.SiteId,
                        FacilityCode = data.FacilityCode,
                        FacilityTypeId = facility.FacilityTypeId,
                        PropertyId = data.PropertyId,
                        CreatedDateTime = nowHour,
                        CurrentValue = data.CurrentPinValue
                    });
                    _context.SaveChanges();
                } else {
                    rawData.CurrentValue = data.CurrentPinValue;
                    _context.BemsMonitoringPointHistory15minRawData.Update(rawData);
                    _context.SaveChanges();
                }

                // save hourly
                var hourly = _context.BemsMonitoringPointHistoryHourly.Where(
                    x => x.SiteId == data.SiteId
                    && x.FacilityCode == data.FacilityCode
                    && x.PropertyId == data.PropertyId
                    && x.CreatedDateTime == nowHour
                ).FirstOrDefault();
                if (hourly == null) {
                    data.FacilityTypeId = facility.FacilityTypeId;
                    _context.BemsMonitoringPointHistoryHourly.Add(data);
                    _context.SaveChanges();
                } else {
                    hourly.CurrentValue = data.CurrentValue;
                    _context.BemsMonitoringPointHistoryHourly.Update(hourly);
                    _context.SaveChanges();
                }

                // daily history update
                var dailyTotalQuery = _context.BemsMonitoringPointHistoryHourly.Where(
                    x => x.SiteId == data.SiteId
                    && x.FacilityCode == data.FacilityCode
                    && x.PropertyId == data.PropertyId
                    && x.CreatedDateTime >= todayStart
                    && x.CreatedDateTime < tomorrowStart
                );
                var dailyTotalValue = (double)(dailyTotalQuery.Sum(x => (double?)x.CurrentValue) ?? 0);
                var dailyMinValue = (double)(dailyTotalQuery.Min(x => (double?)x.CurrentValue) ?? 0);
                var dailyMaxValue = (double)(dailyTotalQuery.Max(x => (double?)x.CurrentValue) ?? 0);

                var daily = _context.BemsMonitoringPointHistoryDaily.Where(
                    x => x.SiteId == data.SiteId
                    && x.FacilityCode == data.FacilityCode
                    && x.PropertyId == data.PropertyId
                    && x.CreatedDateTime == today
                ).OrderBy(x => x.CreatedDateTime).FirstOrDefault();
                if (daily == null) {
                    daily = new BemsMonitoringPointHistoryDaily() {
                        SiteId = data.SiteId,
                        FacilityTypeId = facility.FacilityTypeId,
                        FacilityCode = data.FacilityCode,
                        PropertyId = data.PropertyId,
                        CreatedDateTime = today
                    };
                    daily.DailyValue = dailyTotalValue;
                    daily.MinValue = dailyMinValue;
                    daily.MaxValue = dailyMaxValue;
                    _context.BemsMonitoringPointHistoryDaily.Add(daily);
                } else {
                    daily.DailyValue = dailyTotalValue;
                    daily.MinValue = dailyMinValue;
                    daily.MaxValue = dailyMaxValue;
                    _context.BemsMonitoringPointHistoryDaily.Update(daily);
                }
                _context.SaveChanges();

                trans.Complete();
            }
        }

    }
}