using AutoMapper;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Performance.Services
{
    public class ComputeService : IAutoInjection
    {
        private readonly PerforResaccountRepository perforResaccountRepository;
        //private readonly PerforResaccountnurseRepository _perforResAccountnurseRepository;
        private readonly PerforPersheetRepository _perforPerSheetRepository;
        private readonly PerforImdataRepository _perforImDataRepository;
        private readonly PerforRescomputeRepository _perforRescomputeRepository;
        private readonly PerforResspecialunitRepository _perforResspecialunitRepository;
        private readonly PerforPeragainallotRepository _perforPeragainallotRepository;
        private readonly PerforUserRepository _perforUserRepository;
        private readonly PerforAgemployeeRepository _perforAgemployeeRepository;
        private readonly PerforResbaiscnormRepository perforResbaiscnormRepository;
        private readonly PerforCofincomeRepository _perforCofincomeRepository;
        private readonly PerforAgsecondallotRepository _perforAgsecondallotRepository;
        private readonly PerforAgcomputeRepository _perforAgcomputeRepository;

        public ComputeService(PerforResaccountRepository perforResaccountRepository,
            //PerforResaccountnurseRepository perforResAccountnurseRepository,
            PerforPersheetRepository perforPerSheetRepository,
            PerforImdataRepository perforImDataRepository,
            PerforRescomputeRepository perforRescomputeRepository,
            PerforResspecialunitRepository perforResspecialunitRepository,
            PerforPeragainallotRepository perforPeragainallotRepository,
            PerforUserRepository perforUserRepository,
            PerforAgemployeeRepository perforAgemployeeRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforCofincomeRepository perforCofincomeRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            PerforAgcomputeRepository perforAgcomputeRepository)
        {
            this.perforResaccountRepository = perforResaccountRepository;
            //this._perforResAccountnurseRepository = perforResAccountnurseRepository;
            this._perforPerSheetRepository = perforPerSheetRepository;
            this._perforImDataRepository = perforImDataRepository;
            this._perforRescomputeRepository = perforRescomputeRepository;
            this._perforResspecialunitRepository = perforResspecialunitRepository;
            this._perforPeragainallotRepository = perforPeragainallotRepository;
            this._perforUserRepository = perforUserRepository;
            this._perforAgemployeeRepository = perforAgemployeeRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this._perforCofincomeRepository = perforCofincomeRepository;
            this._perforAgsecondallotRepository = perforAgsecondallotRepository;
            this._perforAgcomputeRepository = perforAgcomputeRepository;
        }

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <param name="type">绩效基数核算参考对象</param>
        /// <returns></returns>
        public List<ResComputeResponse> GetCompute(int allotId, int type)
        {
            var data = new List<ResComputeResponse>();

            var items = EnumHelper.GetItems<AccountUnitType>();
            if (!items.Any(t => t.Value == type))
                throw new PerformanceException("参数错误，type无效");

            var conpute = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountType == items.FirstOrDefault(p => p.Value == type).Name)
                 ?.OrderByDescending(t => t.RealGiveFee).ThenBy(t => t.FitPeople).ThenBy(t => t.AccountingUnit).ToList();

            data = Mapper.Map<List<ResComputeResponse>>(conpute);
            data?.ForEach(t => t.WorkTime = string.IsNullOrEmpty(t.WorkTime) ? null : Convert.ToDateTime(t.WorkTime).ToString("yyyy-MM-dd"));
            return data?.OrderByDescending(t => t.AccountingUnit).ToList();
        }

        /// <summary>
        /// 返回特殊科室发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<res_specialunit> GetSpecial(int allotId)
        {
            var list = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId);
            if (list != null && list.Any())
            {
                list = list.OrderByDescending(t => t.AccountingUnit).ThenBy(t => t.RealGiveFee).ToList();
                return Mapper.Map<List<res_specialunit>>(list);
            }
            return new List<res_specialunit>();
        }

        /// <summary>
        /// 返回医生组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetDoctorPerformance(int allotId)
        {
            List<int> types = new List<int> { (int)UnitType.医生组, (int)UnitType.医技组 };
            var list = perforResaccountRepository.GetEntities(t => types.Contains(t.UnitType.Value) && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> doctor = Mapper.Map<List<DeptResponse>>(list);
            doctor?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return doctor;
        }

        /// <summary>
        /// 返回护理组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetNursePerformance(int allotId)
        {
            var list = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> nurse = Mapper.Map<List<DeptResponse>>(list);
            nurse?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return nurse;
        }

        /// <summary>
        /// 返回其他组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetOtherPerformance(int allotId)
        {
            var unitType = new List<int> { (int)UnitType.其他组, (int)UnitType.专家组 };
            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> other = Mapper.Map<List<DeptResponse>>(list);
            other?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return other;
        }

        /// <summary>
        /// 查看科室绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public DeptDetailResponse GetDepartmentDetail(int allotId, string department, int type)
        {
            if (type == 1)
            {
                var accountList = perforResaccountRepository.GetEntities(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.AccountingUnit == department);
                if (accountList != null)
                    return GetDepartmentDetail(allotId, accountList.First().ID, type);
            }
            else if (type == 2)
            {
                var accountList = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId && t.AccountingUnit == department);
                if (accountList != null)
                    return GetDepartmentDetail(allotId, accountList.First().ID, type);
            }
            return null;
        }


        /// <summary>
        /// 返回科室详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="accountId"></param>
        /// <param name="type"> 1 医生组 2 护理组</param>
        /// <returns></returns>
        public DeptDetailResponse GetDepartmentDetail(int allotId, int accountId, int type)
        {
            var sheetList = _perforPerSheetRepository.GetEntities(t => t.AllotID == allotId);
            if (type == 1)
            {
                var doctor = perforResaccountRepository.GetEntity(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);

                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = Mapper.Map<PerDataAccountBaisc>(doctor),
                    Economic = new List<DeptDetail>(),
                    Workload = new List<DeptDetail>()
                };

                var sheetWorkload = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeDoctorWorkload);
                if (sheetWorkload == null)
                    return null;
                var dataWorkloadList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetWorkload.ID && t.IsTotal != 1 && t.AccountingUnit == doctor.AccountingUnit);
                if (dataWorkloadList != null && dataWorkloadList.Count > 0)
                    dataWorkloadList.ForEach(t => response.Workload.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                var sheetEconomic = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                if (sheetEconomic == null)
                    return null;
                var dataEconomicList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetEconomic.ID && t.UnitType == 1 && t.IsTotal != 1 && t.AccountingUnit == doctor.AccountingUnit);
                if (dataEconomicList != null && dataEconomicList.Count > 0)
                    dataEconomicList.ForEach(t => response.Economic.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                return response;
            }
            else if (type == 2)
            {
                var nurse = perforResaccountRepository.GetEntity(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);
                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = Mapper.Map<PerDataAccountBaisc>(nurse),
                    Economic = new List<DeptDetail>(),
                    Workload = new List<DeptDetail>()
                };

                var sheetWorkload = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeNurseWorkload);
                if (sheetWorkload == null)
                    return null;
                var dataWorkloadList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetWorkload.ID && t.IsTotal != 1 && t.AccountingUnit == nurse.AccountingUnit);
                if (dataWorkloadList != null && dataWorkloadList.Count > 0)
                    dataWorkloadList.ForEach(t => response.Workload.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                var sheetEconomic = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                if (sheetEconomic == null)
                    return null;
                var dataEconomicList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetEconomic.ID && t.UnitType == 2 && t.IsTotal != 1 && t.AccountingUnit == nurse.AccountingUnit);
                if (dataEconomicList != null && dataEconomicList.Count > 0)
                    dataEconomicList.ForEach(t => response.Economic.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));
                return response;
            }

            return null;
        }

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<ComputeResponse> AllCompute(int allotId)
        {
            var list = new List<ComputeResponse>();
            var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId)?.OrderByDescending(t => t.AccountingUnit);
            list = Mapper.Map<List<ComputeResponse>>(allot);
            list?.ForEach(t => t.Source = "一次绩效");
            var again = _perforAgcomputeRepository.GetEntities(t => t.AllotId == allotId);
            if (again != null && again.Any())
            {
                var group = again.GroupBy(t => new { t.Department, t.WorkPost, t.PersonName })
                    .Select(t => new
                    {
                        department = t.Key.Department,
                        jobtitle = t.Key.WorkPost,
                        name = t.Key.PersonName,
                        fee = t.Sum(g => g.RealGiveFee)
                    });
                list.AddRange(group.Select(t => new ComputeResponse
                {
                    Source = "二次绩效",
                    AccountingUnit = t.department,
                    JobTitle = t.jobtitle,
                    EmployeeName = t.name,
                    RealGiveFee = t.fee
                }).OrderByDescending(t => t.AccountingUnit));
            }
            return list;
        }

        public res_compute GetComputeSingle(int computeid)
        {
            return _perforRescomputeRepository.GetEntity(t => t.ID == computeid);
        }

        /// <summary>
        /// 修改实发绩效
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public res_compute UpdateRealfee(ComputerRequest request, int userId, string realName)
        {
            var compute = _perforRescomputeRepository.GetEntity(t => t.ID == request.ComputeId);
            var log = JsonHelper.Deserialize<List<ChangeLog>>(compute.ChangeLog);
            log = log ?? new List<ChangeLog>();
            log.Add(new ChangeLog
            {
                uid = userId,
                user = realName,
                date = DateTime.Now,
                value = compute.RealGiveFee
            });
            compute.RealGiveFee = request.RealGiveFee;
            compute.ChangeLog = JsonHelper.Serialize(log);
            if (!_perforRescomputeRepository.Update(compute))
                throw new PerformanceException("修改失败");

            return compute;
        }

        /// <summary>
        /// 返回绩效平均值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public List<res_baiscnorm> GetBaiscnorm(int allotId)
        {
            return perforResbaiscnormRepository.GetEntities(t => t.AllotID == allotId).OrderBy(t => t.PositionName).ToList();
        }

        /// <summary>
        /// 返回科室详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="accountId"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public DeptDataDetails DeptDetail(int accountId)
        {
            var sheetType = new List<int> { (int)SheetType.Income, (int)SheetType.OtherIncome, (int)SheetType.Expend, (int)SheetType.Workload };
            var doctor = perforResaccountRepository.GetEntity(t => t.ID == accountId);
            string typeValue = EnumHelper.GetItems<UnitType>().FirstOrDefault(t => t.Value == doctor.UnitType).Name.ToString();
            DeptDataDetails deptDetails = new DeptDataDetails
            {
                Pandect = Mapper.Map<PerDataAccountBaisc>(doctor),
                Detail = new List<DetailDtos>()
            };
            int type = doctor.UnitType.Value;
            if (type == (int)UnitType.专家组 || type == (int)UnitType.其他组)
                type = 1;
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == doctor.AllotID && t.UnitType == type && t.AccountingUnit == doctor.AccountingUnit);
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == doctor.AllotID);

            //科室经济
            var sheetEconomic = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
            var dataEconomicList = basicData.Where(t => t.SheetID == sheetEconomic?.ID && t.UnitType == type && t.IsTotal != 1 && t.AccountingUnit == doctor.AccountingUnit).ToList();
            var economic = dataEconomicList?.Select(t => new DeptDetail { ItemName = t.TypeName.Replace($"({typeValue})", ""), ItemValue = t.CellValue ?? 0 });

            Regex reg = new Regex("[0-9]*");
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    var sheetName = reg.Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    var sheetData = basicData.Where(t => t.SheetID == sheet.ID).ToList();
                    if (sheetData == null || !sheetData.Any()) continue;

                    var item = new DetailDtos
                    {
                        ItemName = sheetName,
                        IncomeType = sheet.SheetType == (int)SheetType.Expend ? 2 : sheet.SheetType == (int)SheetType.Workload ? 3 : 1,
                        Amount = (sheetName.Contains("工作量") ? doctor.WorkloadFee : economic.FirstOrDefault(t => t.ItemName.Contains(sheetName))?.ItemValue) ?? 0m,
                        Items = sheetData?.Select(t => new DetailModule
                        {
                            ItemName = t.TypeName,
                            CellValue = t.CellValue,
                            Factor = t.FactorValue,
                            ItemValue = t.IsFactor == 1 ? (t.CellValue * (t.FactorValue ?? 0)) : t.CellValue
                        }).ToList()
                    };
                    deptDetails.Detail.Add(item);
                }
            }
            return deptDetails;
        }


        public int GetAccountId(int secondId)
        {
            var second = _perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second != null)
            {
                var unitType = EnumHelper.GetItems<UnitType>().FirstOrDefault(t => t.Name == second.UnitType);
                var account = perforResaccountRepository.GetEntity(t => t.AllotID == second.AllotId && t.UnitType == unitType.Value && t.Department == second.Department);
                return account?.ID ?? 0;
            }
            return 0;
        }
    }
}
