using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Services;
using Performance.Services.AllotCompute;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Performance.Infrastructure;
using Performance.DtoModels.Second;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Microsoft.AspNetCore.StaticFiles;

namespace Performance.Api.Controllers
{
    /// <summary>
    /// 二次绩效
    /// </summary>
    [ApiController]
    public class SecondAllotController : ControllerBase
    {
        private readonly ILogger<SecondAllotController> _logger;
        private readonly ClaimService claimService;
        private readonly HospitalService _hospitalService;
        private readonly AllotService _allotService;
        private readonly SecondAllotService secondAllotService;
        private readonly ResultComputeService resultComputeService;
        private readonly SecondAllotDetails secondAllotDetails;
        private readonly RedistributionService _redistributionService;

        public SecondAllotController(
            ILogger<SecondAllotController> logger,
            ClaimService claimService,
            HospitalService hospitalService,
            AllotService allotService,
            SecondAllotService secondAllotService,
            ResultComputeService resultComputeService,
            SecondAllotDetails secondAllotDetails,
            RedistributionService redistributionService
            )
        {
            _logger = logger;
            this.claimService = claimService;
            _hospitalService = hospitalService;
            _allotService = allotService;
            this.secondAllotService = secondAllotService;
            this.resultComputeService = resultComputeService;
            this.secondAllotDetails = secondAllotDetails;
            _redistributionService = redistributionService;
        }

        #region 二次绩效列表、录入数据展示，保存数据

        /// <summary>
        /// 二次绩效列表（没有需要初始化）
        /// </summary>
        /// <returns></returns>
        [Route("api/second/list")]
        [HttpPost]
        public ApiResponse List()
        {
            var userId = claimService.GetUserId();
            var result = secondAllotService.GetSecondList(userId);
            if (result != null && result.Any())
                result = result.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).ToList();
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 二次绩效项目内容保存
        /// </summary>
        /// <returns></returns>
        [Route("api/second/savevalue/{secondid}")]
        [HttpPost]
        public ApiResponse SaveValue(int secondid, [FromBody] List<ag_fixatitem> request)
        {
            //if (secondid != 0 && (request == null || request.Count == 0))
            //    secondAllotService.DelValue(secondid, request);

            var allotCount = request.Where(t => t.AllotId > 0).Select(t => t.AllotId).Distinct().Count();
            if (allotCount != 1 || request.Any(t => t.AllotId == 0))
                throw new PerformanceException("一次绩效ID错误");

            var secondCount = request.Where(t => t.SecondId > 0).Select(t => t.SecondId).Distinct().Count();
            if (secondCount != 1 || request.Any(t => t.SecondId == 0))
                throw new PerformanceException("二次绩效ID错误");

            var typeCount = request.Where(t => t.Type > 0).Select(t => t.Type).Distinct().Count();
            if (request.Any(t => t.Type == 0)) //typeCount != 1 ||
                throw new PerformanceException("二次绩效项位置错误");

            var unitTypeCount = request.Where(t => !string.IsNullOrEmpty(t.UnitType)).Select(t => t.UnitType).Distinct().Count();
            if (unitTypeCount != 1 || request.Any(t => string.IsNullOrEmpty(t.UnitType)))
                throw new PerformanceException("科室类型错误");

            var repetition = request.Where(t => !string.IsNullOrWhiteSpace(t.ItemName))
                .GroupBy(t => new { t.RowNumber, t.ItemName /*, WorkType = t.WorkType ?? 0*/ }).Where(t => t.Count() > 1);
            if (repetition.Any())
                throw new PerformanceException(string.Join(";", repetition.Select(t => $"行{t.Key.RowNumber}项‘{t.Key.ItemName}’重复录入")));

            var result = secondAllotService.SaveValue(request, secondid);
            return new ApiResponse(ResponseType.OK);
        }

        ///// <summary>
        ///// 提交二次绩效分配结果
        ///// </summary>
        ///// <returns></returns>
        //[Route("api/second/savecompute")]
        //[HttpPost]
        //public ApiResponse SaveCompute([FromBody] List<ag_compute> request)
        //{
        //    var allotCount = request.Where(t => t.AllotId > 0).Select(t => t.AllotId).Distinct().Count();
        //    if (allotCount != 1 || request.Any(t => t.AllotId == 0))
        //        throw new PerformanceException("一次绩效ID错误");

        //    var secondCount = request.Where(t => t.SecondId > 0).Select(t => t.SecondId).Distinct().Count();
        //    if (secondCount != 1 || request.Any(t => t.SecondId == 0))
        //        throw new PerformanceException("二次绩效ID错误");

        //    var departmentCount = request.Where(t => !string.IsNullOrEmpty(t.Department)).Select(t => t.Department).Distinct().Count();
        //    if (departmentCount != 1 || request.Any(t => string.IsNullOrEmpty(t.Department)))
        //        throw new PerformanceException("科室名称错误");

