using System;
using System.Collections.Generic;
using System.Linq;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Dapper;
using Siger.Middlelayer.DashboardRepository;
using Siger.Middlelayer.DashboardRepository.Entities;
using Siger.Middlelayer.KpiRespository;
using Siger.Middlelayer.Repository;

namespace Siger.ApiDashboard.Tasks
{
    public class DbHelper
    {
        private static DbHelper _helper;
        public static DbHelper Instance = _helper ?? (_helper = new DbHelper());

        private static readonly ApiDashboardDbContext DashboardContext;
        private static readonly ApiConfigDbContext ConfigContext;
        private static readonly ApiKpiDbContext KpiContext;

        static DbHelper()
        {
            DashboardContext = new ApiDashboardDbContext();
            ConfigContext = new ApiConfigDbContext();
            KpiContext = new ApiKpiDbContext();
        }

        public void AsyncData()
        {
            var date = DateTime.Now.AddDays(-1).Date;
            var factories = ConfigContext.siger_dashboard_factory.Where(q => q.status == (int) RowState.Valid).ToList();
            foreach (var factory in factories)
            {
                var summary = DashboardContext.siger_dashboard_cn_summary.FirstOrDefault(q => q.factory_id == factory.id && q.date.Date == date);
                if (summary != null)
                {
                    continue;
                }

                var safeDays = GetKpiValue(KpiItemNameKey.SafeDay, factory.project_id, date);
                var delivery = GetKpiValue(KpiItemNameKey.Delivery, factory.project_id, date);
                var complaint = GetKpiValue(KpiItemNameKey.Complaint, factory.project_id, date);
                var deliveryTartget = GetKpiTarget(KpiItemNameKey.Delivery, factory.project_id);
                var output = GetActualYield(factory.project_id, date);

                var entity = new siger_dashboard_cn_summary
                {
                    factory_id = factory.id,
                    project_id = factory.project_id,
                    date = date.Date,
                    security_days = safeDays.ToStr().ToInt(),
                    kpi_delivery = delivery,
                    kpi_delivery_target = deliveryTartget,
                    complaint_count = complaint.ToStr().ToInt(),
                    actual_output = output[0],
                    theory_output = output[1],
                    onepass_rate = 80
                };

                DashboardContext.siger_dashboard_cn_summary.Add(entity);
            }

            DashboardContext.SaveChanges();
        }

        private double GetKpiValue(string itemName, int projectId, DateTime date)
        {
            var item = from q in KpiContext.siger_project_kpi_item
                join t in KpiContext.siger_project_kpi_tasklist on q.id equals t.ItemId
                where q.Item == itemName && q.projectId == projectId && q.status == (int) RowState.Valid && t.status == (int) RowState.Valid
                      && t.Busidate.Date == date.Date
                select t;
            var value = item.FirstOrDefault();
            return value == null ? 0 : value.ActVal;
        }

        private double GetKpiTarget(string itemName, int projectId)
        {
            var item = from q in KpiContext.siger_project_kpi_item
                where q.Item == itemName && q.projectId == projectId && q.status == (int)RowState.Valid 
                select q;
            var value = item.FirstOrDefault();
            return value == null ? 0 : value.TargetVal;
        }

        private List<double> GetActualYield(int project_id, DateTime date)
        {
            var result = new List<double> {600, 650};
            var yieldRepository = new LocationYieldRepository(project_id, project_id);
            var yields = yieldRepository.GetLocationYields(string.Empty, null, date, date.AddDays(1).AddSeconds(-1));
            if (!yields.Any())
            {
                return result;
            }

            var productNames = yields.Select(m => m.productName).Distinct().ToList();
            var products = ConfigContext.siger_project_product.Where(q => productNames.Contains(q.name) && q.status == (int)RowState.Valid && q.projectid == project_id);
            if (!products.Any())
            {
                return result;
            }

            double theory = 0;
            double run = 86400;
            var productIds = products.Select(m => m.id).Distinct().ToList();
            foreach (var productId in productIds)
            {
                var route = ConfigContext.siger_project_product_route.Where(q => q.productId == productId && q.status == (int)RowState.Valid)
                    .OrderByDescending(q => q.serialNumber).FirstOrDefault();
                if (route != null && route.working_hours > 0)
                {
                    theory += run / route.working_hours;
                }
            }

            var actualOutputs = yields.Sum(m => m.yield);
            result.Add(actualOutputs);
            result.Add(theory);

            return result;
        }

        public void Dispose()
        {
            DashboardContext.Dispose();
            ConfigContext.Dispose();
            KpiContext.Dispose();
        }
    }
}
