using AutoMapper;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Performance.Services
{
    public class SecondAllotService : IAutoInjection
    {
        private readonly Application application;
        private readonly PerforUserRepository perforUserRepository;
        private readonly PerforUserhospitalRepository perforUserhospitalRepository;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforAgsecondallotRepository perforAgsecondallotRepository;
        private readonly PerforResaccountRepository perforResaccountRepository;
        private readonly PerforUserroleRepository userroleRepository;
        private readonly PerforAgworkloadRepository perforAgworkloadRepository;
        private readonly PerforAgtempRepository perforAgtempRepository;
        private readonly PerforAgtempitemRepository perforAgtempitemRepository;
        private readonly PerforAgfixatitemRepository perforAgfixatitemRepository;
        private readonly PerforAgusetempRepository perforAgusetempRepository;
        private readonly PerforAgcomputeRepository perforAgcomputeRepository;
        private readonly PerforCofagainRepository perforCofagainRepository;

        public SecondAllotService(IOptions<Application> application,
            PerforUserRepository perforUserRepository,
            PerforUserhospitalRepository perforUserhospitalRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            PerforResaccountRepository perforResaccountRepository,
            PerforUserroleRepository userroleRepository,
            PerforAgworkloadRepository perforAgworkloadRepository,
            PerforAgtempRepository perforAgtempRepository,
            PerforAgtempitemRepository perforAgtempitemRepository,
            PerforAgfixatitemRepository perforAgfixatitemRepository,
            PerforAgusetempRepository perforAgusetempRepository,
            PerforAgcomputeRepository perforAgcomputeRepository,
            PerforCofagainRepository perforCofagainRepository)
        {
            this.application = application.Value;
            this.perforUserRepository = perforUserRepository;
            this.perforUserhospitalRepository = perforUserhospitalRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforAgsecondallotRepository = perforAgsecondallotRepository;
            this.perforResaccountRepository = perforResaccountRepository;
            this.userroleRepository = userroleRepository;
            this.perforAgworkloadRepository = perforAgworkloadRepository;
            this.perforAgtempRepository = perforAgtempRepository;
            this.perforAgtempitemRepository = perforAgtempitemRepository;
            this.perforAgfixatitemRepository = perforAgfixatitemRepository;
            this.perforAgusetempRepository = perforAgusetempRepository;
            this.perforAgcomputeRepository = perforAgcomputeRepository;
            this.perforCofagainRepository = perforCofagainRepository;
        }

        /// <summary>
        /// 获取二次绩效列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<SecondListResponse> GetSecondList(int userId)
        {
            var user = perforUserRepository.GetEntity(t => t.ID == userId);
            if (user == null)
                throw new NotImplementedException("人员ID无效");
            var role = userroleRepository.GetEntity(t => t.UserID == userId);
            var hospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
            if (hospital == null)
                throw new NotImplementedException("人员未选择医院");
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospital.HospitalID && new List<int> { 6, 8 }.Contains(t.States));
            if (allotList == null || allotList.Count == 0)
                throw new NotImplementedException("该医院未生成绩效");

            var allotListId = allotList.Select(t => t.ID).ToList();
            var secondList = perforAgsecondallotRepository.GetEntities(t => allotListId.Contains(t.AllotId.Value) && t.Department == user.Department);
            //各科室绩效分配结果
            var accountList = perforResaccountRepository.GetEntities(t => allotListId.Contains(t.AllotID.Value) && t.Department == user.Department);
            //取得未生成二次绩效的绩效id  
            var exceptListId = secondList == null ? allotListId : allotListId.Except(secondList.Select(t => t.AllotId.Value));

            #region 初始化二次绩效
            List<ag_secondallot> newSecond = new List<ag_secondallot>();
            foreach (var item in exceptListId)
            {
                var allot = allotList.FirstOrDefault(t => t.ID == item);
                if (allot == null) continue;

                res_account account = null;
                if (role.RoleID == application.DirectorRole)
                    account = accountList.FirstOrDefault(t => t.AllotID == item && (t.UnitType == (int)UnitType.医生组 || t.UnitType == (int)UnitType.医技组));
                else if (role.RoleID == application.NurseRole)
                    account = accountList.FirstOrDefault(t => t.AllotID == item && t.UnitType == (int)UnitType.护理组);

                if (account == null) continue;

                var second = new ag_secondallot
                {
                    AllotId = item,
                    Year = allot.Year,
                    Month = allot.Month,
                    Department = user.Department,
                    UnitType = ((UnitType)account.UnitType).ToString(),
                    RealGiveFee = account.RealGiveFee
                };
                newSecond.Add(second);
            }
            #endregion

            if (newSecond.Count > 0)
            {
                perforAgsecondallotRepository.AddRange(newSecond.ToArray());
                if (secondList == null)
                    secondList = newSecond;
                else
                    secondList.AddRange(newSecond);
            }

            var list = Mapper.Map<List<SecondListResponse>>(secondList);
            list?.ForEach(t => t.IsArchive = allotList.FirstOrDefault(a => a.ID == t.AllotId).States == 8 ? 1 : 0);
            return list;
        }

        /// <summary>
        /// 获取模板列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<SecondTempResponse> GetTemp(int hospitalid)
        {
            var temps = perforAgtempRepository.GetEntities();
            if (temps != null && temps.Any())
            {
                var useTemp = perforAgusetempRepository.GetEntity(t => t.HospitalId == hospitalid);
                var secondTemps = Mapper.Map<List<SecondTempResponse>>(temps);
                secondTemps.ForEach(t => t.IsSelected = t.Id == useTemp.UseTempId);
                return secondTemps;
            }
            return new List<SecondTempResponse>();
        }

        /// <summary>
        /// 使用模板
        /// </summary>
        /// <param name="tempId"></param>
        /// <returns></returns>
        public bool UseTemp(UseTempRequest request)
        {
            var temp = perforAgtempRepository.GetEntity(t => t.Id == request.TempId);
            if (temp == null)
                throw new PerformanceException("参数tempId 无效");

            var result = false;
            var entity = perforAgusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            if (entity == null)
            {
                entity = Mapper.Map<ag_usetemp>(request);
                result = perforAgusetempRepository.Add(entity);
            }
            else
            {
                entity.UseTempId = request.TempId;
                result = perforAgusetempRepository.Update(entity);
                //删除多余的数据
                if (result)
                {
                    //获取固定模板列头
                    var tempItem = perforAgtempitemRepository.GetEntities(t => t.TempId == request.TempId);

                    var headItems = Mapper.Map<List<HeadItem>>(tempItem) ?? new List<HeadItem>();
                    //获取工作量列头
                    var workItem = perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
                    if (workItem != null && workItem.Count > 0)
                    {
                        var workDtos = Mapper.Map<List<HeadItem>>(workItem);
                        workDtos.ForEach(t => { t.Type = 3; });
                        headItems.AddRange(workDtos);
                    }
                    List<ag_fixatitem> list = new List<ag_fixatitem>();

                    //获取数据
                    var fixatList = perforAgfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId);
                    foreach (var item in headItems)
                    {
                        list.AddRange(fixatList.Where(t => t.ItemName == item.FiledName && t.Type == item.Type));
                    }
                    if (list != null && list.Count > 0)
                    {
                        var delList = fixatList.Except(list);
                        perforAgfixatitemRepository.RemoveRange(delList.ToArray());
                    }


                }
            }
            return result;
        }

        /// <summary>
        /// 应用模板
        /// </summary>
        /// <returns></returns>
        public void RefreshTemp(UseTempRequest request)
        {
            var usetemp = perforAgusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            if (usetemp == null)
                throw new PerformanceException("参数usetempId 无效");
            //获取工作量列头
            var workItem = perforAgworkloadRepository.GetEntities(t => t.HospitalId == usetemp.HospitalId && t.Department == usetemp.Department && t.UnitType == usetemp.UnitType);
            //获取固定模板列头
            var tempItem = perforAgtempitemRepository.GetEntities(t => t.TempId == usetemp.UseTempId);
            var tempHeader = workItem == null ? tempItem.Select(t => t.FiledName) : tempItem.Select(t => t.FiledName).Union(workItem?.Select(t => t.ItemName));

            //获取数据
            var fixatList = perforAgfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId);
            if (fixatList == null || fixatList.Count == 0)
                throw new PerformanceException("未录入数据");

            //更新系数、排序
            fixatList.ForEach(t =>
            {
                t.Sort = workItem?.FirstOrDefault(w => w.ItemName == t.ItemName)?.Sort;
                t.FactorValue = workItem?.FirstOrDefault(w => w.ItemName == t.ItemName)?.FactorValue;
            });
            perforAgfixatitemRepository.UpdateRange(fixatList.ToArray());
            //删除  列 不存在的数据
            var header = fixatList.Select(t => t.ItemName).Distinct();
            var delItems = header.Except(tempHeader);
            if (delItems != null && delItems.Count() > 0)
                perforAgfixatitemRepository.RemoveRange(fixatList.Where(t => delItems.Contains(t.ItemName)).ToArray());
            //添加  新增列 的数据
            var addItems = new List<ag_fixatitem>();
            fixatList.Select(t => t.RowNumber).Distinct().ToList().ForEach(t =>
            {
                addItems.AddRange(tempHeader.Except(header)?.Select(s => new ag_fixatitem
                {
                    ItemName = s,
                    RowNumber = t,
                    AllotId = fixatList.First().AllotId,
                    SecondId = fixatList.First().SecondId,
                    UnitType = fixatList.First().UnitType,
                    Sort = tempItem?.FirstOrDefault(w => w.FiledName == s)?.Sort ?? workItem?.FirstOrDefault(w => w.ItemName == s)?.Sort,
                    FactorValue = workItem?.FirstOrDefault(w => w.ItemName == s)?.FactorValue,
                    Type = tempItem?.FirstOrDefault(w => w.FiledName == s)?.Type ?? 3,
                    SourceType = tempItem?.FirstOrDefault(w => w.FiledName == s)?.SourceType ?? 1,
                }));
            });
            if (addItems != null && addItems.Count() > 0)
                perforAgfixatitemRepository.AddRange(addItems.ToArray());
        }

        /// <summary>
        /// 获取工作量列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<ag_workload> GetWorkloadList(WorkloadRequest request)
        {
            return perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
        }

        /// <summary>
        /// 二次绩效项录入保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool SaveValue(List<ag_fixatitem> request)
        {
            var secondId = request.First().SecondId;
            var second = perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("二次绩效ID不存在");
            var fixatitems = perforAgfixatitemRepository.GetEntities(t => t.SecondId == secondId);
            foreach (var item in request)
            {
                if (fixatitems != null && fixatitems.Any(t => t.SecondId == secondId && t.RowNumber == item.RowNumber && t.ItemName == item.ItemName))
                {
                    var cellItem = fixatitems.First(t => t.SecondId == secondId && t.RowNumber == item.RowNumber && t.ItemName == item.ItemName);
                    cellItem.ItemValue = item.ItemValue;
                    cellItem.Sort = item.Sort;
                    cellItem.SourceType = item.SourceType;
                    cellItem.Type = item.Type;
                    cellItem.UnitType = item.UnitType;
                    perforAgfixatitemRepository.Update(cellItem);
                }
                else
                {
                    perforAgfixatitemRepository.Add(item);
                }
            }
            return true;
        }

        /// <summary>
        /// 二次绩效分配结果保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool SaveCompute(List<ag_compute> request)
        {
            var secondId = request.First().SecondId;
            var second = perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("二次绩效ID不存在");
            if (second.Status == 2)
                throw new PerformanceException("二次绩效已提交，无法重复提交");

            var compute = perforAgcomputeRepository.GetEntities(t => t.SecondId == secondId);
            foreach (var item in request)
            {
                if (compute != null && compute.Any(t => t.SecondId == secondId && t.Department == item.Department && t.PersonName == item.PersonName))
                {
                    var cellItem = compute.First(t => t.SecondId == secondId && t.Department == item.Department && t.PersonName == item.PersonName);
                    cellItem.RealGiveFee = item.RealGiveFee;
                    perforAgcomputeRepository.Update(cellItem);
                }
                else
                {
                    perforAgcomputeRepository.Add(item);
                }
            }
            return true;
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkloadAdd(WorkloadRequest request)
        {
            var workloadList = perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            if (workloadList != null && workloadList.Any(t => t.ItemName == request.ItemName))
                throw new PerformanceException("项目名称重复");
            ag_workload workload = new ag_workload
            {
                HospitalId = request.HospitalId,
                Department = request.Department,
                UnitType = request.UnitType,
                FactorValue = request.FactorValue ?? 1,
                ItemName = request.ItemName,
                Sort = request.Sort ?? 1,
            };
            var result = perforAgworkloadRepository.Add(workload);
            if (result)
            {
                workload.ItemId = $"Feild{workload.Id}";
                perforAgworkloadRepository.Update(workload);
            }

            return result;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkloadUpdate(WorkloadRequest request)
        {
            var workloadList = perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            if (workloadList != null && workloadList.Any(t => t.Id != request.Id && t.ItemName == request.ItemName))
                throw new PerformanceException("项目名称重复");

            var workload = workloadList.FirstOrDefault(t => t.Id == request.Id);
            workload.HospitalId = request.HospitalId;
            workload.Department = request.Department;
            workload.UnitType = request.UnitType;
            workload.FactorValue = request.FactorValue;
            workload.ItemName = request.ItemName;
            workload.Sort = request.Sort;
            workload.ItemId = $"Feild{workload.Id}";

            return perforAgworkloadRepository.Update(workload);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool WorkloadDelete(int id)
        {
            var workload = perforAgworkloadRepository.GetEntity(t => t.Id == id);
            return perforAgworkloadRepository.Remove(workload);
        }

        /// <summary>
        /// 二次绩效详情
        /// </summary>
        /// <returns></returns>
        public SecondResponse GetSecondDetail(UseTempRequest request)
        {
            var usetemp = perforAgusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            if (usetemp == null)
                throw new PerformanceException("当前科室暂未配置绩效模板");
            //获取固定模板列头
            var tempItem = perforAgtempitemRepository.GetEntities(t => t.TempId == usetemp.UseTempId);

            var headItems = Mapper.Map<List<HeadItem>>(tempItem) ?? new List<HeadItem>();
            //获取工作量列头
            var workItem = perforAgworkloadRepository.GetEntities(t => t.HospitalId == usetemp.HospitalId && t.Department == usetemp.Department && t.UnitType == usetemp.UnitType);
            if (workItem != null && workItem.Count > 0)
            {
                var workDtos = Mapper.Map<List<HeadItem>>(workItem);
                workDtos.ForEach(t => { t.Type = 3; });
                headItems.AddRange(workDtos);
            }

            var result = new SecondResponse { HeadItems = headItems, BodyItems = new List<BodyItem>() };
            //获取数据
            var fixatList = perforAgfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId && t.RowNumber.HasValue);
            if (request.IsArchive == 1)
            {
                if (fixatList == null || fixatList.Count == 0)
                    throw new PerformanceException("绩效归档时，尚未添加数据。");
                else
                {
                    var existHead = fixatList.Select(t => new { FiledName = t.ItemName, Sort = t.Sort.Value, SourceType = t.SourceType.Value, Type = t.Type.Value, FactorValue = t.FactorValue.Value }).Distinct().ToList();
                    headItems = existHead.Select(t => new HeadItem
                    {
                        FiledId = headItems.FirstOrDefault(h => h.FiledName == t.FiledName && h.Type == t.Type)?.FiledId ?? "无FiledId",
                        FiledName = t.FiledName,
                        Sort = t.Sort,
                        SourceType = t.SourceType,
                        Type = t.Type,
                        FactorValue = t.FactorValue
                    }).Where(t => t.FiledId != "无FiledId").ToList();
                }
            }

            if (fixatList != null && fixatList.Count > 0)
            {
                //补充数据
                var rows = fixatList.Select(t => t.RowNumber.Value).Distinct();
                foreach (var row in rows)
                {
                    var header = row == -1 ? headItems.Where(t => t.Type == 1).ToList() : headItems.Where(t => t.Type != 1).ToList();
                    foreach (var item in header)
                    {
                        var bodyItem = new BodyItem
                        {
                            RowNumber = row,
                            FiledId = item.FiledId,
                            FiledName = item.FiledName,
                            FactorValue = item.FactorValue,
                            SourceType = item.SourceType,
                            Type = item.Type,
                            Sort = item.Sort,
                            Value = fixatList.FirstOrDefault(t => t.RowNumber == row && t.ItemName == item.FiledName)?.ItemValue
                        };
                        result.BodyItems.Add(bodyItem);
                    }
                }
            }
            else
            {
                var second = perforAgsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
                var config = perforCofagainRepository.GetEntities(t => t.AllotID == second.AllotId && t.Department == request.Department) ?? new List<cof_again>();
                config.Add(new cof_again { TypeName = "绩效合计(考核后)", Value = second.RealGiveFee });
                foreach (var item in headItems.Where(t => t.Type == 1))
                {
                    var bodyItem = new BodyItem
                    {
                        RowNumber = -1,
                        FiledId = item.FiledId,
                        FiledName = item.FiledName,
                        FactorValue = item.FactorValue,
                        SourceType = item.SourceType,
                        Type = item.Type,
                        Sort = item.Sort,
                        Value = config.FirstOrDefault(t => t.TypeName == item.FiledName)?.Value.ToString()
                    };
                    result.BodyItems.Add(bodyItem);
                }
                result.BodyItems.FirstOrDefault(t => t.FiledName == "发放月份").Value = $"{second.Year}年{second.Month}月";
            }
            return result;
        }
    }
}
