using Microsoft.Extensions.Logging;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Performance.Services
{
    public class ReportService : IAutoInjection
    {
        private readonly ILogger<ReportService> logger;
        private PerforReportRepository perforReportRepository;
        private PerforPerallotRepository perforPerallotRepository;
        private PerforResbaiscnormRepository perforResbaiscnormRepository;
        private PerforHospersonfeeRepository perforHospersonfeeRepository;
        private PerforResaccountRepository perforResaccountRepository;
        private PerforRepimportconfigRepository repimportconfigRepository;

        public ReportService(
            ILogger<ReportService> logger,
            PerforReportRepository perforReportRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforHospersonfeeRepository perforHospersonfeeRepository,
            PerforRepimportconfigRepository repimportconfigRepository,
            PerforResaccountRepository perforResaccountRepository)
        {
            this.logger = logger;
            this.perforReportRepository = perforReportRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this.perforHospersonfeeRepository = perforHospersonfeeRepository;
            this.perforResaccountRepository = perforResaccountRepository;
            this.repimportconfigRepository = repimportconfigRepository;
        }

        /// <summary>
        /// 月群体人均绩效
        /// </summary>
        /// <returns></returns>
        public List<PerReport> GetAvgPerfor(int hospitalid)
        {
            return perforReportRepository.GetAvgPerfor(hospitalid);
        }

        /// <summary>
        /// 人群绩效比
        /// </summary>
        /// <returns></returns>
        public List<PerReport> AvgRatio(int hospitalid)
        {
            return perforReportRepository.AvgRatio(hospitalid);
        }

        /// <summary>
        /// 首页数据概况
        /// </summary>
        /// <param name="request"></param>
        public dynamic Survey(int hospitalId)
        {
            var states = new List<int>() { 6, 8 };
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
            if (allotList == null || !allotList.Any())
                throw new PerformanceException("用户未创建绩效！");

            var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).FirstOrDefault();
            var keyvalue = new Dictionary<string, decimal>();
            var basicList = perforResbaiscnormRepository.GetEntities(t => t.AllotID == allot.ID && t.PositionName.IndexOf("保底") < 0);
            if (basicList != null)
            {
                foreach (var basic in basicList)
                {
                    keyvalue.Add(basic.PositionName, Math.Round(basic.AvgValue.Value, 2));
                }
            }
            return new
            {
                year = allot.Year,
                month = allot.Month,
                avgperfor = keyvalue
            };
        }

        /// <summary>
        /// 科室医生人均绩效（含科主任）
        /// </summary>
        /// <returns></returns>
        public List<PerReport> DoctorAvg(int hospitalId, int isIndex)
        {
            var states = new List<int>() { 6, 8 };
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
            if (allotList == null || !allotList.Any())
                throw new PerformanceException("用户未创建绩效！");

            var result = new List<PerReport>();
            var doctorList = perforResaccountRepository.GetEntities(t => t.UnitType != (int)UnitType.护理组 && allotList.Select(a => a.ID).Contains(t.AllotID.Value));
            if (isIndex == 1)
            {
                var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).FirstOrDefault();
                doctorList = perforResaccountRepository.GetEntities(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allot.ID);
            }
            if (doctorList == null)
                return result;
            var s = from a in allotList
                    join d in doctorList on a.ID equals d.AllotID into data
                    from t in data
                    select new PerReport
                    {
                        Y = a.Year + "-" + a.Month.ToString().PadLeft(2, '0'),
                        X = t.AccountingUnit,
                        Value = Math.Round(t.Avg.Value, 2)
                    };
            return s.OrderBy(t => t.Y).ThenByDescending(t => t.Value).ToList();
        }

        /// <summary>
        /// 科室护理人均绩效（含护士长）
        /// </summary>
        /// <returns></returns>
        public List<PerReport> NurseAvg(int hospitalId, int isIndex)
        {
            var states = new List<int>() { 6, 8 };
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
            if (allotList == null || !allotList.Any())
                throw new PerformanceException("用户未创建绩效！");

            var result = new List<PerReport>();
            var doctorList = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && allotList.Select(a => a.ID).Contains(t.AllotID.Value));
            if (isIndex == 1)
            {
                var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).FirstOrDefault();
                doctorList = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allot.ID);
            }
            if (doctorList == null)
                return result;
            var s = from a in allotList
                    join d in doctorList on a.ID equals d.AllotID into data
                    from t in data
                    select new PerReport
                    {
                        Y = a.Year + "-" + a.Month.ToString().PadLeft(2, '0'),
                        X = t.AccountingUnit,
                        Value = Math.Round(t.Avg.Value, 2)
                    };
            return s.OrderBy(t => t.Y).ThenByDescending(t => t.Value).ToList();
        }

        /// <summary>
        /// 门诊患者均次费用
        /// </summary>
        /// <returns></returns>
        public List<PerReport> OutFeeAvg(int hospitalId)
        {
            var states = new List<int>() { 6, 8 };
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
            if (allotList == null || !allotList.Any())
                throw new PerformanceException("用户未创建绩效！");

            var date = new List<string>();
            date = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).Take(6).Select(t => t.Year + "-" + t.Month.ToString().PadLeft(2, '0')).ToList();
            return perforReportRepository.OutFeeAvg(hospitalId, date);
        }

        /// <summary>
        /// 住院患者均次费用
        /// </summary>
        /// <returns></returns>
        public List<PerReport> InpatFeeAvg(int hospitalId)
        {
            var states = new List<int>() { 6, 8 };
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
            if (allotList == null || !allotList.Any())
                throw new PerformanceException("用户未创建绩效！");

            var date = new List<string>();
            date = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).Take(6).Select(t => t.Year + "-" + t.Month.ToString().PadLeft(2, '0')).ToList();
            return perforReportRepository.InpatFeeAvg(hospitalId, date);
        }

        ///// <summary>
        ///// 科室药占比
        ///// </summary>
        ///// <returns></returns>
        //public List<PerReport> Medicine(int hospitalId, int isIndex)
        //{
        //    var states = new List<int>() { 6, 8 };
        //    var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
        //    if (allotList == null || !allotList.Any())
        //        throw new PerformanceException("用户未创建绩效！");

        //    var date = new List<string>();
        //    if (isIndex == 1)
        //    {
        //        var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).FirstOrDefault();
        //        date.Add(allot.Year + "-" + allot.Month.ToString().PadLeft(2, '0'));
        //    }
        //    else
        //    {
        //        date = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).Take(6).Select(t => t.Year + "-" + t.Month.ToString().PadLeft(2, '0')).ToList();
        //    }
        //    return perforReportRepository.Medicine(hospitalId, date);
        //}

        ///// <summary>
        ///// 科室有效收入占比
        ///// </summary>
        ///// <returns></returns>
        //public List<PerReport> Income(int hospitalId, int isIndex)
        //{
        //    var states = new List<int>() { 6, 8 };
        //    var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
        //    if (allotList == null || !allotList.Any())
        //        throw new PerformanceException("用户未创建绩效！");

        //    var date = new List<string>();
        //    if (isIndex == 1)
        //    {
        //        var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).FirstOrDefault();
        //        date.Add(allot.Year + "-" + allot.Month.ToString().PadLeft(2, '0'));
        //    }
        //    else
        //    {
        //        date = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).Take(6).Select(t => t.Year + "-" + t.Month.ToString().PadLeft(2, '0')).ToList();
        //    }
        //    return perforReportRepository.Income(hospitalId, date);
        //}

        /// <summary>
        /// 只支持EXCEL抽取报表数据
        /// </summary>
        /// <param name="allot"></param>
        /// <returns></returns>
        internal int ImportData(per_allot allot)
        {
            Dictionary<string, object> pairs = new Dictionary<string, object>
            {
                { "@allotid", allot.ID },
                { "@hospitalid", allot.HospitalId },
                { "@year", allot.Year },
                { "@month", allot.Month },
            };
            var imports = repimportconfigRepository.GetEntities(w => w.ScriptType == 2);
            foreach (var item in imports)
            {
                try
                {
                    var flag = perforPerallotRepository.ImportData(item, pairs);
                }
                catch (Exception ex)
                {
                    logger.LogError(ex.ToString());
                }
            }
            return 0;
        }

        /// <summary>
        /// 补充报表数据
        /// </summary>
        /// <param name="allot"></param>
        /// <returns></returns>
        internal int UpdateData(per_allot allot)
        {
            Dictionary<string, object> pairs = new Dictionary<string, object>
            {
                { "@allotid", allot.ID },
                { "@hospitalid", allot.HospitalId },
                { "@year", allot.Year },
                { "@month", allot.Month },
            };
            var imports = repimportconfigRepository.GetEntities(w => w.ScriptType == 3);
            foreach (var item in imports)
            {
                try
                {
                    var flag = perforPerallotRepository.UpdateData(item, pairs);
                }
                catch (Exception ex)
                {
                    logger.LogError(ex.ToString());
                }
            }
            return 0;
        }

        /// <summary>
        /// 首页
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <returns></returns>
        public List<PerReport> IndexReport(int hospitalId, string source)
        {
            var states = new List<int>() { 6, 8 };
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId && states.Contains(t.States));
            if (allotList == null || !allotList.Any())
                throw new PerformanceException("用户未创建绩效！");

            var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).FirstOrDefault();
            var currentDate = allot.Year + "-" + allot.Month.ToString().PadLeft(2, '0');    //本月
            var yoyDate = (allot.Year - 1) + "-" + allot.Month.ToString().PadLeft(2, '0');  //同比
            var chainDate = allot.Year + "-" + (allot.Month - 1).ToString().PadLeft(2, '0');    //环比

            var report = new List<PerReport>();
            switch (source)
            {
                case "医院收入结构占比":
                    report = perforReportRepository.InHosIncome(hospitalId, currentDate);
                    break;

                case "绩效发放金额":
                    report = perforReportRepository.PerforPayment(hospitalId, currentDate, yoyDate, chainDate);
                    break;

                case "绩效发放金额占全院收入占比":
                    report = perforReportRepository.IndexPerforRatio(hospitalId, currentDate, yoyDate, chainDate);
                    break;

                case "药占比":
                    report = perforReportRepository.IndexDrugRatio(hospitalId, currentDate, yoyDate, chainDate);
                    break;

                case "材料占比":
                    report = perforReportRepository.IndexMaterialRatio(hospitalId, currentDate, yoyDate, chainDate);
                    break;

                case "结构占比":
                    report = perforReportRepository.IndexStructRatio(hospitalId, currentDate);
                    break;
            }

            return report;
        }

        /// <summary>
        /// 菜单
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <returns></returns>
        public List<PerReport> MenuReport(ReportRequest request)
        {
            var report = new List<PerReport>();
            switch (request.Source)
            {
                case "业务总收入":
                    report = perforReportRepository.GeneralIncome(request);
                    break;

                case "门诊住院业务收入占比":
                    report = perforReportRepository.InHosIncome(request);
                    break;

                case "业务收入结构占比":
                    report = perforReportRepository.StructRatio(request);
                    break;

                case "药占比":
                    report = perforReportRepository.DrugRatio(request);
                    break;

                case "材料占比":
                    report = perforReportRepository.MaterialRatio(request);
                    break;

                case "绩效发放金额占全院收入占比":
                    report = perforReportRepository.PerforRatio(request);
                    break;

                case "绩效群体收入":
                    report = perforReportRepository.PerforGroup(request);
                    break;

                case "医生核算单元人均绩效":
                    report = perforReportRepository.DoctorAvg(request);
                    break;

                case "护理核算单元人均绩效":
                    report = perforReportRepository.NurseAvg(request);
                    break;
            }

            return report;
        }

        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="allot"></param>
        /// <returns></returns>
        public void ExecProc(string execsql, object param)
        {
            try
            {
                perforPerallotRepository.Execute(execsql, param, 60 * 60);
            }
            catch (Exception ex)
            {
                logger.LogError($"执行存储过程时发生异常，sql：{execsql}；参数：{JsonHelper.Serialize(param)}；异常：{ex.Message}；");
            }
        }
    }
}
