using Performance.DtoModels;
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 PerSheetDataComputeEconomic : IAutoInjection
    {
        #region 合并科室经济
        /// <summary>
        /// 计算科室经济核算汇总表
        /// </summary>
        /// <param name="excel"></param>
        /// <returns></returns>
        public PerSheet MergeCompute(PerExcel excel, List<EntityModels.cof_income> incomeconfs)
        {
            PerSheet compSheet = new PerSheet
            {
                SheetName = "科室经济核算汇总表",
                ModuleName = "科室经济核算汇总表",
                PerHeader = new List<PerHeader>(),
                PerData = new List<IPerData>()
            };

            List<PerData> perDataList = new List<PerData>();
            //初始核算单元列头 
            compSheet.PerHeader.Add(new PerHeader { CellValue = "核算单元", Level = 0, MergeCell = 1, MergeRow = 2, PointCell = 0, PointRow = 0 });
            //起始列
            int pointCell = 1;
            //计算需从以下sheet中拿取数据
            SheetType[] types = { SheetType.Income, SheetType.OtherIncome, SheetType.Expend };
            foreach (var type in types)
            {
                //取出当前sheet类型数据
                var sheetList = excel.PerSheet.Where(t => t.SheetType == type);
                if (sheetList.Any())
                {
                    bool isHasData = false;
                    List<PerHeader> headList = new List<PerHeader>();
                    //子集列号为父级列号
                    int childPointCell = pointCell;
                    foreach (var sheet in sheetList)
                    {
                        var dataList = sheet.PerData.Select(t => (PerData)t);
                        //判断是否创建头部
                        if (!isHasData && dataList != null && dataList.Count() > 0)
                            isHasData = true;
                        foreach (var item in EnumHelper.GetItems<UnitType>().Where(t => t.Value <= 3))
                        {
                            var group = dataList.Where(t => t.UnitType == item.Name);

                            var typeName = $"{GetCleanSheetName(sheet.SheetName)}({item.Name})";
                            //创建子集头部信息
                            PerHeader childHeader = new PerHeader(1, childPointCell, typeName, 1, 1, 1, null, 2);
                            headList.Add(childHeader);

                            var ds = group.Where(t => !string.IsNullOrWhiteSpace(t.AccountingUnit) && t.CellValue.HasValue)
                                .GroupBy(t => t.AccountingUnit).Select(t => new PerData
                                {
                                    SignID = childHeader.SignID,
                                    UnitType = item.Name,
                                    AccountingUnit = t.Key,
                                    CellValue = ComputeValue(t, sheet.SheetName, item.Name, incomeconfs),
                                    TypeName = typeName,
                                    RowNumber = dataList.FirstOrDefault(s => s.AccountingUnit == t.Key && s.UnitType == item.Name)?.RowNumber ?? 0,
                                    ComputRule = type == SheetType.Expend ? 2 : 1
                                });

                            perDataList.AddRange(ds);
                            childPointCell++;
                        }
                    }
                    if (isHasData)
                    {
                        PerHeader header = new PerHeader(0, pointCell, EnumHelper.GetDescription(type), 1, 1, headList.Count, headList, 2);
                        compSheet.PerHeader.Add(header);
                    }

                    //父级列号为当前列号+子集个数
                    pointCell = pointCell + headList.Count;
                }
            }
            int number = 0;
            foreach (var accountingUnit in perDataList.OrderBy(t => t.RowNumber).Select(t => t.AccountingUnit).Distinct())
            {
                perDataList.Where(t => t.AccountingUnit == accountingUnit).ToList().ForEach(item => item.RowNumber = number);
                number++;
            }
            compSheet.PerData.AddRange(perDataList);

            return compSheet;
        }

        private decimal? ComputeValue(IGrouping<string, PerData> group, string sheetName, string unit, List<EntityModels.cof_income> incomeconfs)
        {
            var value = group.Sum(s => s.IsFactor ? (s.CellValue * (s.FactorValue ?? 0)) : s.CellValue);
            foreach (var conf in incomeconfs)
            {
                if (sheetName.Contains(conf.SheetNameKeyword) && conf.UnitName == unit)
                {
                    value = value * conf.Value;
                }
            }

            return value;
        }

        private string GetCleanSheetName(string sheetName)
        {
            sheetName = sheetName.Trim()
               .Replace("医生组", "")
               .Replace("护理组", "")
               .Replace(" ", "")
               .Replace(".", "");

            sheetName = Regex.Replace(sheetName, @"\d", "");

            return sheetName;
        }

        #endregion

        #region 一次汇总
        /// <summary>
        /// 计算科室经济核算一次汇总表
        /// </summary>
        /// <param name="excel"></param>
        /// <returns></returns>
        public PerSheet OnceCompute(PerSheet sheet)
        {
            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.Children.ForEach(item => item.PointCell = item.PointCell + phead);
                     phead = phead + 3;
                }
            }

            List<PerHeader> perHeadList = new List<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(0, maxcell + 1, $" {header.CellValue}合计", 0, 1, 3, new List<PerHeader>(), 1);
                    perHeadList.Add(parentHead);

                    var typeClass = dataList.Where(t => header.Children.Select(s => s.CellValue).Contains(t.TypeName));
                    int pointcell = 0;
                    foreach (var item in EnumHelper.GetItems<UnitType>().Where(t => t.Value <= 3))
                    {
                        pointcell++;
                        var group = typeClass.Where(t => t.UnitType == item.Name);

                        var childHead = new PerHeader(1, maxcell + pointcell, item.Name, 1, 1, 1, null, 1);
                        parentHead.Children.Add(childHead);
                        var ds = group.Where(t => t.CellValue.HasValue)
                            .GroupBy(t => t.AccountingUnit).Select(t => new PerData
                            {
                                UnitType = item.Name,
                                AccountingUnit = t.Key,
                                CellValue = t.Sum(s => s.CellValue),
                                TypeName = item.Name,
                                RowNumber = t.FirstOrDefault()?.RowNumber ?? 0,
                                IsTotal = 1,
                                PointCell = maxcell + pointcell,
                                ComputRule = t.Select(s => s.ComputRule).Distinct().First(),
                                SignID = childHead.SignID,
                            });
                        perDataList.AddRange(ds);
                    }
                }
            }
            sheet.PerHeader.AddRange(perHeadList);
            sheet.PerData.AddRange(perDataList);
            return sheet;
        }
        #endregion

        #region 二次计算
        /// <summary>
        /// 二次计算
        /// </summary>
        /// <param name="sheet"></param>
        /// <returns></returns>
        public (PerSheet Sheet, List<PerData> PerData) TwiceCompute(PerSheet sheet)
        {
            //获取最大列坐标位置
            var maxhead = sheet.PerHeader.OrderByDescending(t => t.PointCell).FirstOrDefault();
            int thiscell = maxhead.Children != null && maxhead.Children.Count > 0
                ? maxhead.Children.Max(t => t.PointCell) + 1
                : maxhead.PointCell;
            PerHeader perHead = new PerHeader(0, thiscell, "科室可核算业绩收入", 0, 1, 3, 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 => t.UnitType);
            foreach (var group in groupList)
            {
                var childHead = new PerHeader(1, thiscell, group.Key, 1, 1, 1, null, 1);
                perHead.Children.Add(childHead);
                var ds = group.GroupBy(t => t.AccountingUnit).Select(t => new PerData
                {
                    UnitType = group.Key,
                    AccountingUnit = t.Key,
                    CellValue = t.Sum(s => s.ComputRule == 2 ? s.CellValue * -1 : s.CellValue),
                    TypeName = group.Key,
                    RowNumber = t.FirstOrDefault()?.RowNumber ?? 0,
                    IsTotal = 1,
                    PointCell = thiscell,
                    ComputRule = t.Select(s => s.ComputRule).Distinct().First(),
                    SignID = childHead.SignID,
                });
                perDataList.AddRange(ds);
                thiscell++;
            }
            sheet.PerHeader.Add(perHead);
            sheet.PerData.AddRange(perDataList);
            return (sheet, perDataList);
        }
        #endregion
    }
}
