using AutoMapper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Services.AllotCompute;
using Performance.Services.ExtractExcelService;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Performance.Services
{
    public class AllotService : IAutoInjection
    {
        private BaiscNormService baiscNormService;
        private CheckDataService checkDataService;
        private ImportDataService importDataService;
        private ProcessComputService processComputService;
        private ResultComputeService resultComputeService;
        private PerforLogdbugRepository logdbug;
        private ConfigService configService;
        private IHostingEnvironment _evn;
        private ILogger<AllotService> _logger;
        private PerforPerallotRepository _allotRepository;
        private IEmailService emailService;
        private readonly IOptions<Application> options;
        private readonly ComputeDirector _computeDirector;
        private readonly PerforRescomputeRepository _perforRescomputeRepository;
        private readonly PerforImemployeeRepository _perforImEmployeeRepository;
        private PerforPeragainallotRepository _againallotRepository;
        private PerforLogcheckRepository perforLogcheckRepository;
        private readonly PerforHospitalRepository perforHospitalRepository;
        private readonly PerforResbaiscnormRepository perforResbaiscnormRepository;
        private PerforHospitalconfigRepository perforHospitalconfigRepository;
        private readonly RoleService roleService;
        private readonly UserService userService;
        private PerforCofdirectorRepository perforCofdirectorRepository;
        private readonly PerforReportRepository _reportRepository;
        private readonly PerforPeremployeeRepository _perforPeremployeeRepository;

        //private readonly IHubContext<AllotLogHub> hubContext;
        private readonly LogManageService logManageService;

        private readonly ReportService reportService;
        private readonly QueryDataService queryDataService;

        public AllotService(
            PerforPerallotRepository allotRepository,
            BaiscNormService baiscNormService,
            CheckDataService checkDataService,
            ImportDataService importDataService,
            ProcessComputService processComputService,
            ResultComputeService resultComputeService,
            ConfigService configService,
            PerforLogdbugRepository logdbug,
            IHostingEnvironment evn, ILogger<AllotService> logger,
            IEmailService emailService,
            IOptions<Application> options,
            ComputeDirector computeDirector,
            PerforRescomputeRepository perforRescomputeRepository,
            PerforImemployeeRepository perforImEmployeeRepository,
            PerforPeragainallotRepository againallotRepository,
            PerforLogcheckRepository perforLogcheckRepository,
            PerforHospitalRepository perforHospitalRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforHospitalconfigRepository perforHospitalconfigRepository,
            //IHubContext<AllotLogHub> hubContext
            RoleService roleService,
            UserService userService,
            LogManageService logManageService,
            ReportService reportService,
            PerforCofdirectorRepository perforCofdirectorRepository,
            PerforReportRepository reportRepository,
            PerforPeremployeeRepository perforPeremployeeRepository,
            QueryDataService queryDataService)
        {
            _allotRepository = allotRepository;
            _againallotRepository = againallotRepository;
            _logger = logger;
            _evn = evn;
            this.baiscNormService = baiscNormService;
            this.checkDataService = checkDataService;
            this.importDataService = importDataService;
            this.processComputService = processComputService;
            this.resultComputeService = resultComputeService;
            this.emailService = emailService;
            this.options = options;
            _computeDirector = computeDirector;
            _perforRescomputeRepository = perforRescomputeRepository;
            _perforImEmployeeRepository = perforImEmployeeRepository;
            this.configService = configService;
            this.logdbug = logdbug;
            this.perforLogcheckRepository = perforLogcheckRepository;
            this.perforHospitalRepository = perforHospitalRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this.perforHospitalconfigRepository = perforHospitalconfigRepository;
            this.roleService = roleService;
            this.userService = userService;
            //this.hubContext = hubContext;
            this.logManageService = logManageService;
            this.reportService = reportService;
            this.perforCofdirectorRepository = perforCofdirectorRepository;
            _reportRepository = reportRepository;
            _perforPeremployeeRepository = perforPeremployeeRepository;
            this.queryDataService = queryDataService;
        }

        #region 基础功能

        /// <summary>
        /// 绩效记录
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <returns></returns>
        public List<AllotResponse> GetAllotList(int? hospitalId)
        {
            if (!hospitalId.HasValue || hospitalId.Value <= 0)
                throw new PerformanceException("hospitalId无效");
            var allotList = _allotRepository.GetEntities(t => t.HospitalId == hospitalId);
            allotList = allotList == null ? allotList : allotList.OrderByDescending(t => t.ID).ToList();
            var isconfig = perforHospitalconfigRepository.GetEntity(t => t.HospitalId == hospitalId) == null ? false : true;
            var result = Mapper.Map<List<AllotResponse>>(allotList);
            result?.ForEach(t =>
            {
                t.IsDown = !string.IsNullOrEmpty(t.ExtractPath);
                if (!string.IsNullOrEmpty(t.ExtractPath))
                    t.ExtractPath = t.ExtractPath.Replace(options.Value.AbsolutePath, options.Value.HttpPath).Replace("\\", "/");

                t.HasConfig = isconfig ? 3 : 0;
            });
            if (result != null && result.Any())
            {
                result = result.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).ToList();
            }
            return result;
        }

        /// <summary>
        /// 生成成功或归档绩效记录
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <returns></returns>
        public List<AllotResponse> GetSuccAllotList(int? hospitalId)
        {
            if (!hospitalId.HasValue || hospitalId.Value <= 0)
                throw new PerformanceException("hospitalId无效");
            var allotList = _allotRepository.GetEntities(t => t.HospitalId == hospitalId
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
            allotList = allotList == null ? allotList : allotList.OrderByDescending(t => t.ID).ToList();
            var isconfig = perforHospitalconfigRepository.GetEntity(t => t.HospitalId == hospitalId) == null ? false : true;
            var reuslt = Mapper.Map<List<AllotResponse>>(allotList);
            reuslt?.ForEach(t =>
            {
                t.IsDown = !string.IsNullOrEmpty(t.ExtractPath);
                if (!string.IsNullOrEmpty(t.ExtractPath))
                    t.ExtractPath = t.ExtractPath.Replace(options.Value.AbsolutePath, options.Value.HttpPath).Replace("\\", "/");

                t.HasConfig = isconfig ? 3 : 0;
            });
            return reuslt;
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public per_allot InsertAllot(AllotRequest request, int userID)
        {
            var repAllot = _allotRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Year == request.Year && t.Month == request.Month);
            if (repAllot != null && repAllot.Count() > 0)
                throw new PerformanceException("当前绩效记录已存在");

            var allot = Mapper.Map<per_allot>(request);
            allot.CreateDate = DateTime.Now;
            allot.CreateUser = userID;
            allot.States = (int)AllotStates.NoData;
            allot.Remark = EnumHelper.GetDescription(AllotStates.NoData);
            if (!_allotRepository.Add(allot))
                throw new PerformanceException("保存失败");

            return allot;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public AllotResponse UpdateAllot(AllotRequest request)
        {
            var allot = _allotRepository.GetEntity(t => t.ID == request.ID);
            if (allot == null)
                throw new PerformanceException("当前绩效记录不存在");

            var repAllot = _allotRepository.GetEntities(t => t.ID != request.ID && t.HospitalId == request.HospitalId
                && t.Year == request.Year && t.Month == request.Month);
            if (repAllot != null && repAllot.Count() > 0)
                throw new PerformanceException("当前绩效记录与其他记录冲突");

            allot.HospitalId = request.HospitalId.Value;
            allot.Year = request.Year;
            allot.Month = request.Month;
            if (!_allotRepository.Update(allot))
                throw new PerformanceException("保存失败");

            return Mapper.Map<AllotResponse>(allot);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="iD"></param>
        /// <returns></returns>
        public bool DeleteAllot(int iD)
        {
            var allot = _allotRepository.GetEntity(t => t.ID == iD);
            if (allot == null)
                throw new PerformanceException("当前绩效记录不存在");
            var result = _allotRepository.Remove(allot);
            if (!string.IsNullOrEmpty(allot.Path))
            {
                var dpath = Path.Combine(_evn.ContentRootPath, "Files", $"{allot.HospitalId}", $"{allot.Year}{allot.Month.ToString().PadLeft(2, '0')}");
                var name = FileHelper.GetFileName(allot.Path);
                var path = Path.Combine(dpath, name);
                if (allot.Path != path)
                {
                    try
                    {
                        FileHelper.Move(allot.Path, path);
                        allot.Path = path;
                        _allotRepository.Remove(allot);

                        configService.ClearAllotData(allot.ID);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError("移动文件失败;{0}", ex);
                    }
                }

                FileHelper.CreateDirectory(dpath);
            }

            return result;
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public per_allot GetAllot(int allotId)
        {
            return _allotRepository.GetEntity(t => t.ID == allotId);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="allot"></param>
        /// <returns></returns>
        public bool Update(per_allot allot)
        {
            return _allotRepository.Update(allot);
        }

        #endregion 基础功能

        /// <summary>
        /// 修改自定义提取结果地址
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="path"></param>
        public void UpdateAllotCustomExtractPath(int allotId, string path)
        {
            var allot = _allotRepository.GetEntity(w => w.ID == allotId);
            allot.CustomExtractPath = path;
            _allotRepository.Update(allot);
        }

        public void UpdateAllotStates(int allotId, int states, string remark, int generate = 0)
        {
            _allotRepository.UpdateAllotStates(allotId, states, remark, generate);
        }

        public per_allot UpdateAllotShowFormula(int allotId)
        {
            var allot = _allotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                return null;
            allot.ShowFormula = allot.ShowFormula == 0 ? 1 : 0;
            _allotRepository.Update(allot);
            return allot;
        }

        /// <summary>
        /// 生成绩效
        /// </summary>
        /// <param name="allot"></param>
        /// <param name="user"></param>
        public void Generate(per_allot allot)
        {
            DateTime time = DateTime.Now;
            try
            {
                logManageService.WriteMsg("绩效开始执行", $"正在生成{allot.Year}-{allot.Month.ToString().PadLeft(2, '0')}月份绩效!", 1, allot.ID, "ReceiveMessage", true);

                var excel = new PerExcel();
                int generate = allot.Generate;
                if (new int[] { (int)AllotGenerate.OriginalDataEdited, (int)AllotGenerate.PersonnelOffice }.Contains(allot.Generate))
                {
                    logManageService.WriteMsg("绩效开始执行", $"数据来源：生成成功后被修改的原数据。", 1, allot.ID, "ReceiveMessage", true);
                    generate = (int)AllotGenerate.Success;
                    configService.ClearResData(allot.ID);
                    excel = queryDataService.QueryDataAndHeader(allot);
                }
                else
                {
                    logManageService.WriteMsg("绩效开始执行", $"数据来源：用户上传的Excel。", 1, allot.ID, "ReceiveMessage", true);

                    configService.Clear(allot.ID);
                    // 关闭筛选功能
                    ExtractHelper.CloseAutoFilter(allot.Path);
                    // 导出数据
                    excel = importDataService.ReadDataAndSave(allot);

                    UpdateAllotStates(allot.ID, (int)AllotStates.InCheckData, EnumHelper.GetDescription(AllotStates.InCheckData));
                    //if (!checkDataService.Check(excel, allot))
                    //{
                    //    UpdateAllotStates(allot.ID, (int)AllotStates.CheckFail, EnumHelper.GetDescription(AllotStates.CheckFail));
                    //    //SendEmail(allot, mail, 3, time);
                    //    logManageService.WriteMsg("绩效数据校验失败", "详情可至“更多 -- 查看日志”查看", 3, allot.ID, "ReceiveMessage", true);
                    //    return;
                    //}
                }
                UpdateAllotStates(allot.ID, (int)AllotStates.InGenerate, EnumHelper.GetDescription(AllotStates.InGenerate));

                //保底绩效计算需分两次进行；
                //第一次计算包含（保底绩效临床医生人均绩效、保底绩效医技医生人均绩效、保底绩效护士人均绩效）得出科室业绩绩效；
                //根据当前业绩绩效核算各人群人均绩效，取工勤人均作为 保底工勤人均绩效

                //第二次计算包含（保底绩效临床医生人均绩效、保底绩效医技医生人均绩效、保底绩效护士人均绩效、保底工勤人均绩效）得出科室业绩绩效；
                //根据当前业绩绩效核算出最终绩效结果

                //科室经济核算汇总、工作量汇总
                logManageService.WriteMsg("科室业绩汇总", "正在生成科室收入支出汇总、工作量汇总", 1, allot.ID, "ReceiveMessage", true);
                var (list, mergeSheets) = processComputService.MergeCompute(excel, allot.ID);
                processComputService.Save(list, allot.ID);

                #region 注释

                ////计算保底绩效参考标准（保底绩效临床医生人均绩效、保底绩效医技医生人均绩效、保底绩效护士人均绩效）
                //logManageService.WriteMsg("计算保底绩效参考标准值", "正在保底绩效临床医生人均绩效、保底绩效医技医生人均绩效、保底绩效护士人均绩效", 1, allot.ID, "ReceiveMessage", true);
                //var minimumBaiscnorm = processComputService.ComputeMinimum(excel, mergeSheets, allot.ID);

                ////计算科室业绩（含保底绩效临床医生人均绩效、保底绩效医技医生人均绩效、保底绩效护士人均绩效）保底绩效
                //logManageService.WriteMsg("计算保底绩效参考标准值", "计算科室业绩", 1, allot.ID, "ReceiveMessage", true);
                //var sheet = processComputService.Compute(excel, mergeSheets, minimumBaiscnorm, true);

                ////计算科室自定义保底绩效范围
                //logManageService.WriteMsg("计算保底绩效参考标准值", "正在计算科室自定义保底绩效范围", 1, allot.ID, "ReceiveMessage", true);
                //processComputService.ComputeCustomMinimum(excel, mergeSheets, minimumBaiscnorm, allot.ID);

                ////计算各人群人均保底绩效
                //logManageService.WriteMsg("计算保底绩效参考标准值", "正在生成保底绩效行政工勤人均绩效", 1, allot.ID, "ReceiveMessage", true);
                //var minimumBaiscnorm2 = resultComputeService.Compute(allot, excel, sheet, true);
                //if (minimumBaiscnorm2 != null && minimumBaiscnorm2.Any(t => t.PositionName == EnumHelper.GetDescription(PerforType.行政工勤)))
                //{
                //    var minimum = minimumBaiscnorm2.First(t => t.PositionName == EnumHelper.GetDescription(PerforType.行政工勤));
                //    minimum.PositionName = EnumHelper.GetDescription(MinimumType.保底工勤);
                //    minimumBaiscnorm.Add(minimum);
                //}

                ////保存 保底绩效参考标准
                //logManageService.WriteMsg("计算保底绩效参考标准值", "保存保底绩效参考标准", 1, allot.ID, "ReceiveMessage", true);
                //perforResbaiscnormRepository.AddRange(minimumBaiscnorm.ToArray());

                //// 科室奖罚汇总
                //logManageService.WriteMsg("正在生成绩效", "科室奖罚汇总", 1, allot.ID, "ReceiveMessage", true);
                //var accountExtras = processComputService.GetAccountExtra(excel, SheetType.AccountExtra, true);
                //// 科室药占比考核
                //logManageService.WriteMsg("正在生成绩效", "科室药占比考核", 1, allot.ID, "ReceiveMessage", true);
                //var drugExtras = processComputService.GetAccountExtra(excel, SheetType.AccountDrugAssess, true);
                //// 科室材料占比考核
                //logManageService.WriteMsg("正在生成绩效", "科室材料占比考核", 1, allot.ID, "ReceiveMessage", true);
                //var materialsExtras = processComputService.GetAccountExtra(excel, SheetType.AccountMaterialsAssess, true);
                //// 科室考核得分率
                //logManageService.WriteMsg("正在生成绩效", "科室考核得分率", 1, allot.ID, "ReceiveMessage", true);
                //var accountScoreAverages = processComputService.GetAccountScoreAverage(excel, SheetType.AccountScoreAverage, true);

                ////科室药占比考核
                //logManageService.WriteMsg("正在生成绩效", "科室奖罚汇总", 1, allot.ID, "ReceiveMessage", true);
                //var accountExtras = processComputService.GetAccountExtra(excel);

                ////科室材料考核
                //logManageService.WriteMsg("正在生成绩效", "科室奖罚汇总", 1, allot.ID, "ReceiveMessage", true);
                //var accountExtras = processComputService.GetAccountExtra(excel);

                #endregion 注释

                //重新计算科室业绩（含所有提供保底金额）
                logManageService.WriteMsg("正在生成绩效", "计算科室业绩分", 1, allot.ID, "ReceiveMessage", true);
                var sheetLast = processComputService.Compute(excel, mergeSheets, allot);

                //保存计算过程数据
                logManageService.WriteMsg("正在生成绩效", "保存科室业绩结果及计算过程中产生的数据", 1, allot.ID, "ReceiveMessage", true);
                processComputService.Save(sheetLast, allot.ID);

                ////业务中层行政中高层医院奖罚
                //logManageService.WriteMsg("正在生成绩效", "业务中层行政中高层医院奖罚", 1, allot.ID, "ReceiveMessage", true);
                //var employeeExtra = processComputService.GetEmployeeExtra(excel);

                // 计算最总数据
                logManageService.WriteMsg("正在生成绩效", "计算最终绩效数据", 1, allot.ID, "ReceiveMessage", true);
                var baiscnormList = resultComputeService.Compute(allot, sheetLast);

                // 计算行政科室绩效
                processComputService.ComputeOffice(allot, excel);

                // 计算特殊科室
                logManageService.WriteMsg("正在生成绩效", "计算最终特殊科室绩效数据", 1, allot.ID, "ReceiveMessage", true);
                resultComputeService.SpecialUnitCompute(excel, allot, baiscnormList);
                logManageService.WriteMsg("正在生成绩效", "保存最终特殊科室绩效数据", 1, allot.ID, "ReceiveMessage", true);

                //保存 绩效人均参考标准
                logManageService.WriteMsg("正在生成绩效", "保存绩效人均参考标准", 1, allot.ID, "ReceiveMessage", true);
                perforResbaiscnormRepository.AddRange(baiscnormList.ToArray());

                //// 保存预留绩效
                //logManageService.WriteMsg("正在生成绩效", "保存预留绩效金额", 1, allot.ID, "ReceiveMessage", true);
                //resultComputeService.SaveReserved(allot, allot.HospitalId);

                // 科室下发
                resultComputeService.GenerateSecondAllot(allot);

                UpdateAllotStates(allot.ID, (int)AllotStates.GenerateAccomplish, EnumHelper.GetDescription(AllotStates.GenerateAccomplish), generate);
                perforCofdirectorRepository.SupplementaryData(allot.ID);
                // 验证科室核算单元、工号
                AccoungtingVerify(allot.ID);
                //补全支出费用类别
                configService.SaveDrugtypeDisburse(allot.ID);
                //logManageService.WriteMsg("正在生成报表数据", "正在生成报表数据", 1, allot.ID, "ReceiveMessage", true);
                //var res = reportService.ImportData(allot);
                //var flag = reportService.UpdateData(allot);
                //logManageService.WriteMsg("正在生成报表数据", $"报表数据生成完成；受影响：{res}行", 1, allot.ID, "ReceiveMessage", true);
                //reportService.ExecProc("call proc_report_performance(@hospitalid, @year, @month);", new { allot.HospitalId, allot.Year, allot.Month });


                ////发送邮件
                //logManageService.WriteMsg("正在发送邮件", "正在发送邮件", 1, allot.ID, "ReceiveMessage", true);
                //SendEmail(allot, mail, 1, time);
                //logdbug.Add(allot.ID, "绩效开始执行", "绩效生成成功");
                logManageService.WriteMsg("绩效生成结束", "绩效生成成功", 5, allot.ID, "ReceiveMessage", true);
            }
            catch (Exception ex)
            {
                logManageService.WriteMsg("绩效生成失败", ex.Message, 4, allot.ID, "ReceiveMessage");
                logdbug.Add(allot.ID, "绩效生成失败", ex.ToString(), 4, 1);
                UpdateAllotStates(allot.ID, (int)AllotStates.GenerateFail, EnumHelper.GetDescription(AllotStates.GenerateFail));
                //SendEmail(allot, mail, 2, time);
                //throw ex;
            }
        }

        /// <summary>
        /// 绩效生成报表
        /// </summary>
        /// <param name="allot"></param>
        public void GenerateReport(per_allot allot)
        {
            reportService.ExecProc("call proc_report_performance(@hospitalid, @year, @month);", new { allot.HospitalId, allot.Year, allot.Month });
        }

        /// <summary>
        /// 验证科室核算单元、工号
        /// </summary>
        /// <param name="allot"></param>
        public void AccoungtingVerify(int allotId)
        {
            reportService.ExecProc("call proc_verify_accoungingunit_unittype(@allotId);", new { allotId });
        }

        /// <summary>
        /// 重新计算院领导绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="money"></param>
        public void Recalculation(int allotId, decimal money)
        {
            var allot = _allotRepository.GetEntity(w => w.ID == allotId);

            var empolyeeList = _perforImEmployeeRepository.GetEntities(t => t.AllotID == allotId && t.AccountType == AccountUnitType.行政高层.ToString());

            if (empolyeeList == null) return;

            var computeEmployees = Mapper.Map<List<ComputeEmployee>>(empolyeeList);
            computeEmployees.ForEach(w => w.FitPeopleValue = money);

            List<res_baiscnorm> baiscnormList = new List<res_baiscnorm>();
            var computResult = _computeDirector.Compute(computeEmployees, allot, baiscnormList);

            if (computResult == null) return;

            baiscnormList = baiscNormService.ComputeOtherAvg(baiscnormList, computResult, empolyeeList);
            baiscnormList.ForEach(t => t.AllotID = allot.ID);

            var historyRescompute = _perforRescomputeRepository.GetEntities(w => w.AllotID == allotId && w.AccountType == AccountUnitType.行政高层.ToString());
            if (historyRescompute != null && historyRescompute.Any())
                _perforRescomputeRepository.RemoveRange(historyRescompute.ToArray());

            var computes = Mapper.Map<List<res_compute>>(computResult);
            computes.ForEach(t => t.AllotID = allot.ID);
            _perforRescomputeRepository.AddRange(computes.ToArray());

            var names = baiscnormList.Select(b => b.PositionName).ToList();
            var historyResbaiscnorm = perforResbaiscnormRepository.GetEntities(w => w.AllotID == allotId && names.Contains(w.PositionName));
            if (historyResbaiscnorm != null && historyResbaiscnorm.Any())
                perforResbaiscnormRepository.RemoveRange(historyResbaiscnorm.ToArray());
            perforResbaiscnormRepository.AddRange(Mapper.Map<res_baiscnorm[]>(baiscnormList));
        }

        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="allot"></param>
        /// <param name="mail"></param>
        /// <param name="type"> 1 成功 2 异常 3 验证失败</param>
        private void SendEmail(per_allot allot, string mail, int type, DateTime time)
        {
            var hospital = perforHospitalRepository.GetEntity(t => t.ID == allot.HospitalId);

            var message = new EmailMessage();
            message.To = new List<string> { mail };
            message.DisplayName = "溯直健康";
            message.Subject = $"绩效生成任务结束提醒！";
            if (type == 1)
            {
                message.Body = $"<p>尊敬的用户！</p><p>&nbsp;&nbsp;&nbsp;&nbsp;数值健康提醒您，您在{time.ToString("yyyy-MM-dd hh:mm:ss")}发布" +
                    $"{hospital.HosName}{allot.Year}年{allot.Month}月的绩效生成任务<strong><span style=\"color:#E53333;\">“执行成功”</span></strong>，" +
                    $"您可以登录<a href=\"http://jixiao.suvalue.com\" target=\"_blank\">http://jixiao.suvalue.com</a>查看绩效结果。</p>";
            }
            else if (type == 2)
            {
                message.Body = $"<p>尊敬的用户！</p><p>&nbsp;&nbsp;&nbsp;&nbsp;数值健康提醒您，您在{time.ToString("yyyy-MM-dd hh:mm:ss")}发布" +
                    $"{hospital.HosName}{allot.Year}年{allot.Month}月的绩效生成任务<strong><span style=\"color:#E53333;\">“执行失败”</span></strong>，" +
                    $"执行过程中出现异常情况，我们将尽快解决问题。给您带来的不便我们深感歉意！</p>";
            }
            else if (type == 3)
            {
                message.Body = $"<p>尊敬的用户！</p><p>&nbsp;&nbsp;&nbsp;&nbsp;数值健康提醒您，您在{time.ToString("yyyy-MM-dd hh:mm:ss")}发布" +
                    $"{hospital.HosName}{allot.Year}年{allot.Month}月的绩效生成任务<strong><span style=\"color:#E53333;\">“校验失败”</span></strong>，" +
                    $"您可以登录<a href=\"http://jixiao.suvalue.com\" target=\"_blank\">http://jixiao.suvalue.com</a>查看详细清空。</p>";
            }

            emailService.SendAsync(message);
        }

        /// <summary>
        /// 归档绩效记录
        /// </summary>
        /// <param name="allot"></param>
        public void Pigeonhole(per_allot allot)
        {
            allot.States = 8;
            allot.Remark = "归档";
            _allotRepository.Update(allot);
            //if (_allotRepository.Update(allot))
            //{
            //    var again = _againallotRepository.GetEntities(t => t.AllotID == allot.ID);
            //    if (again != null && again.Count > 0)
            //    {
            //        foreach (var item in again)
            //        {
            //            item.Remark = $"原状态：{item.States}，归档更改状态";
            //            item.States = 5;
            //            _againallotRepository.Update(item);
            //        }
            //    }
            //}
        }

        /// <summary>
        /// 检索数据是否合格
        /// </summary>
        /// <param name="allot"></param>
        public List<AgainAllotResponse> GetAgainAllotNotSucceed(per_allot allot)
        {
            var again = _againallotRepository.GetEntities(t => t.AllotID == allot.ID && (!t.States.HasValue || t.States.Value != 3));
            List<AgainAllotResponse> result = Mapper.Map<List<AgainAllotResponse>>(again);
            if (result != null && result.Count > 0)
            {
                result.ForEach(t => { t.Year = allot.Year; t.Month = allot.Month; });
            }
            return result;
        }

        /// <summary>
        /// 绩效校验结果
        /// </summary>
        /// <param name="allot"></param>
        /// <returns></returns>
        public List<log_check> AllotCheckResult(per_allot allot)
        {
            var list = perforLogcheckRepository.GetEntities(t => t.AllotID == allot.ID);
            if (list != null)
                list = list.OrderBy(t => t.Titile).ThenBy(t => t.ID).ToList();
            return list;
        }

        /// <summary>
        /// 绩效历史日志
        /// </summary>
        /// <param name="allot"></param>
        /// <returns></returns>
        public List<log_dbug> AllotLog(per_allot allot, int type)
        {
            var list = logdbug.GetEntities(t => t.AllotID == allot.ID && t.Type == type);
            if (list != null)
                list = list.OrderBy(t => t.CreateTime).ToList();
            return list;
        }

        /// <summary>
        /// 获取医院预留绩效
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <param name="year"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        public List<EmployeeReservedDto> GetReserved(int hospitalId, int year, int userid)
        {
            var user = userService.GetUser(userid);
            if (user == null)
                throw new PerformanceException("用户信息错误");

            var role = roleService.GetUserRole(userid)?.FirstOrDefault()?.Type;
            if (!role.HasValue)
                throw new PerformanceException("用户信息错误");

            var reserveds = _reportRepository.GetEmployeeReserved(hospitalId, year);

            if (reserveds != null && reserveds.Any())
            {
                if (role.Value == options.Value.NurseRole)
                    reserveds = reserveds.Where(w => UnitTypeUtil.Is(w.UnitType, UnitType.护理组, UnitType.其他护理组) && w.AccountingUnit == user.Department)?.ToList();
                else if (role.Value == options.Value.DirectorRole)
                    reserveds = reserveds.Where(w => UnitTypeUtil.Is(w.UnitType, UnitType.医生组, UnitType.其他医生组, UnitType.医技组, UnitType.其他医技组) && w.AccountingUnit == user.Department)?.ToList();
                else if (role.Value == options.Value.SpecialRole)
                    reserveds = reserveds.Where(w => UnitTypeUtil.Is(w.UnitType, UnitType.特殊核算组) && w.AccountingUnit == user.Department)?.ToList();
                else if (role.Value == options.Value.OfficeRole)
                    reserveds = reserveds.Where(w => UnitTypeUtil.Is(w.UnitType, UnitType.行政中层, UnitType.行政后勤) && w.AccountingUnit == user.Department)?.ToList();
            }

            return reserveds;
        }
        /// <summary>
        /// 查询个人绩效
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public List<OwnerPerformanceDto> GetOwnerPerformance(int userid)
        {
            var user = userService.GetUser(userid);
            if (user == null)
                throw new PerformanceException("用户信息错误");

            var roleType = roleService.GetUserRole(userid)?.FirstOrDefault()?.Type;
            if (!roleType.HasValue)
                throw new PerformanceException("用户信息错误");

            if (roleType != (int)Role.绩效查询)
                throw new PerformanceException("当前用户暂不支持绩效查询");

            var hospitals = userService.GetUserHospital(userid);
            string jobNumber = user.Login;
            var owner = _reportRepository.GetOwnerPerformance(hospitals, jobNumber);

            if (owner == null || !owner.Any())
                return new List<OwnerPerformanceDto>();

            var employees = _perforPeremployeeRepository.GetEntities(w => w.PersonnelNumber == jobNumber);

            var res = owner
                .Where(w => w.States == (int)AllotStates.Archive)
                .GroupBy(w => new { w.AllotId, w.Year, w.Month, w.JobNumber })
                .Select(w => new OwnerPerformanceDto
                {
                    AllotId = w.Key.AllotId,
                    Year = w.Key.Year,
                    Month = w.Key.Month,
                    JobNumber = w.Key.JobNumber,

                    PerforSumFee = Math.Round(w.Sum(p => p.PerforSumFee) ?? 0, 2, MidpointRounding.AwayFromZero),     // 业绩绩效
                    PerforManagementFee = Math.Round(w.Sum(p => p.PerforManagementFee) ?? 0, 2, MidpointRounding.AwayFromZero),// 管理绩效
                    NightWorkPerfor = Math.Round(w.Sum(p => p.NightWorkPerfor) ?? 0, 2, MidpointRounding.AwayFromZero),// 夜班绩效
                    AdjustLaterOtherFee = Math.Round(w.Sum(p => p.AdjustLaterOtherFee) ?? 0, 2, MidpointRounding.AwayFromZero), // 调节后其他绩效
                    OtherPerfor = Math.Round(w.Sum(p => p.OtherPerfor) ?? 0, 2, MidpointRounding.AwayFromZero), // 医院其他绩效
                    HideOtherPerfor = Math.Round(w.Sum(p => p.HideOtherPerfor) ?? 0, 2, MidpointRounding.AwayFromZero),// 不公示其他绩效

                    RealPerformance = Math.Round(w.Sum(p => p.RealPerformance) ?? 0, 2, MidpointRounding.AwayFromZero),// 中转使用： 业绩绩效+管理绩效+调节后其他绩效
                    Detail = w
                        .Where(p => p.Year == w.Key.Year && p.Month == w.Key.Month && p.JobNumber == w.Key.JobNumber)
                        .Select(detial =>
                        {
                            var dto = Mapper.Map<OwnerPerformanceDto>(detial);
                            dto.Source = string.IsNullOrEmpty(detial.SourceItem) ? detial.Source : $"{detial.Source}-{detial.SourceItem}";
                            // 应发绩效
                            dto.ShouldGiveFee = Math.Round((dto.RealPerformance ?? 0) + (dto.OtherPerfor ?? 0) + (dto.HideOtherPerfor ?? 0) + (dto.NightWorkPerfor ?? 0), 2, MidpointRounding.AwayFromZero);
                            dto.ReservedRatio = employees?.FirstOrDefault(emp => emp.AllotId == dto.AllotId && emp.PersonnelNumber == jobNumber)?.ReservedRatio ?? 0; // 预留比例
                            dto.ReservedRatioFee = Math.Round((dto.RealPerformance ?? 0) * (dto.ReservedRatio ?? 0), 2, MidpointRounding.AwayFromZero);  // 预留绩效
                            dto.RealGiveFee = Math.Round(dto.ShouldGiveFee - (dto.ReservedRatioFee ?? 0) ?? 0, 2, MidpointRounding.AwayFromZero); // 实发绩效
                            return dto;
                        }),
                })
                .ToList();

            foreach (var item in res)
            {
                item.UnitType = employees?.FirstOrDefault(w => w.AllotId == item.AllotId && w.PersonnelNumber == jobNumber)?.UnitType ?? "";
                item.AccountingUnit = employees?.FirstOrDefault(w => w.AllotId == item.AllotId && w.PersonnelNumber == jobNumber)?.AccountingUnit ?? "";
                item.EmployeeName = employees?.FirstOrDefault(w => w.AllotId == item.AllotId && w.PersonnelNumber == jobNumber)?.DoctorName ?? "";
                // 全部是0的记录不显示
                item.Detail = item.Detail.Where(w => !(w.PerforSumFee == 0 && w.PerforManagementFee == 0 && w.ShouldGiveFee == 0 && w.OtherPerfor == 0 && w.HideOtherPerfor == 0 && w.RealGiveFee == 0));
                // 为了保证总额一致
                item.ShouldGiveFee = Math.Round(item.Detail?.Sum(w => w.ShouldGiveFee) ?? 0, 2, MidpointRounding.AwayFromZero); // 应发绩效
                item.ReservedRatio = employees?.FirstOrDefault(w => w.AllotId == item.AllotId && w.PersonnelNumber == jobNumber)?.ReservedRatio ?? 0; // 预留比例
                item.ReservedRatioFee = Math.Round(item.Detail?.Sum(w => w.ReservedRatioFee) ?? 0, 2, MidpointRounding.AwayFromZero);  // 预留绩效
                item.RealGiveFee = Math.Round(item.Detail?.Sum(w => w.RealGiveFee) ?? 0, 2, MidpointRounding.AwayFromZero); // 实发绩效
            }

            return res?.OrderByDescending(w => w.Year).ThenByDescending(w => w.Month).ToList();
        }
    }
}