        //    var personNameCount = request.Where(t => !string.IsNullOrEmpty(t.PersonName)).Select(t => t.PersonName).Distinct().Count();
        //    if (personNameCount != 1 || request.Any(t => string.IsNullOrEmpty(t.PersonName)))
        //        throw new PerformanceException("人员名称错误");

        //    var result = secondAllotService.SaveCompute(request);
        //    return new ApiResponse(ResponseType.OK);
        //}

        /// <summary>
        /// 二次绩效录入页面配置信息
        /// </summary>
        /// <returns></returns>
        [Route("api/second/detail")]
        [HttpPost]
        public ApiResponse SecondDetail([CustomizeValidator(RuleSet = "Refresh"), FromBody] UseTempRequest request)
        {
            //var result = secondAllotService.GetSecondDetail(request, claimService.GetUserId());
            var result = secondAllotDetails.GetSecondDetails(claimService.GetUserId(), request.SecondId, request.HospitalId, request.IsArchive, request.EmployeeSource);
            return new ApiResponse(ResponseType.OK, result);
        }

        ///// <summary>
        ///// 二次绩效录入页面配置信息
        ///// </summary>
        ///// <returns></returns>
        //[Route("api/second/otherdetail/{secondid}")]
        //[HttpPost]
        //public ApiResponse SecondOtherDetail(int secondid)
        //{
        //    var result = secondAllotService.GetSecondDetail(secondid);
        //    return new ApiResponse(ResponseType.OK, result);
        //}

        #endregion 二次绩效列表、录入数据展示，保存数据

        /// <summary>
        /// 二次绩效录入页面自动补全
        /// </summary>
        /// <returns></returns>
        [Route("api/second/autocomplete")]
        [HttpPost]
        public ApiResponse AutoComplete([FromBody] SecondEmpRequest request)
        {
            var result = secondAllotService.AutoComplete(request, claimService.GetUserId());
            //var result = secondAllotService.AutoComplete(request.SecondId, request.JobNumber);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 二次绩效录入页面其他模板自动补全
        /// </summary>
        /// <returns></returns>
        [Route("api/second/other/autocomplete")]
        [HttpPost]
        public ApiResponse OtherAutoComplete([FromBody] SecondEmpRequest request)
        {
            var result = secondAllotService.OtherAutoComplete(request, claimService.GetUserId());
            return new ApiResponse(ResponseType.OK, result);
        }

        #region 模板使用

        /// <summary>
        /// 选择二次绩效模板
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("api/temp/list")]
        public ApiResponse<List<SecondTempResponse>> Temp([FromBody] AllotDeptRequest request)
        {
            var userId = claimService.GetUserId();
            var result = secondAllotService.GetTemp(request.HospitalId, request.UnitType, request.Department, userId);
            return new ApiResponse<List<SecondTempResponse>>(ResponseType.OK, result);
        }

        /// <summary>
        /// 保存已选择二次绩效模板
        /// </summary>
        /// <returns></returns>
        [Route("api/temp/usetemp")]
        [HttpPost]
        public ApiResponse UseTemp([CustomizeValidator(RuleSet = "Use"), FromBody] UseTempRequest request)
        {
            var result = secondAllotService.UseTemp(request);
            return result ? new ApiResponse(ResponseType.OK, "选择成功") : new ApiResponse(ResponseType.Fail, "选择失败");
        }

        /// <summary>
        /// 刷新已选择模板
        /// </summary>
        /// <returns></returns>
        [Route("api/second/refreshtemp")]
        [HttpPost]
        public ApiResponse RefreshTemp([CustomizeValidator(RuleSet = "Refresh"), FromBody] UseTempRequest request)
        {
            secondAllotService.RefreshTemp(request);
            return new ApiResponse(ResponseType.OK);
        }

        #endregion 模板使用

        #region 二次绩效工作量配置

