using AutoMapper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Services.AllotCompute;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Performance.Services
{
    public class EmployeeService : IAutoInjection
    {
        private PerforImemployeeRepository perforImemployeeRepository;
        private PerforPersheetRepository perforPersheetRepository;
        private PerforPerallotRepository perforPerallotRepository;
        private PerforImemployeeclinicRepository perforImemployeeclinicRepository;
        private PerforUserhospitalRepository perforUserhospitalRepository;
        private PerforPerallotRepository perallotRepository;
        private PerforPerapramountRepository perapramountRepository;
        private PerforImemployeelogisticsRepository perforImemployeelogisticsRepository;
        private PerforUserroleRepository userroleRepository;
        private PerforPeremployeeRepository peremployeeRepository;
        private PerforUserRepository userRepository;
        private ILogger<EmployeeService> logger;

        public EmployeeService(PerforImemployeeRepository perforImemployeeRepository,
            PerforPersheetRepository perforPersheetRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforUserhospitalRepository perforUserhospitalRepository,
            PerforPerallotRepository perallotRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforImemployeelogisticsRepository perforImemployeelogisticsRepository,
            PerforUserroleRepository userroleRepository,
            PerforPeremployeeRepository peremployeeRepository,
            PerforUserRepository userRepository,
            ILogger<EmployeeService> logger)
        {
            this.perforImemployeeRepository = perforImemployeeRepository;
            this.perforPersheetRepository = perforPersheetRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforImemployeeclinicRepository = perforImemployeeclinicRepository;
            this.perforUserhospitalRepository = perforUserhospitalRepository;
            this.perallotRepository = perallotRepository;
            this.perapramountRepository = perapramountRepository;
            this.perforImemployeelogisticsRepository = perforImemployeelogisticsRepository;
            this.userroleRepository = userroleRepository;
            this.peremployeeRepository = peremployeeRepository;
            this.userRepository = userRepository;
            this.logger = logger;
        }

        #region 行政人员

        /// <summary>
        ///获取人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee GetEmployee(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            return employee;
        }

        /// <summary>
        ///获取人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee> GetEmployeeList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeeRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee Insert(EmployeeRequest request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.Employee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "行政人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            var employee = Mapper.Map<im_employee>(request);
            employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.SheetID = sheet.ID;
            perforImemployeeRepository.Add(employee);
            return employee;
        }

        /// <summary>
        /// 修改人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee Update(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.AccountType = request.AccountType;
            employee.Department = request.Department;
            employee.FitPeople = request.FitPeople;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Attendance = request.Attendance;
            employee.PeopleNumber = request.PeopleNumber;
            employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            employee.Punishment = request.Punishment;
            employee.Adjust = request.Adjust;
            employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeeRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool Delete(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeeRepository.Remove(employee);
        }

        #endregion 行政人员

        #region 临床人员

        /// <summary>
        ///获取临床人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee_clinic> GetEmployeeClinicList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_clinic InsertClinic(im_employee_clinic request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.ClinicEmployee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "临床人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            request.SheetID = sheet.ID;
            perforImemployeeclinicRepository.Add(request);
            return request;
        }

        /// <summary>
        /// 修改临床人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_clinic UpdateClinic(im_employee_clinic request)
        {
            var employee = perforImemployeeclinicRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.UnitType = request.UnitType;
            employee.Department = request.Department;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Efficiency = request.Efficiency;
            employee.Scale = request.Scale;
            employee.Management = request.Management;
            employee.Attendance = request.Attendance;
            employee.PeopleNumber = request.PeopleNumber;
            employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            employee.Punishment = request.Punishment;
            employee.Adjust = request.Adjust;
            employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeeclinicRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DeleteClinic(im_employee_clinic request)
        {
            var employee = perforImemployeeclinicRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeeclinicRepository.Remove(employee);
        }

        #endregion 临床人员

        #region 行政后勤

        /// <summary>
        ///获取临床人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee_logistics> GetEmployeeLogisticsList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeelogisticsRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_logistics InsertLogistics(im_employee_logistics request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.LogisticsEmployee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "临床人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            request.SheetID = sheet.ID;
            perforImemployeelogisticsRepository.Add(request);
            return request;
        }

        /// <summary>
        /// 修改临床人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_logistics UpdateLogistics(im_employee_logistics request)
        {
            var employee = perforImemployeelogisticsRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.AccountType = request.AccountType;
            employee.Department = request.Department;
            employee.FitPeople = request.FitPeople;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            //employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Attendance = request.Attendance;
            //employee.PeopleNumber = request.PeopleNumber;
            //employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            //employee.Punishment = request.Punishment;
            //employee.Adjust = request.Adjust;
            //employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeelogisticsRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DeleteLogistics(im_employee_clinic request)
        {
            var employee = perforImemployeelogisticsRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeelogisticsRepository.Remove(employee);
        }

        #endregion 行政后勤

        /// <summary>
        /// 人事科修改后提交状态
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public bool Audit(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null || !new List<int> { (int)AllotStates.GenerateSucceed, (int)AllotStates.GenerateAccomplish }.Contains(allot.States))
                throw new PerformanceException("绩效信息错误");
            if ((int)AllotStates.Archive == allot.States)
                throw new PerformanceException("绩效已归档，暂不支持修改");

            allot.Generate = (int)AllotGenerate.PersonnelOffice;
            return perforPerallotRepository.Update(allot);
        }

        public List<per_apr_amount> GetAprList(int allotId, int userId)
        {
            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            var list = new List<per_apr_amount>();
            if (new int[] { 1, 2, 5 }.Contains(userrole.RoleID))   //  绩效管理员、医院管理员、绩效核算办查看所有科室的数据
                list = perapramountRepository.GetEntities(t => t.AllotId == allotId && (t.Amount ?? 0) != 0);
            else
                list = perapramountRepository.GetEntities(t => t.AllotId == allotId && (t.Amount ?? 0) != 0 && t.CreateUser == userId);
            if (list != null && list.Any())
                list = list.OrderBy(t => t.DoctorName).ToList();

            return list;
        }

        public List<per_apr_amount> GetAprList(int allotId, string department)
        {
            var list = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Amount.HasValue && t.Amount != 0 && (t.TypeInDepartment ?? "") == department);
            if (list != null && list.Any())
                list = list.OrderBy(t => t.DoctorName).ToList();

            return list;
        }

        public bool InsertApr(per_apr_amount request, int userId)
        {
            if (request == null)
                return false;

            //var data = perapramountRepository.GetEntity(t => t.PersonnelNumber == request.PersonnelNumber && t.AllotId == request.AllotId);
            //if (data != null)
            //    throw new PerformanceException("人员工号已存在");
            request.Status = 2;
            request.CreateDate = DateTime.Now;
            request.CreateUser = userId;
            return perapramountRepository.Add(request);
        }

        public bool UpdateApr(per_apr_amount request)
        {
            if (request == null)
                return false;

            var data = perapramountRepository.GetEntity(t => t.Id == request.Id);
            if (data == null)
                throw new PerformanceException("修改数据无效");

            data.Status = 2;
            data.PersonnelNumber = request.PersonnelNumber;
            data.DoctorName = request.DoctorName;
            data.PerforType = request.PerforType;
            data.TypeInDepartment = request.TypeInDepartment;
            data.AccountingUnit = request.AccountingUnit;
            data.Amount = request.Amount;

            return perapramountRepository.Update(data);
        }

        public bool DeleteApr(int id)
        {
            var data = perapramountRepository.GetEntity(t => t.Id == id);
            if (data != null)
                return perapramountRepository.Remove(data);

            return true;
        }

        /// <summary>
        /// 审核医院其他绩效
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool ConfirmAudit(int userid, AprAmountAuditRequest request)
        {
            if (request?.Members == null)
                throw new PerformanceException("审核信息无效，请确认");

            foreach (var item in request.Members)
            {
                if (string.IsNullOrEmpty(item.DoctorName) && string.IsNullOrEmpty(item.PersonnelNumber))
                    throw new PerformanceException("审核信息无效，请确认");
            }

            var allApramounts = perapramountRepository.GetEntities(t => t.AllotId == request.AllotId);
            foreach (var member in request.Members)
            {
                var apramounts = allApramounts?.Where(t => (t.DoctorName ?? "") == member.DoctorName && (t.PersonnelNumber ?? "") == member.PersonnelNumber);
                if (apramounts == null)
                    throw new PerformanceException("审核信息无效，请确认");

                foreach (var item in apramounts)
                {
                    item.Status = (request.IsPass == 1) ? 3 : 4;
                    item.AuditUser = userid;
                    item.AuditTime = DateTime.Now;
                    item.Remark = request.Remark;
                    perapramountRepository.UpdateRange(apramounts.ToArray());
                }
            }
            return true;
        }

        public void ImpoerAprEmployees(int allotid, string path, int userid)
        {
            var userrole = userroleRepository.GetEntity(t => t.UserID == userid);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            var data = new List<per_apr_amount>();
            if (new int[] { 1, 2, 5 }.Contains(userrole.RoleID))   //  绩效管理员、医院管理员、绩效核算办查看所有科室的数据
                data = perapramountRepository.GetEntities(t => t.AllotId == allotid && (t.Amount ?? 0) != 0);
            else
                data = perapramountRepository.GetEntities(t => t.AllotId == allotid && (t.Amount ?? 0) != 0 && t.CreateUser == userid);

            if (data != null && data.Any())
                perapramountRepository.RemoveRange(data.ToArray());

            try
            {
                IWorkbook workbook = null;

                var version = FileHelper.GetExtension(path) == ".xlsx" ? ExcelVersion.xlsx : ExcelVersion.xls;
                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
                {
                    workbook = (version == ExcelVersion.xlsx)
                        ? (IWorkbook)(new XSSFWorkbook(fs))
                        : (IWorkbook)(new HSSFWorkbook(fs));
                }
                if (workbook == null) return;
                var sheet = workbook.GetSheetAt(0);

                var firstRow = sheet.GetRow(0);
                Dictionary<int, string> excelheader = new Dictionary<int, string>();
                for (int cellindex = 0; cellindex < firstRow.LastCellNum + 1; cellindex++)
                {
                    var value = firstRow.GetCell(cellindex).GetValue();
                    if (!string.IsNullOrEmpty(value) && !excelheader.ContainsKey(cellindex))
                        excelheader.Add(cellindex, value);
                }

                if (excelheader == null || excelheader.Count == 0)
                    throw new PerformanceException("上传excel内容错误");

                Dictionary<string, int> dict = new Dictionary<string, int>
                {
                    { "录入科室", -1 },{ "核算单元", -1 },{ "人员工号", -1 }, { "姓名", -1 }, { "绩效类型", -1 }, { "金额", -1 },
                };

                foreach (var key in dict.Keys.ToList())
                {
                    if (excelheader.Any(w => w.Value == key))
                        dict[key] = excelheader.First(w => w.Value == key).Key;
                }

                var entities = new List<per_apr_amount>();
                var createtime = DateTime.Now;

                for (int rowindex = 1; rowindex < sheet.LastRowNum + 1; rowindex++)
                {
                    var row = sheet.GetRow(rowindex);
                    if (row == null) continue;

                    var entity = new per_apr_amount
                    {
                        Status = 2,
                        PersonnelNumber = dict["人员工号"] < 0 ? "" : row.GetCell(dict["人员工号"]).GetValue(),
                        DoctorName = dict["姓名"] < 0 ? "" : row.GetCell(dict["姓名"]).GetValue(),
                        PerforType = dict["绩效类型"] < 0 ? "" : row.GetCell(dict["绩效类型"]).GetValue(),
                        Amount = dict["金额"] < 0 ? 0 : ConvertHelper.To<decimal>(row.GetCell(dict["金额"]).GetValue(), 0),
                        TypeInDepartment = dict["录入科室"] < 0 ? "" : row.GetCell(dict["录入科室"]).GetValue(),
                        AccountingUnit = dict["核算单元"] < 0 ? "" : row.GetCell(dict["核算单元"]).GetValue(),
                        AllotId = allotid,
                        CreateDate = createtime,
                        CreateUser = userid,
                    };
                    entities.Add(entity);
                }

                // 补充核算单元
                if (entities.Any())
                {
                    if (entities.Any(w => string.IsNullOrEmpty(w.PersonnelNumber) && w.Amount != 0))
                        throw new PerformanceException("文件中存在“工号”为空的数据");
                    if (entities.Any(w => string.IsNullOrEmpty(w.PerforType) && w.Amount != 0))
                        throw new PerformanceException("文件中存在“绩效类型”为空的数据");
                    if (entities.Any(w => string.IsNullOrEmpty(w.TypeInDepartment) && w.Amount != 0))
                        throw new PerformanceException("文件中存在“录入科室”为空的数据");

                    var employees = peremployeeRepository.GetEntities(w => w.AllotId == allotid);
                    foreach (var item in entities.Where(w => !string.IsNullOrEmpty(w.PersonnelNumber)))
                    {
                        item.AccountingUnit = employees?.FirstOrDefault(w => w.PersonnelNumber == item.PersonnelNumber)?.AccountingUnit ?? "";
                    }
                    perapramountRepository.AddRange(entities.ToArray());
                }
            }
            catch (PerformanceException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                logger.LogError(ex.ToString());
            }
        }

        /// <summary>
        /// 根据人员工号获取人员信息
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="jobNumber"></param>
        /// <returns></returns>
        public per_apr_amount GetEmployeeMessage(int allotId, string personnelNumber, int userId)
        {
            if (string.IsNullOrEmpty(personnelNumber)) return new per_apr_amount();

            var user = userRepository.GetEntity(w => w.ID == userId && w.IsDelete == 1);
            if (user == null) throw new PerformanceException("操作用户不存在或用户信息错误!");

            var employee = peremployeeRepository.GetEntity(w => w.AllotId == allotId && w.PersonnelNumber.Trim() == personnelNumber.Trim());
            if (employee == null) return new per_apr_amount();

            return new per_apr_amount
            {
                AllotId = allotId,
                PersonnelNumber = employee.PersonnelNumber,
                DoctorName = employee.DoctorName,
                TypeInDepartment = user.Department,
                AccountingUnit = employee.AccountingUnit
            };
        }

        /// <summary>
        /// 获取绩效类型字典
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public List<TitleValue> GetPerforTypeDict(int allotId)
        {
            var defaultTypes = new List<string> { "基础绩效", "管理绩效" };

            var aprAmountList = perapramountRepository.GetEntities(w => w.AllotId == allotId);
            if (aprAmountList != null && aprAmountList.Any(w => !defaultTypes.Contains(w.PerforType)))
            {
                var savedTypes = aprAmountList.Where(w => !defaultTypes.Contains(w.PerforType)).Select(t => t.PerforType).Distinct().OrderBy(t => t).ToList();
                defaultTypes.AddRange(savedTypes);
            }
            return defaultTypes.Select(t => new TitleValue
            {
                Title = t,
                Value = t
            }).ToList();
        }
    }
}
