using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Masuit.Tools;
using Newtonsoft.Json;
using Masuit.Tools.Systems;
using NPOI.Util;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using static Performance.Services.ExtractExcelService.WriteDataHelper;
using System.Drawing;
using Microsoft.Extensions.Configuration;

namespace Performance.Services
{
    public partial class ComputeService : IAutoInjection
    {
        /// <summary>
        /// 查询科室详情，返回统一格式
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="unitType"></param>
        /// <param name="accountingUnit"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public UniteDeptDetailResponse UniteDeptDetail(int allotId, UnitType unitType, string accountingUnit, int userId)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null) throw new PerformanceException("绩效月信息错误");
            //当角色对应时过滤
            var userInfo = _userRepository.GetUser(userId);

            var account = perforResaccountRepository.GetEntity(t => t.AllotID == allotId && t.UnitType == (int)unitType && t.AccountingUnit == accountingUnit);
            account ??= new res_account
            {
                AllotID = allotId,
                UnitType = (int)unitType,
                AccountingUnit = accountingUnit,
                Number = 0,
                BasicFactor = 0,
                Extra = 0,
                AssessBeforeOtherFee = 0,
                MedicineExtra = 0,
                MaterialsExtra = 0,
                ScoringAverage = 0,
                AssessLaterOtherFee = 0,
                AdjustFactor = 0,
                AdjustLaterOtherFee = 0,
                RealGiveFee = 0,
            };