        /// <summary>
        /// 二次绩效工作量列表
        /// </summary>
        /// <returns></returns>
        [Route("api/second/workload/list")]
        [HttpPost]
        public ApiResponse WorkloadList([CustomizeValidator(RuleSet = "Query"), FromBody] WorkloadRequest request)
        {
            var result = secondAllotService.GetWorkloadList(request);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 二次绩效工作量新增
        /// </summary>
        /// <returns></returns>
        [Route("api/second/workload/add")]
        [HttpPost]
        public ApiResponse WorkloadAdd([CustomizeValidator(RuleSet = "Add"), FromBody] WorkloadRequest request)
        {
            var result = secondAllotService.WorkloadAdd(request);
            return new ApiResponse(result ? ResponseType.OK : ResponseType.Fail);
        }

        /// <summary>
        /// 二次绩效工作量修改
        /// </summary>
        /// <returns></returns>
        [Route("api/second/workload/update")]
        [HttpPost]
        public ApiResponse WorkloadUpdate([CustomizeValidator(RuleSet = "Update"), FromBody] WorkloadRequest request)
        {
            var result = secondAllotService.WorkloadUpdate(request);
            return new ApiResponse(result ? ResponseType.OK : ResponseType.Fail);
        }

        /// <summary>
        /// 二次绩效工作量删除
        /// </summary>
        /// <returns></returns>
        [Route("api/second/workload/delete")]
        [HttpPost]
        public ApiResponse WorkloadDelete([CustomizeValidator(RuleSet = "Delete"), FromBody] WorkloadRequest request)
        {
            var result = secondAllotService.WorkloadDelete(request.Id);
            return new ApiResponse(result ? ResponseType.OK : ResponseType.Fail);
        }

        /// <summary>
        /// 二次绩效单例奖励列表
        /// </summary>
        /// <returns></returns>
        [Route("api/second/single/list")]
        [HttpPost]
        public ApiResponse SingleAwards([FromBody] WorkloadRequest request)
        {
            var result = secondAllotService.GetSingleList(request);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 二次绩效工作量类型列表
        /// </summary>
        /// <returns></returns>
        [Route("api/second/worktype/list/{secondId}")]
        [HttpPost]
        public ApiResponse WorkTypeList([FromBody] WorkloadRequest request, int secondId)
        {
            var result = secondAllotService.WorkTypeList(request, secondId);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 获取二次分配 提取工作量带出字典
        /// </summary>
        /// <returns></returns>
        [Route("api/second/worktype/map/{secondId}")]
        [HttpPost]
        public ApiResponse WorkloadMap(int secondId)
        {
            var result = secondAllotService.WorkloadMap(secondId);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 保存二次绩效工作量类型
        /// </summary>
        /// <returns></returns>
        [Route("api/second/worktype/save/{secondId}")]
        [HttpPost]
        public ApiResponse SingleSave([FromBody] ag_workload_type request, int secondId)
        {
            if (request.HospitalId == 0)
                return new ApiResponse(ResponseType.ParameterError, "医院信息无效");
            if (string.IsNullOrEmpty(request.TypeName))
                return new ApiResponse(ResponseType.ParameterError, "填写参数无效");

            var result = secondAllotService.SaveWorkType(request, secondId);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 删除二次绩效工作量类型
        /// </summary>
        /// <returns></returns>
        [Route("api/second/worktype/delete")]
        [HttpPost]
        public ApiResponse SingleDelete([CustomizeValidator(RuleSet = "Delete"), FromBody] WorkloadRequest request)
        {
            var result = secondAllotService.DeleteWorkType(request);
            return result ? new ApiResponse(ResponseType.OK, "删除成功") : new ApiResponse(ResponseType.Fail, "删除失败");
        }

        #endregion 二次绩效工作量配置

        #region 二次绩效审核

        /// <summary>
        /// 提交审核
        /// </summary>
        /// <param name="request">二次绩效Id</param>
        /// <returns></returns>
        [HttpPost]
        [Route("/api/second/audit/submit")]
        public ApiResponse SubmitAudit(SubmitAuditRequest request)
        {
            var second = secondAllotService.GetSecondAllot(request.SecondId);
            if (second == null)
                return new ApiResponse(ResponseType.ParameterError, "二次绩效Id无效");
            if (second.Status == 3)
                return new ApiResponse(ResponseType.Fail, "该绩效已\"审核通过\",无需再次提交");

            var userid = claimService.GetUserId();
            var result = secondAllotService.AuditSubmit(second, userid);
            return result ? new ApiResponse(ResponseType.OK, "提交成功") : new ApiResponse(ResponseType.Fail, "提交失败");
        }

        /// <summary>
        /// 二次绩效审核列表
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("/api/second/audit/list")]
        public ApiResponse<List<ag_secondallot>> AuditList([FromBody] AllotDeptRequest request)
        {
            var list = secondAllotService.AuditList(request.AllotId);
            foreach (var item in list)
            {
                item.Remark += item.MarkStatus.HasValue && item.MarkStatus == 1 ? $" 已审计{item.MarkTime?.ToString("(yyyy-MM-dd HH:mm:ss)")}" : "";
            }

            return new ApiResponse<List<ag_secondallot>>(ResponseType.OK, "审核列表", list);
        }

        /// <summary>
        /// 二次绩效审核结果;驳回、成功
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("/api/second/audit/result")]
        public ApiResponse AuditResult([FromBody] SecondAuditRequest request)
        {
            var userid = claimService.GetUserId();
            var result = secondAllotService.ConfirmAudit(userid, request);
            //if (request.IsPass == 1)
            //{
            //    resultComputeService.SaveSecondReserved(request.SecondId);
            //}
            return result ? new ApiResponse(ResponseType.OK, "操作成功") : new ApiResponse(ResponseType.Fail, "操作失败");
        }

        /// <summary>
        /// 二次绩效审计
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("/api/second/mark")]
        public ApiResponse SecondMark([FromBody] SecondMarkRequest request)
        {
            if (request?.SecondIds == null || !request.SecondIds.Any())
                return new ApiResponse(ResponseType.ParameterError, "参数SecondIds无效！");

            var userid = claimService.GetUserId();
            var result = secondAllotService.SecondMark(userid, request.SecondIds);
            return result ? new ApiResponse(ResponseType.OK, "操作成功") : new ApiResponse(ResponseType.Fail, "操作失败");
        }

        /// <summary>
        /// 护理部二次绩效审核列表
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("/api/second/audit/nursingdept/list")]
        public ApiResponse<List<ag_secondallot>> NursingDeptlist([FromBody] AllotDeptRequest request)
        {
            var list = secondAllotService.NursingDeptlist(request.AllotId);
            return new ApiResponse<List<ag_secondallot>>(ResponseType.OK, "审核列表", list);
        }

        /// <summary>
        /// 护理部二次绩效审核结果;驳回、成功
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("/api/second/audit/nursingdept/result")]
        public ApiResponse NursingDeptAuditResult([FromBody] SecondAuditRequest request)
        {
            var userid = claimService.GetUserId();
            var result = secondAllotService.NursingDeptAudit(userid, request);
            return result ? new ApiResponse(ResponseType.OK, "操作成功") : new ApiResponse(ResponseType.Fail, "操作失败");
        }

