using NPOI.HSSF.Record.Chart;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using Remotion.Linq.Clauses.ResultOperators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Performance.Services
{
    public class OriginalService : IAutoInjection
    {
        private readonly PerforPersheetRepository persheetRepository;
        private readonly PerforPerallotRepository perallotRepository;
        private readonly PerforImheaderRepository imheaderRepository;
        private readonly PerforImemployeeRepository imemployeeRepository;
        private readonly PerforImemployeeclinicRepository imemployeeclinicRepository;
        private readonly PerforImdataRepository imdataRepository;
        private readonly PerforImspecialunitRepository imspecialunitRepository;
        private readonly PerforImaccountbasicRepository imaccountbasicRepository;

        public OriginalService(PerforPersheetRepository persheetRepository,
            PerforPerallotRepository perallotRepository,
            PerforImheaderRepository imheaderRepository,
            PerforImemployeeRepository imemployeeRepository,
            PerforImemployeeclinicRepository imemployeeclinicRepository,
            PerforImdataRepository imdataRepository,
            PerforImspecialunitRepository imspecialunitRepository,
            PerforImaccountbasicRepository imaccountbasicRepository)
        {
            this.persheetRepository = persheetRepository;
            this.perallotRepository = perallotRepository;
            this.imheaderRepository = imheaderRepository;
            this.imemployeeRepository = imemployeeRepository;
            this.imemployeeclinicRepository = imemployeeclinicRepository;
            this.imdataRepository = imdataRepository;
            this.imspecialunitRepository = imspecialunitRepository;
            this.imaccountbasicRepository = imaccountbasicRepository;
        }

        public bool EditFactorData(int userId, OriginalRequest request)
        {
            // 含有系数的数据
            var allData = imdataRepository.GetEntities(t => t.SheetID == request.SheetId);
            var basic = allData.FirstOrDefault(t => t.ID == request.Cell.Id);
            // 获取相同核算类型的数据
            var updateData = allData.Where(t => t.UnitType == basic.UnitType);
            var data = updateData.Where(t => t.TypeName == request.Cell.FieldName).ToList();
            // 修改同一类型下的系数
            var factor = ConvertHelper.To<decimal>(request.Cell.CellValue); // 系数
            if (data != null && data.Any())
            {
                data.ForEach(t =>
                {
                    t.FactorValue = factor;
                    t.UpdateDate = DateTime.Now;
                    t.UpdateUser = userId;
                });
            }
            return imdataRepository.UpdateRange(updateData.ToArray());
        }

        public bool EditHeaderData(int userId, OriginalRequest request)
        {
            var filters = new List<string> { "核算单元（医技组）", "核算单元（医生组）", "核算单元（护理组）", "科室名称", "核算单元", "核算单元类型" };
            if (filters.Contains(request.Cell.FieldName))
                throw new PerformanceException("该单元格暂不支持修改");

            var data = imheaderRepository.GetEntity(t => t.ID == request.Cell.Id);
            data.CellValue = request.Cell.CellValue.ToString();
            data.UpdateDate = DateTime.Now;
            data.UpdateUser = userId;
            return imheaderRepository.Update(data);
        }

        public bool EditSheetData(int userId, OriginalRequest request)
        {
            var sheet = persheetRepository.GetEntity(t => t.ID == request.SheetId);
            if (sheet == null)
                throw new PerformanceException("提交数据无效");

            var allot = perallotRepository.GetEntity(t => t.ID == sheet.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效信息错误");

            var result = false;
            try
            {
                switch (sheet.SheetType)
                {
                    case (int)SheetType.Employee:
                        result = EditEmployee(userId, request);
                        break;
                    case (int)SheetType.ClinicEmployee:
                        result = EditEmployeeClinic(userId, request);
                        break;
                    case (int)SheetType.SpecialUnit:
                        result = EditSpecialUnit(userId, request);
                        break;
                    case (int)SheetType.OtherIncome:
                    case (int)SheetType.Income:
                    case (int)SheetType.Expend:
                    case (int)SheetType.Workload:
                    case (int)SheetType.AccountBasic:
                        result = EditFeeData(userId, request, sheet.SheetType == (int)SheetType.AccountBasic);
                        break;
                }
            }
            catch (NotSupportedException)
            {
                throw new PerformanceException("提交参数不合规范");
            }
            catch (InvalidCastException)
            {
                throw new PerformanceException("提交参数不合规范");
            }
            catch (ArgumentException)
            {
                throw new PerformanceException("提交参数不合规范");
            }

            if (result && new int[] { (int)AllotGenerate.Init, (int)AllotGenerate.Success }.Contains(allot.Generate))
            {
                allot.Generate = (int)AllotGenerate.OriginalDataEdited;
                perallotRepository.Update(allot);
            }
            return result;
        }

        #region employee specialunit

        private bool EditEmployee(int userId, OriginalRequest request)
        {
            var employee = imemployeeRepository.GetEntity(t => request.Cell.Id == t.ID);
            if (employee == null)
                throw new PerformanceException("提交数据无效");

            SetValue(employee, request.Cell);
            employee.UpdateDate = DateTime.Now;
            employee.UpdateUser = userId;
            return imemployeeRepository.Update(employee);
        }

        private bool EditEmployeeClinic(int userId, OriginalRequest request)
        {
            var employeeClinic = imemployeeclinicRepository.GetEntity(t => request.Cell.Id == t.ID);
            if (employeeClinic == null)
                throw new PerformanceException("提交数据无效");

            SetValue(employeeClinic, request.Cell);
            employeeClinic.UpdateDate = DateTime.Now;
            employeeClinic.UpdateUser = userId;
            return imemployeeclinicRepository.Update(employeeClinic);
        }

        private bool EditSpecialUnit(int userId, OriginalRequest request)
        {
            var specialUnit = imspecialunitRepository.GetEntity(t => request.Cell.Id == t.ID);
            if (specialUnit == null)
                throw new PerformanceException("提交数据无效");

            SetValue(specialUnit, request.Cell);
            specialUnit.UpdateDate = DateTime.Now;
            specialUnit.UpdateUser = userId;
            return imspecialunitRepository.Update(specialUnit);
        }

        private bool EditAccountBasic(int userId, OriginalRequest request)
        {
            Dictionary<string, string> accdict = new Dictionary<string, string>
            {
                { "核算单元类型", nameof(im_accountbasic.UnitType) },
                { "核算单元", nameof(im_accountbasic.DoctorAccountingUnit) },
                //{ "科室名称", nameof(im_accountbasic.Department) },
                { "效率绩效人数", nameof(im_accountbasic.PermanentStaff) },
                //{ "科主任/护士长人数", nameof(im_accountbasic.DoctorDirectorNumber) },
                { "核算单元人员数量", nameof(im_accountbasic.DoctorNumber) },
                { "预算比例", nameof(im_accountbasic.DoctorBasicFactor) },
                //{ "倾斜系数", nameof(im_accountbasic.DoctorSlopeFactor) },
                //{ "工作量倾斜系数", nameof(im_accountbasic.WorkSlopeFactor) },
                { "保底绩效参考标准", nameof(im_accountbasic.MinimumReference) },
                { "保底绩效系数", nameof(im_accountbasic.MinimumFactor) },
                { "其他绩效1", nameof(im_accountbasic.DoctorOtherPerfor1) },
                { "其他绩效2", nameof(im_accountbasic.DoctorOtherPerfor2) },
                { "药占比奖罚", nameof(im_accountbasic.MedicineExtra) },
                { "材料占比奖罚", nameof(im_accountbasic.MaterialsExtra) },
                { "考核得分率", nameof(im_accountbasic.DoctorScoringAverage) },
                { "调节系数", nameof(im_accountbasic.DoctorAdjustFactor) },
            };

            var imdata = imdataRepository.GetEntity(t => t.SheetID == request.SheetId && t.RowNumber == request.RowNumber);
            if (imdata == null || request.Cell == null || !accdict.ContainsKey(request.Cell.FieldName))
                return false;

            var basic = imaccountbasicRepository.GetEntity(t => t.SheetID == request.SheetId && t.DoctorAccountingUnit == imdata.AccountingUnit && t.UnitType == imdata.UnitType);
            if (basic == null) return false;

            if (request.Cell.FieldName == "核算单元类型")
            {
                var cellvalue = EnumHelper.GetItems<UnitType>().FirstOrDefault(t => t.Name == request.Cell.CellValue.ToString());
                if (cellvalue == null) return false;
                if (cellvalue.Value == basic.UnitType) return true;
                request.Cell.CellValue = cellvalue.Value;
            }

            string fieldname = request.Cell.FieldName;
            request.Cell.FieldName = accdict[request.Cell.FieldName];
            SetValue(basic, request.Cell);
            basic.UpdateDate = DateTime.Now;
            basic.UpdateUser = userId;

            request.Cell.FieldName = fieldname;
            return imaccountbasicRepository.Update(basic);
        }

        private void SetValue<TEntity>(TEntity entity, CellRequest cell)
        {
            var value = cell.CellValue;
            var property = typeof(TEntity).GetProperty(cell.FieldName);
            if (value.ToString().IndexOf("%") > -1)
                value = ConvertHelper.To<decimal>(value.ToString().Replace("%", "")) / 100;
            //else if (cell.FieldName == "FitPeople")
            //{
            //    var fit = EnumHelper.GetItems<PerforType>();
            //    if (!fit.Select(t => t.Description).Contains(cell.CellValue.ToString()))
            //        throw new PerformanceException("'绩效基数核算参考对象'提交值无效");
            //}
            //else if (cell.FieldName == "UnitType")
            //{
            //    var fit = EnumHelper.GetItems<UnitType>();
            //    if (!fit.Select(t => t.Description).Contains(cell.CellValue.ToString()))
            //        throw new PerformanceException("'核算单元分类'提交值无效");
            //}
            else
            {
                if (property == null)
                    throw new PerformanceException("提交参数信息无效");

                if (value != null && value.ToString() != "")
                {
                    try
                    {
                        string type = property.PropertyType.FullName.ToLower();
                        if (type.IndexOf("int") > -1)
                            value = Convert.ToInt32(value);
                        else if (type.IndexOf("decimal") > -1)
                            value = Convert.ToDecimal(value);
                        else if (type.IndexOf("datetime") > -1)
                            value = Convert.ToDateTime(value);
                        else if (type.IndexOf("string") > -1)
                            value = cell.CellValue.ToString();
                    }
                    catch
                    {
                        throw new PerformanceException("提交参数不合规范");
                    }
                }
                else
                    value = null;
            }
            property.SetValue(entity, value);
        }

        #endregion

        #region imdata

        private bool EditFeeData(int userId, OriginalRequest request, bool basic)
        {
            var result = false;
            var header = imheaderRepository.GetEntity(t => t.SheetID == request.SheetId && t.PointCell == request.Cell.PointCell);
            if (string.IsNullOrEmpty(request.Cell.FieldName))
            {
                if (header == null)
                    throw new PerformanceException("提交数据无效");
                else
                    request.Cell.FieldName = header.CellValue;
            }

            if (basic)
                result = EditAccountBasic(userId, request); //用于计算不显示

            // 用于显示不计算
            var publicTypes = new string[] { "核算单元（医技组）", "核算单元（医生组）", "核算单元（护理组）", "科室名称", "核算单元类型", "核算单元" };
            if (publicTypes.Contains(request.Cell.FieldName))
                result = ImDataPublic(request);
            else
            {
                if (request.Cell.Id > 0)
                {
                    try
                    {
                        var value = request.Cell.CellValue;
                        if (value.ToString().IndexOf("%") > -1)
                            value = ConvertHelper.To<decimal>(value.ToString().Replace("%", "")) / 100;
                        var entity = imdataRepository.GetEntity(w => w.ID == request.Cell.Id);
                        entity.CellValue = Convert.ToDecimal(value);
                        entity.UpdateDate = DateTime.Now;
                        entity.UpdateUser = userId;
                        result = imdataRepository.Update(entity);
                    }
                    catch
                    {
                        throw new PerformanceException("提交参数不合规范");
                    }
                }
                else
                    result = ImDataInsert(userId, request, header);
            }

            return result;
        }

        private bool ImDataPublic(OriginalRequest request)
        {
            var allData = imdataRepository.GetEntities(t => t.SheetID == request.SheetId && t.RowNumber == request.RowNumber);
            if (request.Cell == null || allData == null || !allData.Any())
                throw new PerformanceException("提交数据无效");

            if (request.Cell.FieldName == "核算单元类型")
            {
                var unittype = allData.FirstOrDefault().UnitType;
                if (unittype != (int)request.Cell.CellValue)
                {
                    allData.ForEach(t =>
                    {
                        t.UnitType = (int)request.Cell.CellValue;
                    });
                }
            }
            else if (request.Cell.FieldName == "科室名称")
            {
                var department = allData.FirstOrDefault().Department;
                if (request.Cell.CellValue.ToString() != department)
                {
                    allData.ForEach(t =>
                    {
                        t.Department = request.Cell.CellValue.ToString();
                    });
                }
            }
            else if (request.Cell.FieldName == "核算单元")
            {
                var accounting = allData.FirstOrDefault().AccountingUnit;
                if (request.Cell.CellValue.ToString() != accounting)
                {
                    allData.ForEach(t =>
                    {
                        t.AccountingUnit = request.Cell.CellValue.ToString();
                    });
                }
            }
            else
            {
                Dictionary<string, int> publicTypes = new Dictionary<string, int>
                {
                    { "核算单元（医技组）", (int)UnitType.医技组 },
                    { "核算单元（医生组）", (int)UnitType.医生组 },
                    { "核算单元（护理组）", (int)UnitType.护理组 },
                };

                var cellvalue = request.Cell.CellValue.ToString();
                var accountingUnit = allData.FirstOrDefault(t => t.UnitType == publicTypes[request.Cell.FieldName]).AccountingUnit;
                if (cellvalue != accountingUnit)
                {
                    allData.Where(t => t.UnitType == publicTypes[request.Cell.FieldName]).ToList().ForEach(t =>
                    {
                        t.AccountingUnit = cellvalue;
                    });
                }
            }
            return imdataRepository.UpdateRange(allData.ToArray());
        }

        private bool ImDataInsert(int userId, OriginalRequest request, im_header header)
        {
            var allData = imdataRepository.GetEntities(t => t.SheetID == request.SheetId);
            if (request.Cell == null || allData == null || !allData.Any())
                throw new PerformanceException("提交数据无效");
            // 核算单元、科室
            var publicData = allData.Where(t => t.RowNumber == request.RowNumber).GroupBy(t => t.UnitType).Select(t => new
            {
                UnitType = t.Key,
                AccountingUnit = t.Max(group => group.AccountingUnit),
                Department = t.Max(group => group.Department),
            });
            // rownumber含有的核算类型
            var unittype = allData.Where(t => t.RowNumber == request.RowNumber).Select(t => t.UnitType).Distinct();
            var factor = allData.Where(t => unittype.Contains(t.UnitType) && t.TypeName == request.Cell.FieldName)
                .GroupBy(t => new { t.UnitType, t.TypeName }).Select(t => new
                {
                    t.Key.UnitType,
                    t.Key.TypeName,
                    FactorValue = t.Max(group => group.FactorValue) ?? 0
                });
            if (factor == null || !factor.Any())
                factor = unittype.Select(t => new { UnitType = t, TypeName = request.Cell.FieldName, FactorValue = 0m });
            var allotid = allData.First().AllotID;
            var newData = factor.Select(t => new im_data
            {
                RowNumber = request.RowNumber,
                AccountingUnit = publicData.FirstOrDefault(w => w.UnitType == t.UnitType)?.AccountingUnit,
                Department = publicData.FirstOrDefault(w => w.UnitType == t.UnitType)?.Department,
                UnitType = t.UnitType,
                TypeName = request.Cell.FieldName,
                CellValue = ConvertHelper.To<decimal>(request.Cell.CellValue),
                IsFactor = 1,
                FactorValue = t.FactorValue,
                SignID = header.SignID,
                SheetID = request.SheetId,
                AllotID = allotid,
                UpdateDate = DateTime.Now,
                UpdateUser = userId,
            });

            return imdataRepository.AddRange(newData.ToArray());
        }

        #endregion
    }

    public enum AllotGenerate
    {
        Init = 0,
        PersonnelOffice = 1,
        Success = 2,
        OriginalDataEdited = 3,
    }
}