            var ignore = _configuration.GetSection("UniteDeptDetailIgnore").Get<string[]>() ?? Array.Empty<string>();
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == allotId) ?? new List<per_sheet>();
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == allotId) ?? new List<im_header>();
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == allotId && t.AccountingUnit == accountingUnit) ?? new List<im_data>();

            var response = new UniteDeptDetailResponse
            {
                Title = $"{allot.Name ?? $"{allot.Year}年{allot.Month}月"} {unitType} {accountingUnit}",
                UnitType = unitType.ToString(),
                AccountingUnit = accountingUnit,
                DetailItems = new List<DeptDetailItem>()
            };
            // 行政工勤
            if (UnitTypeUtil.IsOffice(response.UnitType))
            {
                var detailItems = new List<DeptDetailItem>();
                #region 补全行政工勤人员明细
                {
                    var items = new List<Dictionary<string, object>>();
                    var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountType == AccountUnitType.行政工勤.ToString() && t.AccountingUnit == accountingUnit) ?? new List<res_compute>();
                    foreach (var item in computes)
                    {
                        items.Add(new Dictionary<string, object>
                        {
                            { "工号", item.JobNumber },
                            { "姓名", item.EmployeeName },
                            { "系数", ValueFormating(item.PostCoefficient,"") },
                            { "出勤", ValueFormating(item.Attendance, UniteDept.Format.两位小数百分比.ToString()) },
                            { "其他绩效", ValueFormating(item.OtherPerfor,"") },
                            { "绩效合计",  ValueFormating(item.PerforTotal,UniteDept.Format.两位小数.ToString()) },
                        });
                    }
                    detailItems.Add(new DeptDetailItem { Title = "行政工勤", Total = account.PerforTotal ?? 0, TotalFormat = ValueFormating(account.PerforTotal ?? 0, ""), Items = items });
                }
                #endregion

                #region 补全6.11个人岗位系数
                {
                    var items = new List<Dictionary<string, object>>();
                    var postSheet = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.PersonPostCoefficient);
                    if (postSheet != null)
                    {
                        var postDatas = basicData?.Where(w => w.SheetID == postSheet.ID && w.AccountingUnit == account?.AccountingUnit);
                        foreach (var post in postDatas?.GroupBy(w => new { w.JobNumber }))
                        {
                            var row = new Dictionary<string, object>
                            {
                                { "工号", post.Key.JobNumber },
                                { "姓名", post.FirstOrDefault()?.EmployeeName },
                            };
                            foreach (var item in post.Where(w => w.IsTotal != 1))
                            {
                                var val = item.IsFactor == 1 ? (item.CellValue * (item.FactorValue ?? 0)) : item.CellValue;
                                row.AddOrUpdate(item.TypeName, ValueFormating(val, ""), ValueFormating(val, ""));
                            }
                            var amount = post.FirstOrDefault(w => w.IsTotal == 1)?.CellValue ?? 0;
                            row.AddOrUpdate("合计", ValueFormating(amount, ""), ValueFormating(amount, ""));
                            items.Add(row);
                        }
                        var totalValue = basicData.Where(t => t.SheetID == postSheet.ID && t.UnitType == (int)SheetType.PersonPostCoefficient && t.IsTotal == 1)?.Sum(t => t.CellValue) ?? 0;
                        detailItems.Add(new DeptDetailItem { Title = "岗位系数", Total = totalValue, TotalFormat = ValueFormating(totalValue, ""), Items = items });
                    }
                }
                #endregion

                #region 特殊处理
                var total = detailItems.FirstOrDefault(w => w.Title == "行政工勤")?.Total ?? 0;

                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.业绩分值.ToString(), Total = 0 });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.业绩绩效.ToString(), Total = total, Children = detailItems });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.工作量绩效.ToString(), Total = 0 });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.考核前绩效.ToString(), Total = total });
                #endregion
            }
            else if (UnitTypeUtil.Is(response.UnitType, UnitType.特殊核算组.ToString()))
            {
                var special = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId && t.Department == accountingUnit);
                if (special?.Any() != true) return response;

                var detailItems = new List<DeptDetailItem>();
                #region 补全特殊核算组量化指标明细
                {
                    var items = new List<Dictionary<string, object>>();
                    foreach (var item in special)
                    {
                        items.Add(new Dictionary<string, object>
                        {
                            { "量化指标", item.QuantitativeIndicators },
                            { "数量", ValueFormating(item.Quantity, "")  },
                            { "量化指标绩效分值", ValueFormating(item.QuantitativeIndicatorsValue, "") },
                            { "工作量绩效", ValueFormating(item.QuantitativeFee, UniteDept.Format.两位小数.ToString()) },
                        });
                    }

                    detailItems.Add(new DeptDetailItem { Title = "量化考核", Total = special.First().ResultsTotalFee ?? 0, TotalFormat = ValueFormating(special.First().ResultsTotalFee ?? 0, ""), Items = items });
                }
                #endregion

                #region 特殊处理
                var total = detailItems.FirstOrDefault(w => w.Title == "量化考核")?.Total ?? 0;

                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.业绩分值.ToString(), Total = 0 });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.业绩绩效.ToString(), Total = 0 });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.工作量绩效.ToString(), Total = total, Children = detailItems });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.考核前绩效.ToString(), Total = special.First().PerforTotal ?? 0 });
                #endregion
            }
            else
            {
                var detailItems = new List<DeptDetailItem>();
                #region 补全临床科室收入明细
                {
                    var leftSheetTypes = new List<int> { (int)SheetType.Income, (int)SheetType.OtherIncome, (int)SheetType.Expend, };
                    foreach (var sheetType in leftSheetTypes)
                    {
                        foreach (var sheet in persheet.Where(t => t.SheetType == sheetType).OrderBy(w => w.SheetName))
                        {
                            var type = TypeConversion(account.UnitType);
                            var sheetName = BeautifulName(sheet.SheetName);


                            var items = new List<Dictionary<string, object>>();
                            var postDatas = basicData.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1 && t.UnitType == (int)type);
                            if (postDatas?.Any() != true) continue;
                            var headersDatas = headers.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1).ToList();
                            postDatas = from temp1 in postDatas
                                        join temp2 in headersDatas on temp1.TypeName equals temp2.CellValue
                                        orderby temp2.PointCell ascending
                                        select temp1;

                            foreach (var post in postDatas.GroupBy(t => new { t.TypeName }))
                            {
                                if (ignore.Contains(post.Key.TypeName)) continue;

                                var lhfz = post.Sum(group => group.CellValue);
                                var hsfz = post.Sum(group => group.IsFactor == 1 ? (group.CellValue * (group.FactorValue ?? 0)) : group.CellValue);
                                var row = new Dictionary<string, object>
                                {
                                    { "量化指标", post.Key.TypeName },
                                    { "量化分值", ValueFormating(lhfz, "") },
                                    { "核算比例", ValueFormating(post.FirstOrDefault().FactorValue, UniteDept.Format.两位小数百分比.ToString()) },
                                    { "核算分值", ValueFormating(hsfz, "") },
                                };
                                items.Add(row);
                            }
                            #region 添加合计
                            {
                                var lhfz = postDatas.Sum(w => w.CellValue);
                                var hsfz = postDatas.Sum(w => w.IsFactor == 1 ? (w.CellValue * (w.FactorValue ?? 0)) : w.CellValue);
                                items.Add(new Dictionary<string, object>
                                {
                                    {  "量化指标", "原始分值合计"},
                                    {  "量化分值", ValueFormating(lhfz, "") },
                                    {  "核算比例", "核算分值合计"},
                                    {  "核算分值", ValueFormating(hsfz, "") },
                                });
                            }
                            #endregion

                            var amount = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal != 1)?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
                            detailItems.Add(new DeptDetailItem { Title = sheetName, Total = amount, TotalFormat = ValueFormating(amount, ""), Items = items });
                        }
                    }
                }
                #endregion

                var detailItemWorkloads = new List<DeptDetailItem>();
                #region 补全临床科室工作量明细
                {
                    foreach (var sheet in persheet.Where(t => t.SheetType == (int)SheetType.Workload))
                    {
                        if ((sheet.SheetName.Contains("医生") && account.UnitType == (int)UnitType.护理组) || (sheet.SheetName.Contains("护理") && account.UnitType != (int)UnitType.护理组))
                            continue;

                        string sheetName = BeautifulName(sheet.SheetName);

                        var type = TypeConversion(account.UnitType);

                        var workitems = cofworkitemRepository.GetEntities(t => t.AllotID == allotId);
                        var medicineFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadMedicineProp);
                        var cmiFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadCMI);
                        var inclineFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadIncline);

                        var items = new List<Dictionary<string, object>>();

                        var unitTypes = new int[] { (int)UnitType.医生组, (int)UnitType.医技组, (int)UnitType.其他医技组 };
                        var postDatas = (unitTypes.Contains((int)type))
                            ? basicData.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1 && unitTypes.Contains(t.UnitType.Value))
                            : basicData.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1 && t.UnitType == (int)type);
                        if (postDatas?.Any() != true) continue;
                        var headersDatas = headers.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1).ToList();
                        postDatas = from temp1 in postDatas
                                    join temp2 in headersDatas on temp1.TypeName equals temp2.CellValue
                                    orderby temp2.PointCell ascending
                                    select temp1;
                        foreach (var post in postDatas.GroupBy(t => new { t.TypeName }))
                        {
                            if (ignore.Contains(post.Key.TypeName)) continue;

                            var itemValue = post.Sum(group => group.IsFactor == 1 ? (group.CellValue * (group.FactorValue ?? 0)) : group.CellValue);
                            itemValue = itemValue * (medicineFactor ?? 1) * (cmiFactor ?? 1) * (inclineFactor ?? 1);
                            var row = new Dictionary<string, object>
                            {
                                { "项目", post.Key.TypeName },
                                { "数量", ValueFormating(post.Sum(group => group.CellValue), "") },
                                { "系数", ValueFormating(post.FirstOrDefault().FactorValue, "") },
                                { "药占比系数", "" },
                                { "CMI系数", "" },
                                { "工作量倾斜", "" },
                                { "金额", ValueFormating(itemValue, "") }
                            };

                            if (workitems != null && workitems.Any(a => a.Type == 1 && a.Item == post.Key.TypeName) && medicineFactor != null)
                                row.AddOrUpdate("药占比系数", ValueFormating(medicineFactor, ""));
                            if (workitems != null && workitems.Any(a => a.Type == 2 && a.Item == post.Key.TypeName) && cmiFactor != null)
                                row.AddOrUpdate("CMI系数", ValueFormating(cmiFactor, ""));
                            if (workitems != null && workitems.Any(a => a.Type == 3 && a.Item == post.Key.TypeName) && inclineFactor != null)
                                row.AddOrUpdate("工作量倾斜", ValueFormating(inclineFactor, ""));

                            items.Add(row);
                        }
                        items.Add(new Dictionary<string, object>
                        {
                            { "项目", "核算分值合计"},
                            { "数量", "" },
                            { "系数", "" },
                            { "药占比系数", "" },
                            { "CMI系数", "" },
                            { "工作量倾斜", "" },
                            { "金额", ValueFormating(postDatas.Sum(w => w.IsFactor == 1 ? (w.CellValue * (w.FactorValue ?? 0)) : w.CellValue),"") },
                        });
                        DeleteBlankColumn(items);

                        var amount = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal != 1)?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
                        detailItemWorkloads.Add(new DeptDetailItem { Title = sheetName, Total = amount, TotalFormat = ValueFormating(amount, ""), Items = items });
                    }
                }
                #endregion

                #region 特殊处理
                string remark = "";
                if (allot.ShowFormula == 1)
                {
                    var sr = string.Join(" + ", persheet.Where(t => t.SheetType == (int)SheetType.Income).Select(w => BeautifulName(w.SheetName)));
                    var ewsr = string.Join(" + ", persheet.Where(t => t.SheetType == (int)SheetType.OtherIncome).Select(w => BeautifulName(w.SheetName)));
                    var zc = string.Join(" - ", persheet.Where(t => t.SheetType == (int)SheetType.Expend).Select(w => BeautifulName(w.SheetName)));
                    remark = $"{sr} + {ewsr} - {zc}";
                }
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.业绩分值.ToString(), Total = account.Income ?? 0, Children = detailItems });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.业绩绩效.ToString(), Total = account.PerforFee ?? 0 });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.工作量绩效.ToString(), Total = account.WorkloadFee ?? 0, Children = detailItemWorkloads });
                response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.考核前绩效.ToString(), Total = account.PerforTotal ?? 0 });
                #endregion
            }

            // 只显示合计没有详情
            response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.考核后绩效.ToString(), Total = account.AssessLaterPerforTotal ?? 0 });
            response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.考核后其他绩效.ToString(), Total = account.AssessLaterOtherFee ?? 0 });
            response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.调节系数.ToString(), Total = account.AdjustFactor ?? 1 });
            response.DetailItems.Add(new DeptDetailItem { Title = UniteDept.Title.实发绩效.ToString(), Total = account.RealGiveFee ?? 0 });

            // 加载用户设置
            var settings = GetUniteDeptDetailSetting(allotId);
            // 显示详情 
            #region 补全公共附属表明细
            {
                var rightSheetTypeMaps = new DeptDetailItem[]
                {
                    new DeptDetailItem { Title = UniteDept.Title.预算比例.ToString(), SheetType = SheetType.BudgetRatio, Total = account.BasicFactor ?? 0, },
                    new DeptDetailItem { Title = UniteDept.Title.医院奖罚.ToString(), SheetType = SheetType.AccountExtra, Total = account.Extra ?? 0, },
                    new DeptDetailItem { Title = UniteDept.Title.考核前其他绩效.ToString(), SheetType = SheetType.AssessBeforeOtherFee, Total = account.AssessBeforeOtherFee ?? 0, },
                    new DeptDetailItem { Title = UniteDept.Title.药占比奖罚.ToString(), SheetType = SheetType.AccountDrugAssess, Total = account.MedicineExtra ?? 0, },
                    new DeptDetailItem { Title = UniteDept.Title.材料占比奖罚.ToString(), SheetType = SheetType.AccountMaterialsAssess, Total = account.MaterialsExtra ?? 0, },
                    new DeptDetailItem { Title = UniteDept.Title.考核得分率.ToString(), SheetType = SheetType.AccountScoreAverage, Total = account.ScoringAverage ?? 0, },
                    new DeptDetailItem { Title = UniteDept.Title.调节后其他绩效.ToString(), SheetType = SheetType.AccountAdjustLaterOtherFee, Total = account.AdjustLaterOtherFee ?? 0, },
                };
                foreach (var detail in rightSheetTypeMaps)
                {
                    response.DetailItems.Add(detail);

                    foreach (var sheet in persheet.Where(t => t.SheetType == (int)detail.SheetType))
                    {
                        var type = TypeConversion(account.UnitType);
                        var sheetName = BeautifulName(sheet.SheetName);

                        var items = new List<Dictionary<string, object>>();
                        var postDatas = basicData.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1 && t.UnitType == (int)type);

                        var headersDatas = headers.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1).ToList();
                        postDatas = from temp1 in postDatas
                                    join temp2 in headersDatas on temp1.TypeName equals temp2.CellValue
                                    orderby temp2.PointCell ascending
                                    select temp1;
                        foreach (var post in postDatas.GroupBy(t => new { t.TypeName }))
                        {
                            if (ignore.Contains(post.Key.TypeName)) continue;

                            var settingItem = settings.FirstOrDefault(w => w.Title == detail.Title) ?? new UniteDeptDetailItem() { Children = new List<UniteDeptDetailItem>() };
                            var gs = settingItem.Children.FirstOrDefault(w => w.Title == post.Key.TypeName) ?? new UniteDeptDetailItem { Format = "" };
                            if (string.IsNullOrEmpty(gs.Display))
                                gs.Display = UniteDept.DisplayRule.始终显示.ToString();

                            if (gs.Display == UniteDept.DisplayRule.始终隐藏.ToString()) continue;

                            var states = new int[] { (int)AllotStates.绩效下发, (int)AllotStates.归档 };
                            if (gs.Display == UniteDept.DisplayRule.下发显示.ToString() && userInfo.IsSecondAdmin && !states.Contains(allot.States)) continue;

                            var fz = post.Sum(group => group.IsFactor == 1 ? (group.CellValue * (group.FactorValue ?? 0)) : group.CellValue);
                            var row = new Dictionary<string, object>
                            {
                                { "指标", post.Key.TypeName },
                                { "分值", ValueFormating(fz, gs.Format) },
                                { "说明", gs.Remark },
                            };
                            items.Add(row);
                        }
                        DeleteBlankColumn(items);
                        var amount = basicData?.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0;
                        detail.Total = amount;
                        detail.Items = items;
                    }
                }
            }
            #endregion

            // 应用用户设置的显示规则
            foreach (var detail in response.DetailItems)
            {
                detail.Display = true;

                var cfg = settings.FirstOrDefault(w => w.Title == detail.Title);
                // 部分左右侧显示全部格式化
                detail.TotalFormat = ValueFormating(detail.Total, cfg?.Format);
                // 只对右侧设置排序
                detail.Sort = cfg == null ? detail.Sort : cfg.Sort;
                // 备注
                detail.Remark = allot.ShowFormula == 1 ? cfg?.Remark : null;
                // 只对科室查看时右侧并且未下发隐藏内容
                if (cfg?.Display == UniteDept.DisplayRule.始终隐藏.ToString())
                {
                    detail.Display = false;
                }
                else if (cfg?.Display == UniteDept.DisplayRule.下发显示.ToString())
                {
                    if (userInfo.IsSecondAdmin && allot.States != (int)AllotStates.绩效下发 && allot.States != (int)AllotStates.归档)
                    {
                        detail.Display = false;
                    }
                }
            }

            response.DetailItems = response.DetailItems.OrderBy(w => w.Sort).ToList();

            return response;
        }
        /// <summary>
        /// 删除空白列
        /// </summary>
        /// <param name="items"></param>
        private static void DeleteBlankColumn(List<Dictionary<string, object>> items)
        {
            // 保证Key数量一致
            var keys = items.SelectMany(dict => dict.Keys).Distinct();
            foreach (var k in keys)
            {
                var values = items.SelectMany(dict => dict.Where(kvp => kvp.Key == k).Select(kvp => kvp.Value));
                if (!values.Any(w => !string.IsNullOrEmpty(w?.ToString())))
                {
                    foreach (var item in items)
                    {
                        item.Remove(k);
                    }
                }
            }
        }

        // 详情页面数值格式化
        private string ValueFormating(decimal? value, string format)
        {
            var total = value ?? 0;
            if (total == 0)
            {
                return string.Format("{0:0.####}", total);
            }
            else
            {
                if (format == UniteDept.Format.整数百分比.ToString())
                {
                    return string.Format("{0:0%}", total);
                }
                else if (format == UniteDept.Format.一位小数百分比.ToString())
                {
                    return string.Format("{0:0.#%}", total);
                }
                else if (format == UniteDept.Format.两位小数百分比.ToString())
                {
                    return string.Format("{0:0.##%}", total);
                }
                else if (format == UniteDept.Format.三位小数百分比.ToString())
                {
                    return string.Format("{0:0.###%}", total);
                }
                else if (format == UniteDept.Format.四位小数百分比.ToString())
                {
                    return string.Format("{0:0.####%}", total);
                }
                else if (Math.Abs(total) < 1.5m)
                {
                    return string.Format("{0:0.####}", total);
                }
                else if (format == UniteDept.Format.整数.ToString())
                {
                    return Math.Round(total, 0, MidpointRounding.AwayFromZero).ToString();
                }
                else if (format == UniteDept.Format.一位小数.ToString())
                {
                    total = Math.Round(total, 1, MidpointRounding.AwayFromZero);
                    return string.Format("{0:0.####}", total);
                }
                else if (format == UniteDept.Format.两位小数.ToString())
                {
                    total = Math.Round(total, 2, MidpointRounding.AwayFromZero);
                    return string.Format("{0:0.####}", total);
                }
                else if (format == UniteDept.Format.三位小数.ToString())
                {
                    total = Math.Round(total, 3, MidpointRounding.AwayFromZero);
                    return string.Format("{0:0.####}", total);
                }
                else if (format == UniteDept.Format.四位小数.ToString())
                {
                    total = Math.Round(total, 3, MidpointRounding.AwayFromZero);
                    return string.Format("{0:0.####}", total);
                }
                return string.Format("{0:0.####}", total);
            }
        }
        private string BeautifulName(string sheetName)
        {
            sheetName = new Regex("[0-9]*").Replace(sheetName, "", 5).Replace(".", "").Replace(" ", "");
            sheetName = sheetName != "科室考核" ? sheetName.Replace("科室绩效", "").Replace("科室", "") : sheetName;
            return sheetName;
        }

        /// <summary>
        /// 查询显示设置内容
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        /// <exception cref="PerformanceException"></exception>
        public List<UniteDeptDetailItem> GetUniteDeptDetailSetting(int allotId)
        {

            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null) throw new PerformanceException("绩效月信息错误");

            var ignore = _configuration.GetSection("UniteDeptDetailIgnore").Get<string[]>() ?? Array.Empty<string>();
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == allotId) ?? new List<per_sheet>();
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == allotId) ?? new List<im_header>();
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == allotId) ?? new List<im_data>();

            var response = new List<UniteDeptDetailItem>() { };

            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.业绩分值.ToString(), Format = UniteDept.Format.整数.ToString(), });
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.业绩绩效.ToString(), Format = UniteDept.Format.整数.ToString(), Remark = "业绩分值 * 预算比例" });
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.工作量绩效.ToString(), Format = UniteDept.Format.整数.ToString(), });
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.考核前绩效.ToString(), Format = UniteDept.Format.整数.ToString(), });
            // 只显示合计没有详情
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.考核后绩效.ToString(), Format = UniteDept.Format.整数.ToString(), Remark = "考核前绩效 × 考核得分率 + 药占比奖罚 + 材料占比奖罚 + 医院奖罚 + 考核后其他绩效" });
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.考核后其他绩效.ToString(), Format = UniteDept.Format.整数.ToString(), });
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.调节系数.ToString(), Format = UniteDept.Format.两位小数百分比.ToString(), });
            response.Add(new UniteDeptDetailItem { Title = UniteDept.Title.实发绩效.ToString(), Format = UniteDept.Format.整数.ToString(), Remark = "考核后绩效 × 调节系数 + 调节后其他绩效" });

            // 显示详情 
            #region 补全公共附属表明细  
            var rightSheetTypeMaps = new List<UniteDeptDetailItem>()
            {
                new UniteDeptDetailItem { Title = UniteDept.Title.预算比例.ToString(), SheetType = (int)SheetType.BudgetRatio, Format = UniteDept.Format.两位小数百分比.ToString(), },
                new UniteDeptDetailItem { Title = UniteDept.Title.医院奖罚.ToString(), SheetType = (int)SheetType.AccountExtra, Format = UniteDept.Format.整数.ToString(), },
                new UniteDeptDetailItem { Title = UniteDept.Title.考核前其他绩效.ToString(), SheetType = (int)SheetType.AssessBeforeOtherFee, Format = UniteDept.Format.整数.ToString(), },
                new UniteDeptDetailItem { Title = UniteDept.Title.药占比奖罚.ToString(), SheetType = (int)SheetType.AccountDrugAssess, Format = UniteDept.Format.整数.ToString(), },
                new UniteDeptDetailItem { Title = UniteDept.Title.材料占比奖罚.ToString(), SheetType = (int)SheetType.AccountMaterialsAssess, Format = UniteDept.Format.整数.ToString(), },
                new UniteDeptDetailItem { Title = UniteDept.Title.考核得分率.ToString(), SheetType = (int)SheetType.AccountScoreAverage, Format = UniteDept.Format.两位小数百分比.ToString(), },
                new UniteDeptDetailItem { Title = UniteDept.Title.调节后其他绩效.ToString(), SheetType = (int)SheetType.AccountAdjustLaterOtherFee, Format = UniteDept.Format.整数.ToString(), },
            };
            foreach (var detail in rightSheetTypeMaps)
            {
                response.Add(detail);
                foreach (var sheet in persheet.Where(t => t.SheetType == detail.SheetType))
                {
                    var sheetName = BeautifulName(sheet.SheetName);

                    var items = new List<UniteDeptDetailItem>();
                    var postDatas = basicData.Where(t => t.SheetID == sheet.ID && t.IsTotal != 1);
                    foreach (var post in postDatas.GroupBy(t => new { t.TypeName }))
                    {
                        if (ignore.Contains(post.Key.TypeName)) continue;
                        items.Add(new UniteDeptDetailItem { Title = post.Key.TypeName });
                    }
                    detail.Children = items;
                }
            }
            #endregion

            var entity = _perforCofDeptDetailRepository.GetEntity(w => w.AllotId == allotId);
            var cofDeptDetail = string.IsNullOrEmpty(entity?.Settings)
                ? new List<UniteDeptDetailItem>()
                : JsonHelper.Deserialize<List<UniteDeptDetailItem>>(entity.Settings);

            var enumItems = EnumHelper.GetItems<UniteDept.Title>();
            foreach (var detail in response)
            {
                detail.Id = SnowFlake.GetInstance().GetLongId().ToString();
                detail.Display = UniteDept.DisplayRule.始终显示.ToString();
                detail.Children ??= new List<UniteDeptDetailItem>();
                foreach (var item in detail.Children)
                {
                    item.Id = SnowFlake.GetInstance().GetLongId().ToString();
                    item.ParentId = detail.Id;
                    item.Display = UniteDept.DisplayRule.始终显示.ToString();
                }

                var cfg = enumItems.FirstOrDefault(w => w.Name == detail.Title);
                // 只对右侧设置排序
                detail.Sort = cfg == null ? detail.Sort : cfg.Value;
                // 读取数据库保存内容
                var temp1 = cofDeptDetail.FirstOrDefault(w => w.Title == detail.Title);
                if (temp1 != null)
                {
                    detail.Remark = temp1.Remark;
                    detail.Format = temp1.Format;
                    detail.Sort = temp1.Sort;
                    detail.Display = temp1.Display;
                    foreach (var item in detail.Children)
                    {
                        var temp2 = temp1.Children.FirstOrDefault(w => w.Title == item.Title);
                        if (temp2 != null)
                        {
                            item.Remark = temp2.Remark;
                            item.Format = temp2.Format;
                            item.Sort = temp2.Sort;
                            item.Display = temp2.Display;
                        }
                    }
                    foreach (var item2 in temp1.Children)
                    {
                        if (!detail.Children.Any(w => w.Title == item2.Title))
                            detail.Children.Add(item2);
                    }
                }
            }

            response = response.OrderBy(w => w.Sort).ToList();
            return response;
        }
        public void SaveUniteDeptDetailSetting(int allotId, List<UniteDeptDetailItem> request)
        {
            var entity = _perforCofDeptDetailRepository.GetEntity(w => w.AllotId == allotId);
            if (entity == null)
            {
                entity = new cof_dept_detail { AllotId = allotId, CreateTime = DateTime.Now, Settings = JsonHelper.Serialize(request) };
                _perforCofDeptDetailRepository.Add(entity);
            }
            else
            {
                entity.Settings = JsonHelper.Serialize(request);
                _perforCofDeptDetailRepository.Update(entity);
            }
        }

        #region 科室详情下载
        public string ExcelDownload(UniteDeptDetailResponse uniteDeptDetail, string name, int allotId)
        {
            var dpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Files");
            if (!Directory.Exists(dpath)) Directory.CreateDirectory(dpath);

            string filepath = Path.Combine(dpath, $"{name}{DateTime.Now:yyyy年MM月dd日}");
            if (File.Exists(filepath)) File.Delete(filepath);

            using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate))
            using (ExcelPackage package = new ExcelPackage(fs))
            {
                var worksheet = package.Workbook.Worksheets.Add(uniteDeptDetail.Title);
                worksheet.View.ShowGridLines = false;

                var maxColIndex = GetMaxColumnIndex(0, uniteDeptDetail.DetailItems);
                worksheet.SetValue(1, 1, uniteDeptDetail.Title);
                worksheet.Cells[1, 1, 1, maxColIndex].Merge = true;
                worksheet.Cells[1, 1, 1, maxColIndex].Style.Font.Bold = true;
                worksheet.Cells[1, 1, 1, maxColIndex].Style.Font.Size = 18;
                worksheet.Cells[1, 1, 1, maxColIndex].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                worksheet.Cells[1, 1, 1, maxColIndex].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                worksheet.Cells[1, 1, 1, maxColIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                worksheet.Cells[1, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
                worksheet.Cells[1, 1].Style.Fill.BackgroundColor.SetColor(Color.GhostWhite);
                var rowIndex = 1;
                WriteSheetCells(worksheet, maxColIndex, rowIndex, uniteDeptDetail.DetailItems);
                worksheet.Cells.AutoFitColumns();
                int lastColumnIndex = worksheet.Dimension.End.Column;
                worksheet.Column(lastColumnIndex).Width = 20;
                package.Save();
            }
            return filepath;
        }

        int WriteSheetCells(ExcelWorksheet worksheet, int maxColIndex, int rowIndex, List<DeptDetailItem> detailItems)
        {
            foreach (var item in detailItems.Where(w => w.Display))
            {
                ++rowIndex;
                worksheet.SetValue(rowIndex, 1, $"{item.Title} :  {item.TotalFormat}");
                if (!string.IsNullOrEmpty(item.Remark))
                {
                    worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].AddComment(item.Remark, "System");
                }
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Merge = true;
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Font.Bold = true;
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Font.Size = 14;
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Fill.PatternType = ExcelFillStyle.Solid;
                worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Fill.BackgroundColor.SetColor(Color.GhostWhite);
                if (item.Children?.Any() == true)
                {
                    rowIndex = WriteSheetCells(worksheet, maxColIndex, rowIndex, item.Children);
                }
                else if (item.Items?.Any() == true)
                {
                    rowIndex = rowIndex + 1;
                    var headers = item.Items.FirstOrDefault().Keys.Select(w => w);
                    for (int colIndex = 0; colIndex < headers.Count(); colIndex++)
                    {
                        worksheet.SetValue(rowIndex, colIndex + 1, headers.ElementAt(colIndex));

                        worksheet.Cells[rowIndex, colIndex + 1].Style.Font.Bold = true;
                        worksheet.Cells[rowIndex, colIndex + 1].Style.Font.Size = 11;
                        worksheet.Cells[rowIndex, colIndex + 1].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                        worksheet.Cells[rowIndex, colIndex + 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                        worksheet.Cells[rowIndex, colIndex + 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                        worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Fill.PatternType = ExcelFillStyle.Solid;
                        worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Fill.BackgroundColor.SetColor(Color.GhostWhite);
                        if (colIndex + 1 == headers.Count())
                        {
                            worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Merge = true;

                            worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.Font.Bold = true;
                            worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.Font.Size = 11;
                            worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                            worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                            worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                            worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Fill.PatternType = ExcelFillStyle.Solid;
                            worksheet.Cells[rowIndex, 1, rowIndex, maxColIndex].Style.Fill.BackgroundColor.SetColor(Color.GhostWhite);
                        }
                    }
                    foreach (var row in item.Items)
                    {
                        rowIndex = rowIndex + 1;
                        for (int colIndex = 0; colIndex < headers.Count(); colIndex++)
                        {
                            var cellValue = row[headers.ElementAt(colIndex)]?.ToString() ?? ""; // 获取单元格的值
                            double numericValue = 0;
                            if (cellValue.EndsWith("%") && double.TryParse(cellValue.Replace("%", ""), out numericValue))
                            {
                                worksheet.SetValue(rowIndex, colIndex + 1, numericValue / 100);
                                worksheet.Cells[rowIndex, colIndex + 1].Style.Numberformat.Format = "0.00%";
                            }
                            else if (double.TryParse(cellValue, out numericValue) && cellValue.Length != 18)
                            {
                                worksheet.SetValue(rowIndex, colIndex + 1, numericValue);
                                worksheet.Cells[rowIndex, colIndex + 1].Style.Numberformat.Format = "0.00";
                            }
                            else
                            {
                                worksheet.SetValue(rowIndex, colIndex + 1, cellValue);
                            }
                            worksheet.Cells[rowIndex, colIndex + 1].Style.Font.Size = 11;
                            worksheet.Cells[rowIndex, colIndex + 1].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                            worksheet.Cells[rowIndex, colIndex + 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                            worksheet.Cells[rowIndex, colIndex + 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                            if (colIndex + 1 == headers.Count())
                            {
                                worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Merge = true;
                                worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.Font.Size = 11;
                                worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                                worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                                worksheet.Cells[rowIndex, colIndex + 1, rowIndex, maxColIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                            }
                        }
                    }
                }
            }
            return rowIndex;
        }

        int GetMaxColumnIndex(int maxColIndex, List<DeptDetailItem> detailItems)
        {
            foreach (var item in detailItems)
            {
                if (item.Children?.Any() == true)
                {
                    var tempMaxColIndex = GetMaxColumnIndex(maxColIndex, item.Children);
                    if (tempMaxColIndex > maxColIndex)
                    {
                        maxColIndex = tempMaxColIndex;
                    }
                }
                else if (item.Items?.Any() == true)
                {
                    var tempMaxColIndex = item.Items.SelectMany(dict => dict.Keys).Distinct().Count();
                    if (tempMaxColIndex > maxColIndex)
                    {
                        maxColIndex = tempMaxColIndex;
                    }
                }
            }
            return maxColIndex;
        }


        #endregion
    }
}