        #endregion 二次绩效审核

        #region 二次绩效其他绩效

        /// <summary>
        /// 二次绩效其他绩效详情
        /// </summary>
        /// <returns></returns>
        [Route("api/second/other/list")]
        [HttpPost]
        public ApiResponse OtherList([FromBody] AgOtherRequest request)
        {
            var result = secondAllotDetails.GetOtherTempDetails(claimService.GetUserId(), request.SecondId, request.IsArchive, request.EmployeeSource);
            //var result = secondAllotDetails.GetOtherTempData(claimService.GetUserId(), request.SecondId, request.IsArchive, request.EmployeeSource, out decimal? realAmount);
            var obj = new
            {
                header = secondAllotService.OtherListHeader(request.SecondId, result?.Sum(t => t.RealAmount)),
                body = result,
            };
            return new ApiResponse(ResponseType.OK, obj);
        }

        /// <summary>
        /// 二次绩效其他绩效保存
        /// </summary>
        /// <returns></returns>
        [Route("api/second/other/save")]
        [HttpPost]
        public ApiResponse OtherSave([FromBody] AgOtherRequest request)
        {
            var result = secondAllotService.OtherSave(request.SecondId, request.Othersources);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 二次绩效其他绩效保存(new)
        /// </summary>
        /// <param name="secondId"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/other/save/{secondId}")]
        [HttpPost]
        public ApiResponse OtherSave(int secondId, [FromBody] SaveCollectData request)
        {
            secondAllotService.OtherSave(secondId, request);
            return new ApiResponse(ResponseType.OK);
        }

        #endregion 二次绩效其他绩效

        /// <summary>
        /// 二次绩效结果打印
        /// </summary>
        /// <returns></returns>
        [Route("api/second/print/{secondid}")]
        [HttpPost]
        public ApiResponse SecondPrint(int secondid)
        {
            var result = secondAllotService.Print(secondid);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 二次绩效结果打印(新版)
        /// </summary>
        /// <returns></returns>
        [Route("api/second/newprint/{secondid}")]
        [HttpPost]
        public ApiResponse SecondNewPrint(int secondid)
        {
            var result = secondAllotService.NewPrint(secondid);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 科主任/护士长管理绩效
        /// </summary>
        /// <returns></returns>
        [Route("api/second/deptcompute/{allotId}")]
        [HttpPost]
        public ApiResponse DeptComputeDetail(int allotId)
        {
            var userId = claimService.GetUserId();
            //var data = secondAllotService.DeptComputeDetail(userId, allotId, out int isShowManage);
            var data = secondAllotService.DeptComputeDetailList(userId, allotId, out int isShowManage);
            return new ApiResponse(ResponseType.OK, new { isShowManage, data });
        }

        /// <summary>
        /// 科主任/护士长管理绩效打印
        /// </summary>
        /// <returns></returns>
        [Route("api/second/print/deptcompute/{allotId}")]
        [HttpPost]
        public ApiResponse DeptComputePrint(int allotId)
        {
            var userId = claimService.GetUserId();
            var result = secondAllotService.DeptComputePrint(userId, allotId);
            return new ApiResponse(ResponseType.OK, result);
        }

        /// <summary>
        /// 获取二次绩效详情数据
        /// </summary>
        /// <param name="secondId"></param>
        /// <param name="employeeSource"></param>
        /// <returns></returns>
        [HttpPost("api/second/detail/{secondId}/{employeeSource}")]
        public ApiResponse GetSecondAllotDetail([FromRoute] int secondId, int employeeSource)
        {
            var detail = secondAllotService.GetSecondSavedData(claimService.GetUserId(), secondId, employeeSource);
            return new ApiResponse(ResponseType.OK, detail);
        }

        /// <summary>
        /// 获取工作量类型
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        [HttpPost("api/second/worktype/{secondId}")]
        public ApiResponse GetWorktypeDict([FromRoute] int secondId)
        {
            var detail = secondAllotService.GetWorkTypeDict(secondId);
            return new ApiResponse(ResponseType.OK, detail);
        }

        /// <summary>
        /// 获取工作量明细项
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        [HttpPost("api/second/workload/{secondId}")]
        public ApiResponse GetWorkloadDict([FromRoute] int secondId)
        {
            var detail = secondAllotService.GetWorkloadDict(secondId);
            return new ApiResponse(ResponseType.OK, detail);
        }

        /// <summary>
        /// 二次绩效项目内容保存
        /// </summary>
        /// <param name="secondId"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("api/second/savedata/{secondId}")]
        [AllowAnonymous]
        public ApiResponse SaveValue([FromRoute] int secondId, [FromBody] dynamic request)
        {
            secondAllotService.SaveSecondAllotData(secondId, request);
            return new ApiResponse(ResponseType.OK);
        }

        /// <summary>
        /// 二次绩效录入页面自动补全
        /// </summary>
        /// <returns></returns>
        [Route("api/second/autocomplete/{secondId}")]
        [HttpPost]
        public ApiResponse AutoCompleteBodyData([FromRoute] int secondId, SecondEmployeeRequest request)
        {
            var result = secondAllotService.AutoComplete(secondId, request);
            return new ApiResponse(ResponseType.OK, result);
        }

        #region 二次分配后台计算
        /// <summary>
        /// 二次绩效录入页面
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/load")]
        [HttpPost]
        public ApiResponse RedistributionLoad([FromBody] SecondLoadDto request)
        {
            try
            {
                if (!Enum.IsDefined(typeof(ComputeMode), request.ComputeMode))
                    throw new PerformanceException("暂不支持当前计算方式！");

                var overrideMode = EmployeeSource.Initial;
                if (Enum.IsDefined(typeof(EmployeeSource), request.OverrideMode))
                    overrideMode = (EmployeeSource)request.OverrideMode;

                var result = _redistributionService.Load(request.SecondId, (ComputeMode)request.ComputeMode, overrideMode);
                _redistributionService.ClearInvalidValue(result.Body?.Data);

                return new ApiResponse(ResponseType.OK, result);
            }
            catch (PerformanceException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                _logger.LogError($"二次绩效录入页面:{ex}");
                return new ApiResponse(ResponseType.Fail, "数据加载失败");
            }
        }


        /// <summary>
        /// 提交数据正确性检验
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/check")]
        [HttpPost]
        public ApiResponse RedistributionCheck([FromBody] SecondComputeDto request)
        {
            try
            {
                if (request?.Body == null)
                    throw new PerformanceException("提交空参数，无法查看计算结果！");

                var second = secondAllotService.GetSecondAllot(request.SecondId);
                if (second == null) throw new PerformanceException("参数SecondId无效！");

                var allot = _allotService.GetAllot(second.AllotId.Value);
                if (allot == null)
                    throw new PerformanceException("绩效记录不存在！");
                // 年资职称绩效占比与工作量绩效占比 校验
                var loads = _redistributionService.GetWorkLoads(allot, second);
                var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);

                if ((ComputeMode)request.ComputeMode != ComputeMode.NotCalculate)
                {
                    var workloadRatio = workloadGroups.Select(w => request.Head.GetValue($"Workload_Ratio_{w.Name}", 0m));
                    if (workloadRatio.Any(w => w > 1 || w < 0))
                        throw new PerformanceException("工作量绩效占比存在异常值！");

                    var seniorityTitlesAccountedPerformance = request.Head.GetValue(nameof(ag_headsource.SeniorityTitlesAccountedPerformance), 0m);
                    if (seniorityTitlesAccountedPerformance > 1 || seniorityTitlesAccountedPerformance < 0)
                        throw new PerformanceException("年资职称绩效占比值异常！");

                    if (seniorityTitlesAccountedPerformance + workloadRatio.Sum() > 1)
                        throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和，超过100%！");
                    else if (seniorityTitlesAccountedPerformance + workloadRatio.Sum() < 1)
                        throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和，不足100%！");
                }

                List<SecondComputeCheckResultDto> result = new List<SecondComputeCheckResultDto>();

                // 二次分配人员信息 校验
                var checkData = _redistributionService.CheckData(allot, second, (ComputeMode)request.ComputeMode, request.Body, loads);
                if (checkData != null && checkData.Count > 0)
                    result.AddRange(checkData);

                // 二次分配提交数据格式 校验
                var dic = _redistributionService.GetTableHeaderDictionary((ComputeMode)request.ComputeMode, allot, second, loads, workloadGroups);
                var checkFormat = _redistributionService.CheckFormat(request.Head, request.Body, dic);
                if (checkFormat != null && checkFormat.Count > 0)
                    result.AddRange(checkFormat);

                return new ApiResponse(ResponseType.OK, result);
            }
            catch (PerformanceException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                _logger.LogError($"提交数据正确性检验:{ex}");
                return new ApiResponse(ResponseType.Fail, "数据验证失败");
            }
        }

        /// <summary>
        /// 二次绩效结果计算
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/compute")]
        [HttpPost]
        public ApiResponse RedistributionCompute([FromBody] SecondComputeDto request)
        {
            try
            {
                if (!Enum.IsDefined(typeof(ComputeMode), request.ComputeMode))
                    throw new PerformanceException("暂不支持当前计算方式！");

                if (request?.Body == null)
                    throw new PerformanceException("提交空参数，无法查看计算结果！");

                var second = secondAllotService.GetSecondAllot(request.SecondId);
                if (second == null) throw new PerformanceException("参数SecondId无效！");

                var allot = _allotService.GetAllot(second.AllotId.Value);
                if (allot == null)
                    throw new PerformanceException("绩效记录不存在！");

                var hospital = _hospitalService.GetHopital(allot.HospitalId);
                if (hospital == null)
                    return new ApiResponse(ResponseType.Fail, "医院信息不存在");

                // 年资职称绩效占比与工作量绩效占比 校验
                var loads = _redistributionService.GetWorkLoads(allot, second);
                var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);

                if ((ComputeMode)request.ComputeMode != ComputeMode.NotCalculate)
                {
                    var workloadRatio = workloadGroups.Select(w => request.Head.GetValue($"Workload_Ratio_{w.Name}", 0m));
                    if (workloadRatio.Any(w => w > 1 || w < 0))
                        throw new PerformanceException("工作量绩效占比存在异常值！");

                    var seniorityTitlesAccountedPerformance = request.Head.GetValue(nameof(ag_headsource.SeniorityTitlesAccountedPerformance), 0m);
                    if (seniorityTitlesAccountedPerformance > 1 || seniorityTitlesAccountedPerformance < 0)
                        throw new PerformanceException("年资职称绩效占比值异常！");

                    if (seniorityTitlesAccountedPerformance + workloadRatio.Sum() > 1)
                        throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和，超过100%！");
                    else if (seniorityTitlesAccountedPerformance + workloadRatio.Sum() < 1)
                        throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和，不足100%！");
                }

                // 二次分配人员信息 校验
                var checkDatas = _redistributionService.CheckData(allot, second, (ComputeMode)request.ComputeMode, request.Body, loads);
                if (checkDatas != null && checkDatas.Any(w => w.Level == ResponseType.Error.ToString()))
                    return new ApiResponse(ResponseType.Fail, "数据验证未通过，请修复后查看计算结果！", checkDatas.Where(w => w.Level == ResponseType.Error.ToString()));

                // 清理无效数据 没有Tab标签的数据才是要计算的数据
                var cleanDatas = request.Body.Where(w => w.Count > 0 && w.GetValue(nameof(ResponseType), "") == ResponseType.OK.ToString()).ToList();
                if (cleanDatas == null || cleanDatas.Count == 0)
                    throw new PerformanceException("提交参数都是无效数据，请重新填写数据后查看计算结果！");

                // 计算提交数据结果
                _redistributionService.ResultCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, loads, workloadGroups, hospital);
                // 补充医院其他绩效
                _redistributionService.SupplementOtherPerfor(second, cleanDatas);
                // 重算部分数据
                _redistributionService.RedistributionCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, hospital);

                _redistributionService.ClearInvalidValue(cleanDatas);
                var dic = _redistributionService.GetTableHeaderDictionary((ComputeMode)request.ComputeMode, allot, second, loads, workloadGroups);
                _redistributionService.RowsExpand(allot, dic, cleanDatas);
                return new ApiResponse(ResponseType.OK, new { Head = request.Head, Body = cleanDatas, Dic = dic });
            }
            catch (PerformanceException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                _logger.LogError($"二次绩效结果计算:{ex}");
                return new ApiResponse(ResponseType.Fail, "计算失败");
            }
        }
        /// <summary>
        /// 二次绩效保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/save")]
        [HttpPost]
        public ApiResponse RedistributionSave([FromBody] SecondComputeDto request)
        {
            try
            {
                var second = secondAllotService.GetSecondAllot(request.SecondId);
                if (second == null) throw new PerformanceException("参数SecondId无效！");

                if (second.Status == (int)SecondAllot.Status.等待审核 || second.Status == (int)SecondAllot.Status.审核通过)
                    throw new PerformanceException("保存失败，当前二次分配已提交！");

                var allot = _allotService.GetAllot(second.AllotId.Value);
                if (allot == null)
                    throw new PerformanceException("绩效记录不存在！");
                var hospital = _hospitalService.GetHopital(allot.HospitalId);
                if (hospital == null)
                    return new ApiResponse(ResponseType.Fail, "医院信息不存在");

                var loads = _redistributionService.GetWorkLoads(allot, second);
                var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);
                // 二次分配人员信息 校验
                var checkDatas = _redistributionService.CheckData(allot, second, (ComputeMode)request.ComputeMode, request.Body, loads);
                if (checkDatas != null && checkDatas.Any(w => w.Level == ResponseType.Error.ToString()))
                    return new ApiResponse(ResponseType.Fail, "数据验证未通过，请修复后查看计算结果！", checkDatas.Where(w => w.Level == ResponseType.Error.ToString()));
                // 二次分配提交数据格式 校验
                var dic = _redistributionService.GetTableHeaderDictionary((ComputeMode)request.ComputeMode, allot, second, loads, workloadGroups);
                var checkFormat = _redistributionService.CheckFormat(request.Head, request.Body, dic);
                if (checkFormat != null && checkFormat.Any(w => w.Level == ResponseType.Error.ToString()))
                    return new ApiResponse(ResponseType.Fail, "数据验证未通过，请修复后查看计算结果！", checkFormat.Where(w => w.Level == ResponseType.Error.ToString()));

                // 清理无效数据 没有Tab标签的数据才是要计算的数据
                var cleanDatas = request.Body.Where(w => w.Count > 0 && w.GetValue(nameof(ResponseType), "") == ResponseType.OK.ToString()).ToList();
                if (cleanDatas == null || cleanDatas.Count == 0)
                    throw new PerformanceException("提交参数都是无效数据，请重新填写数据后保存！");

                // 计算提交数据结果
                _redistributionService.ResultCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, loads, workloadGroups, hospital);
                // 补充医院其他绩效
                _redistributionService.SupplementOtherPerfor(second, cleanDatas);
                // 重算部分数据
                _redistributionService.RedistributionCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, hospital);

                var result = secondAllotService.RedistributionSave(allot, second, request.Head, cleanDatas);
                return result ? new ApiResponse(ResponseType.OK) : new ApiResponse(ResponseType.Fail, "保存失败");
            }
            catch (PerformanceException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                _logger.LogError($"二次绩效保存:{ex}");
                return new ApiResponse(ResponseType.Fail, "保存失败");
            }
        }

        /// <summary>
        /// 二次绩效提交
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/submit")]
        [HttpPost]
        public ApiResponse RedistributionSubmit([FromBody] SecondComputeDto request)
        {
            try
            {
                var second = secondAllotService.GetSecondAllot(request.SecondId);
                if (second == null)
                    return new ApiResponse(ResponseType.ParameterError, "二次绩效Id无效");
                if (second.Status == 3)
                    return new ApiResponse(ResponseType.Fail, "该绩效已\"审核通过\",无需再次提交");

                var allot = _allotService.GetAllot(second.AllotId.Value);
                if (allot == null)
                    throw new PerformanceException("绩效记录不存在！");
                var hospital = _hospitalService.GetHopital(allot.HospitalId);
                if (hospital == null)
                    return new ApiResponse(ResponseType.Fail, "医院信息不存在");

                if (!new int[] { (int)AllotStates.绩效下发, (int)AllotStates.归档 }.Contains(allot.States))
                    throw new PerformanceException("绩效未下发，无法提交！");

                var loads = _redistributionService.GetWorkLoads(allot, second);
                var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);

                // 二次分配人员信息 校验
                var checkDatas = _redistributionService.CheckData(allot, second, (ComputeMode)request.ComputeMode, request.Body, loads);
                if (checkDatas != null && checkDatas.Any(w => w.Level == ResponseType.Error.ToString()))
                    return new ApiResponse(ResponseType.Fail, "数据验证未通过，请修复后查看计算结果！", checkDatas.Where(w => w.Level == ResponseType.Error.ToString()));

                // 二次分配提交数据格式 校验
                var dic = _redistributionService.GetTableHeaderDictionary((ComputeMode)request.ComputeMode, allot, second, loads, workloadGroups);
                var checkFormat = _redistributionService.CheckFormat(request.Head, request.Body, dic);
                if (checkFormat != null && checkFormat.Any(w => w.Level == ResponseType.Error.ToString()))
                    return new ApiResponse(ResponseType.Fail, "数据验证未通过，请修复后查看计算结果！", checkFormat.Where(w => w.Level == ResponseType.Error.ToString()));

                // 清理无效数据 没有Tab标签的数据才是要计算的数据
                var cleanDatas = request.Body.Where(w => w.Count > 0 && w.GetValue(nameof(ResponseType), "") == ResponseType.OK.ToString()).ToList();
                if (cleanDatas == null || cleanDatas.Count == 0)
                    throw new PerformanceException("提交参数都是无效数据，请重新填写数据后查看计算结果！");

                // 计算提交数据结果
                _redistributionService.ResultCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, loads, workloadGroups, hospital);
                // 补充医院其他绩效
                _redistributionService.SupplementOtherPerfor(second, cleanDatas);
                // 重算部分数据
                _redistributionService.RedistributionCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, hospital);

                var saveResult = secondAllotService.RedistributionSave(allot, second, request.Head, cleanDatas);

                if (saveResult)
                {
                    var res = _redistributionService.ValidationData(second);
                    if (!string.IsNullOrEmpty(res))
                        return new ApiResponse(ResponseType.Fail, $"提交数据中存在无效数据，已经被删除，确认正确后请重新提交；删除工号清单如下:{res}");

                    var userid = claimService.GetUserId();
                    var result = secondAllotService.AuditSubmit(second, userid);
                    if (result)
                        return new ApiResponse(ResponseType.OK, "提交成功");
                }
                return new ApiResponse(ResponseType.Fail, "提交失败");
            }
            catch (PerformanceException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.LogError($"二次绩效提交:{ex}");
                return new ApiResponse(ResponseType.Fail, "提交失败");
            }
        }

        /// <summary>
        /// 二次绩效撤回提交
        /// </summary>
        /// <returns></returns>
        [Route("api/second/redistribution/rollback/{secondId}")]
        [HttpPost]
        public ApiResponse RedistributionRollback(int secondId)
        {
            var result = secondAllotService.RollbackSubmit(secondId);
            if (result)
                return new ApiResponse(ResponseType.OK, "提交成功");

            return new ApiResponse(ResponseType.Fail, "提交失败");
        }
        /// <summary>
        /// 二次分配人员字典带出
        /// </summary> 
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/employee")]
        [HttpPost]
        public ApiResponse RedistributionEmployee([FromBody] SecondEmployeeDto request)
        {
            // 返回信息 
            var employees = _redistributionService.RedistributionEmployee(request);
            return new ApiResponse(ResponseType.OK, employees);
        }

        /// <summary>
        /// 二次分配审核后查看详情
        /// </summary> 
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("api/second/redistribution/detail")]
        [HttpPost]
        public ApiResponse RedistributionDetail([FromBody] SecondBaseDto request)
        {
            if (!Enum.IsDefined(typeof(ComputeMode), request.ComputeMode))
                throw new PerformanceException("暂不支持当前计算方式！");

            var second = secondAllotService.GetSecondAllot(request.SecondId);
            if (second == null) throw new PerformanceException("参数SecondId无效！");

            var allot = _allotService.GetAllot(second.AllotId.Value);
            if (allot == null)
                throw new PerformanceException("绩效记录不存在！");
            // 年资职称绩效占比与工作量绩效占比 校验
            var loads = _redistributionService.GetWorkLoads(allot, second);
            var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);

            // 返回信息 
            var (head, rows) = _redistributionService.RedistributionDetail((ComputeMode)request.ComputeMode, allot, second, workloadGroups);
            var dic = _redistributionService.GetTableHeaderDictionary((ComputeMode)request.ComputeMode, allot, second, loads, workloadGroups);
            _redistributionService.RowsExpand(allot, dic, rows);


            return new ApiResponse(ResponseType.OK, new { Head = head, Body = rows, Dic = dic });
        }
        #endregion

        /// <summary>
        /// 二次绩效上传文件
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        [Route("api/second/import")]
        [HttpPost]
        public ApiResponse Import([FromForm] IFormCollection form)
        {
            return secondAllotService.Import(form);
        }
        /// <summary>
        /// 二次绩效下载文件
        /// </summary>
        /// <param name="secondid"></param>
        /// <returns></returns>
        [HttpPost("api/second/download/{secondid}")]
        public IActionResult DownloadCurrentCalculationTable(int secondid)
        {
            var secondAllot = secondAllotService.GetSecondAllot(secondid);
            if (null == secondAllot)
                throw new PerformanceException("secondid不存在");

            if (string.IsNullOrEmpty(secondAllot.AttachFile))
                throw new PerformanceException("尚未上传文件");

            if (!FileHelper.IsExistFile(secondAllot.AttachFile))
                throw new PerformanceException("文件路径无效");

            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(secondAllot.AttachFile, FileMode.Open))
            {
                stream.CopyToAsync(memoryStream).Wait();
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            var provider = new FileExtensionContentTypeProvider();
            FileInfo fileInfo = new FileInfo(secondAllot.AttachFile);
            var memi = provider.Mappings[".xlsx"];
            return File(memoryStream, memi, Path.GetFileName(fileInfo.Name));
        }
    }
}
