using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Performance.Services
{
    /// <summary>
    /// 工作量
    /// </summary>
    public class PerSheetDataComputeWorkload : IAutoInjection
    {
        #region 工作量一次计算
        /// <summary>
        /// 工作量一次计算
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="confs">药占比分值</param>
        /// <returns></returns>
        public PerSheet OnceCompute(PerSheet sheet, List<CofDrugProp> confs = null)
        {
            var dataList = sheet.PerData.Select(t => (PerData)t);
            int phead = 0;
            //修改cell坐标，为新增合计预留位置
            foreach (var header in sheet.PerHeader)
            {
                if (header.IsHasChildren)
                {
                    header.PointCell = header.PointCell + phead;
                    header.MergeCell = header.MergeCell + 1;
                    header.Children.ForEach(item => item.PointCell = item.PointCell + phead);
                    phead = phead + 1;
                }
            }

            Dictionary<string, PerHeader> perHead = new Dictionary<string, PerHeader>();
            List<PerData> perDataList = new List<PerData>();
            //插入合计结果
            foreach (var header in sheet.PerHeader)
            {
                if (header.IsHasChildren)
                {
                    var maxcell = header.Children.Max(t => t.PointCell);
                    var parentHead = new PerHeader(1, maxcell + 1, $" {header.CellValue}合计", 0, 1, 1, new List<PerHeader>(), 1);
                    perHead.Add(header.SignID, parentHead);

                    var typeClass = dataList.Where(t => header.Children.Select(s => s.CellValue).Contains(t.TypeName));
                    int pointcell = 0;

                    foreach (var group in typeClass.GroupBy(t => t.UnitType))
                    {
                        var ds = group.Where(t => t.CellValue.HasValue)
                            .GroupBy(t => t.AccountingUnit).Select(t => new PerData
                            {
                                UnitType = group.Key,
                                AccountingUnit = t.Key,
                                CellValue = ComputValue(header, confs, t),
                                TypeName = group.Key,
                                RowNumber = t.FirstOrDefault()?.RowNumber ?? 0,
                                IsTotal = 1,
                                PointCell = maxcell + pointcell,
                                ComputRule = t.Select(s => s.ComputRule).Distinct().First(),
                                SignID = parentHead.SignID,
                            });
                        perDataList.AddRange(ds);
                    }
                }
            }
            foreach (var item in perHead.Keys)
            {
                sheet.PerHeader.FirstOrDefault(t => t.SignID == item)?.Children.Add(perHead[item]);
            }
            sheet.PerData.AddRange(perDataList);

            return sheet;
        }

        private decimal? ComputValue(PerHeader header, List<CofDrugProp> confs, IGrouping<string, PerData> group)
        {
            var value = group.Sum(s => s.IsFactor ? s.CellValue * s.FactorValue : s.CellValue);
            if (header.CellValue == "门急诊工作量")
            {
                var factor = confs.FirstOrDefault(t => t.AccountingUnit == group.Key)?.Factor ?? 0;
                value = value * factor;
            }

            return value;
        }
        #endregion


        #region 工作量二次计算
        /// <summary>
        /// 工作量二次计算
        /// </summary>
        /// <param name="sheet"></param>
        /// <returns></returns>
        public (PerSheet Sheet, List<PerData> PerData) TwiceCompute(PerSheet sheet, sys_hospital hospital,
            IEnumerable<cof_workitem> workitems, IEnumerable<CofDrugProp> medicineProps, IEnumerable<CofDrugProp> cmis, IEnumerable<CofDrugProp> inclines, bool isDoctor = false)
        {
            //获取最大列坐标位置
            int thiscell = sheet.PerHeader.OrderByDescending(t => t.PointCell).FirstOrDefault().PointCell + 1;
            PerHeader perHead = new PerHeader(0, thiscell, "工作量绩效合计", 0, 1, 1, new List<PerHeader>(), 1);

            var dataList = sheet.PerData.Select(t => (PerData)t);

            List<PerData> perDataList = new List<PerData>();
            //插入合计结果
            //var groupList = dataList.Where(t => t.IsTotal == 1 && t.CellValue.HasValue).GroupBy(t => new { t.UnitType, t.AccountingUnit });
            var groupList = dataList.Where(t => t.CellValue.HasValue).GroupBy(t => new { t.UnitType, t.AccountingUnit });
            foreach (var group in groupList)
            {
                var ds = group.Select(t =>
                {
                    var cellvalue = ComputValue(group, hospital, workitems, medicineProps, cmis, inclines, isDoctor);

                    var dto = new PerData
                    {
                        UnitType = group.Key.UnitType,
                        AccountingUnit = group.Key.AccountingUnit,
                        //CellValue = group.Sum(s => s.CellValue),
                        CellValue = cellvalue,
                        //MedicineFactor = factor,
                        TypeName = group.Key.UnitType,
                        RowNumber = group.FirstOrDefault()?.RowNumber ?? 0,
                        IsTotal = 1,
                        PointCell = thiscell,
                        ComputRule = group.Select(s => s.ComputRule).Distinct().First(),
                        SignID = perHead.SignID,
                    };
                    return dto;
                });
                perDataList.AddRange(ds);
            }
            sheet.PerHeader.Add(perHead);
            sheet.PerData.AddRange(perDataList);
            return (sheet, perDataList);
        }

        private decimal? ComputValue(IGrouping<object, PerData> group, sys_hospital hospital,
            IEnumerable<cof_workitem> workitems, IEnumerable<CofDrugProp> medicineProps, IEnumerable<CofDrugProp> cmis, IEnumerable<CofDrugProp> inclines, bool isDoctor = false)
        {
            var unittype = isDoctor
                ? new List<string> { UnitType.医生组.ToString(), UnitType.医技组.ToString(), UnitType.专家组.ToString(), UnitType.其他医生组.ToString(), UnitType.其他医技组.ToString(), UnitType.特殊核算组.ToString() }
                : new List<string> { UnitType.护理组.ToString(), UnitType.其他护理组.ToString() };

            if ((medicineProps == null && cmis == null && inclines == null) || workitems == null)
                return group.Sum(s => s.IsFactor ? s.CellValue * s.FactorValue : s.CellValue);

            decimal medicinefactor = medicineProps?.FirstOrDefault(t => t.AccountingUnit == group.First().AccountingUnit && unittype.Contains(t.UnitType))?.Factor ?? 1;
            decimal cmifactor = cmis?.FirstOrDefault(t => t.AccountingUnit == group.First().AccountingUnit && unittype.Contains(t.UnitType))?.Factor ?? 1;
            decimal inclinefactor = inclines?.FirstOrDefault(t => t.AccountingUnit == group.First().AccountingUnit && unittype.Contains(t.UnitType))?.Factor ?? 1;

            var value = group.Sum(s =>
            {
                var cellvalue = s.IsFactor ? s.CellValue * s.FactorValue : s.CellValue;
                if (workitems.Any(w => w.Type == 3 && w.Item == s.TypeName))
                    cellvalue = cellvalue * inclinefactor;
                if (workitems.Any(w => w.Type == 2 && w.Item == s.TypeName))
                    cellvalue = cellvalue * cmifactor;
                if (workitems.Any(w => w.Type == 1 && w.Item == s.TypeName))
                    cellvalue = cellvalue * medicinefactor;
                return cellvalue;
            });
            return value;
        }
        #endregion
    }
}
