package com.yifu.cloud.plus.v1.business.service.salary.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.business.entity.salary.TBusSalary;
import com.yifu.cloud.plus.v1.business.entity.salary.TBusSalaryConfig;
import com.yifu.cloud.plus.v1.business.entity.salary.TBusSalaryConfigTitleRes;
import com.yifu.cloud.plus.v1.business.entity.salary.TBusSalaryItem;
import com.yifu.cloud.plus.v1.business.entity.system.TBusDept;
import com.yifu.cloud.plus.v1.business.mapper.salary.TBusSalaryMapper;
import com.yifu.cloud.plus.v1.business.service.salary.TBusSalaryConfigService;
import com.yifu.cloud.plus.v1.business.service.salary.TBusSalaryConfigTitleResService;
import com.yifu.cloud.plus.v1.business.service.salary.TBusSalaryItemService;
import com.yifu.cloud.plus.v1.business.service.salary.TBusSalaryService;
import com.yifu.cloud.plus.v1.business.service.system.TBusDeptService;
import com.yifu.cloud.plus.v1.business.util.SalaryUtil;
import com.yifu.cloud.plus.v1.business.vo.salary.BusSalaryExportVo;
import com.yifu.cloud.plus.v1.business.vo.salary.InitVo;
import com.yifu.cloud.plus.v1.business.vo.salary.KeyValueVo;
import com.yifu.cloud.plus.v1.business.vo.salary.SalaryImportVo;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ExcelAttribute;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.ErrorMessage;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * B端-薪酬主表
 *
 * @author hgw
 * @date 2021-09-06 11:10:32
 */
@Service
public class TBusSalaryServiceImpl extends ServiceImpl<TBusSalaryMapper, TBusSalary> implements TBusSalaryService {

     @Autowired
     private TBusDeptService busDeptService;
     @Autowired
     private TBusSalaryConfigService busSalaryConfigService;
     @Autowired
     private TBusSalaryItemService busSalaryItemService;
     @Autowired
     private TBusSalaryConfigTitleResService busSalaryConfigTitleResService;

     /**
      * @param tBusSalary
      * @Description: 导出
      * @Author: hgw
      * @Date: 2021/9/13 17:01
      * @return: java.util.List<com.yifu.cloud.v1.hrobusiness.api.entity.salary.TBusSalary>
      **/
     @Override
     public BusSalaryExportVo doExport(TBusSalary tBusSalary) {
          BusSalaryExportVo vo = new BusSalaryExportVo();
          List<String> idList = null;
          if (Common.isNotNull(tBusSalary.getIdStr())) {
               idList = Common.initStrToList(tBusSalary.getIdStr(), CommonConstants.COMMA_STRING);
          }
          List<TBusSalary> salaryList = baseMapper.doExport(idList, tBusSalary);
          vo.setSalaryList(salaryList);
          if (salaryList != null && !salaryList.isEmpty()) {
               Set<String> title = new HashSet<>();
               List<String> salaryIdList = new ArrayList<>();
               for (TBusSalary salary : salaryList) {
				   salaryIdList.add(salary.getId());
			   }
			   List<TBusSalaryItem> allItemList = busSalaryItemService.getListBySalaryId(salaryIdList);
			   Map<String, List<TBusSalaryItem>> itemMap = new HashMap<>();
			   List<TBusSalaryItem> itemList;
			   for (TBusSalaryItem item : allItemList) {
				   itemList = itemMap.get(item.getSalaryId());
				   if (itemList == null) {
					   itemList = new ArrayList<>();
				   }
				   itemList.add(item);
				   itemMap.put(item.getSalaryId(), itemList);
			   }
			   for (TBusSalary salary : salaryList) {
				  itemList = itemMap.get(salary.getId());
                    if (itemList != null && !itemList.isEmpty()) {
                         salary.setBisList(itemList);
                         for (TBusSalaryItem items : itemList) {
                              title.add(items.getCnName());
                         }
                    }
               }
               vo.setTitleSet(title);
          }
          return vo;
     }

     /**
      * B端-薪酬主表简单分页查询
      *
      * @param tBusSalary B端-薪酬主表
      * @return
      */
     @Override
     public IPage<TBusSalary> getTBusSalaryPage(Page<TBusSalary> page, TBusSalary tBusSalary) {
          return baseMapper.getTBusSalaryPage(page, tBusSalary);
     }

     /**
      * @param salaryVo
      * @Description: 导入
      * @Author: hgw
      * @Date: 2021/9/6 16:33
      * @return: com.yifu.cloud.v1.common.core.util.R<java.util.List < com.yifu.cloud.v1.common.core.util.bean.ErrorMessage>>
      **/
     @Override
     public R<List<ErrorMessage>> importBusSalary(SalaryImportVo salaryVo) {
          YifuUser user = SecurityUtils.getUser();
          if (user == null || user.getId() == null) {
               return R.failed("未获取到登录人信息！");
          }
          List<ErrorMessage> errorList = new ArrayList<>();
          StringBuilder error = new StringBuilder();
          // 初步判断全局属性有没有空的
          Map<String, TBusDept> deptMap = busDeptService.getAllDeptMap();
          TBusDept dept = this.judgeFirst(error, salaryVo);
          if (error.length() > 0 && !"".equals(error.toString()) && !"null".equals(error.toString())) {
               return R.failed(error.toString());
          }
          // 再次判断每个人的详情
          this.judgeSecond(user, deptMap, dept, errorList, salaryVo);
          if (!errorList.isEmpty()) {
               return R.failed(errorList, "导入失败");
          } else {
               return R.ok();
          }
     }

     /**
      * @Description: 初步判断全局属性有没有空的
      * @Author: hgw
      * @Date: 2021/9/6 16:41
      **/
     private TBusDept judgeFirst(StringBuilder error, SalaryImportVo salaryVo) {
          if (salaryVo.getContentList() == null || salaryVo.getContentList().isEmpty()) {
               error.append("表格数据不可为空！");
          }
          if (salaryVo.getResList() == null || salaryVo.getResList().isEmpty()) {
               error.append("配置关系不可为空！");
          }
          if (Common.isEmpty(salaryVo.getDeptId())) {
               error.append("部门名称不可为空！");
          }
          if (Common.isEmpty(salaryVo.getSaveType())) {
               error.append("是否保存不可为空！");
          }
          TBusDept dept = busDeptService.getById(salaryVo.getDeptId());
          if (dept == null) {
               error.append("根据部门id未找到部门！id=").append(salaryVo.getDeptId());
          }
          return dept;
     }

     /**
      * @Description: 第二步判断与准备数据
      * @Author: hgw
      * @Date: 2021/9/9 14:21
      * @return: void
      **/
     private void judgeSecond(YifuUser user, Map<String, TBusDept> deptMap, TBusDept dept, List<ErrorMessage> errorList
             , SalaryImportVo salaryVo) {

          List<TBusSalaryConfigTitleRes> resList = salaryVo.getResList();

          List<TBusSalaryConfig> configList = busSalaryConfigService.list();

          // 保存或更新-配置
          busSalaryConfigTitleResService.saveOrUpdateRes(resList, salaryVo.getSaveType(), user, dept);

          Map<String, TBusSalaryConfig> salaryConfigMap = new HashMap<>();  //存放所有字段
          for (TBusSalaryConfig cl : configList) {
               salaryConfigMap.put(cl.getId(), cl);
          }
          // 表头配置Map
          Map<String, TBusSalaryConfig> configMap = new HashMap<>();
          for (TBusSalaryConfigTitleRes tc : resList) {
               configMap.put(tc.getExcelTitle(), salaryConfigMap.get(tc.getConfigId()));
          }
          // 得到类的所有field
          Field[] allFields = TBusSalary.class.getDeclaredFields();
          // 将有注解的field存放到fieldsMap中
          Map<String, Field> fieldsMap = new HashMap<>();
          for (Field field : allFields) {
               if (field.isAnnotationPresent(ExcelAttribute.class)) {
                    // 设置类的私有字段属性可访问
                    field.setAccessible(true);
                    fieldsMap.put(field.getName(), field);
               }
          }
          List<TBusSalary> salaryList = doCore(deptMap, dept, errorList, salaryVo, user, configMap, fieldsMap);
          // 保存工资与详情
          this.saveSalaryAndItem(errorList, salaryList);
     }

     /**
      * @param errorList
      * @param salaryList
      * @Description: 保存工资与详情
      * @Author: hgw
      * @Date: 2021/9/14 17:49
      * @return: void
      **/
     private void saveSalaryAndItem(List<ErrorMessage> errorList, List<TBusSalary> salaryList) {
          if (errorList.isEmpty()) {
               this.saveBatch(salaryList);
               for (TBusSalary bus : salaryList) {
                    if (bus.getBisList() != null && !bus.getBisList().isEmpty()) {
                         for (TBusSalaryItem item : bus.getBisList()) {
                              item.setSalaryId(bus.getId());
                         }
                         busSalaryItemService.saveBatch(bus.getBisList());
                    }
               }
          }
     }

     private List<TBusSalary> doCore(Map<String, TBusDept> deptMap, TBusDept dept, List<ErrorMessage> errorList
             , SalaryImportVo salaryVo, YifuUser user, Map<String, TBusSalaryConfig> configMap, Map<String, Field> fieldsMap) {
          List<List<KeyValueVo>> contentList = salaryVo.getContentList();
          String salaryMonth = salaryVo.getSalaryMonth();

          // 其他附加项：
          TBusSalaryConfig otherText = busSalaryConfigService.getById("100");
          Map<String, Integer> mustMap = busSalaryConfigService.getMustMap();
          InitVo initData = new InitVo();
          initData.setOtherText(otherText);
          initData.setMustMap(mustMap);
          // 存放报账list
          List<TBusSalary> salaryList = new ArrayList<>();
          // 存放金额
          // 循环的行标
          int i = 0;
          // 工资详情
          TBusSalary bs;
          // 导入的表里的部门信息
          TBusDept depts;
          // 核心循环：
          for (List<KeyValueVo> kvList : contentList) {
               bs = new TBusSalary();
               // 判断列
               this.judgeColum(errorList, configMap, fieldsMap, initData, i, bs, kvList);
               // 录入了部门、工资月份，覆盖选择的公共的数据
               if (Common.isEmpty(bs.getDeptName())) {
                    bs.setDeptId(dept.getId());
                    bs.setDeptName(dept.getName());
                    bs.setDeptTreeLogo(dept.getTreeLogo());
                    bs.setDeptLevel(dept.getLevel());
               } else {
                    depts = deptMap.get(bs.getDeptName());
                    if (depts == null) {
                         errorList.add(new ErrorMessage(i, "部门不存在，请修改或清除：" + bs.getDeptName()));
                    } else {
                         bs.setDeptId(depts.getId());
                         bs.setDeptName(depts.getName());
                         bs.setDeptTreeLogo(depts.getTreeLogo());
                         bs.setDeptLevel(depts.getLevel());
                    }
               }
               if (Common.isEmpty(bs.getSalaryMonth())) {
                    bs.setSalaryMonth(salaryMonth);
               }
               bs.setCreateTime(LocalDateTime.now());
               bs.setCreateUserId(user.getId());
               bs.setCreateUserName(user.getNickname());
               salaryList.add(bs);
               i++;
          }
          return salaryList;
     }

     /**
      * @Description: 判断列
      * @Author: hgw
      * @Date: 2021/9/9 15:41
      * @return: void
      **/
     private void judgeColum(List<ErrorMessage> errorList, Map<String, TBusSalaryConfig> configMap
             , Map<String, Field> fieldsMap, InitVo initData, int i, TBusSalary bs, List<KeyValueVo> kvList) {
          // 属性
          Field field;
          // 取得类型,并根据对象类型设置值.
          Class<?> fieldType;
          // 单元格文本
          String valueStr;
          // 表头文本
          String titleStr;
          TBusSalaryConfig scs;
          // 工资详情-附加明细
          TBusSalaryItem bsi;
          // 循环的列标排序号
          int j = 0;
          // 附加明细List，追加在工资详情里
          List<TBusSalaryItem> bsiList = new ArrayList<>();
          Map<String, Integer> mustMap = new HashMap<>(initData.getMustMap());
          TBusSalaryConfig otherText = initData.getOtherText();
          // 获取属性对应的注解属性
          ExcelAttribute attr;  //获取属性对应的注解属性
          for (KeyValueVo kv : kvList) {
               valueStr = kv.getContent();
               titleStr = kv.getTitle();
               scs = configMap.get(titleStr);
               if (scs == null) {
                    scs = otherText;
               } else if (mustMap.get(scs.getDbFiedName()) != null) {
                    mustMap.remove(scs.getDbFiedName());
               }
               // 必填项不可为空
               this.judgeMustAndMoney(errorList, i, valueStr, titleStr, scs);
               field = fieldsMap.get(scs.getJavaFiedName());
               // field != null：报账里的属性，否则属于附加表
               if (field == null) {
                    bsi = new TBusSalaryItem();
                    bsi.setCnName(kv.getTitle());
                    bsi.setJavaFiedName(scs.getJavaFiedName());
                    bsi.setTextValue(valueStr);
                    bsi.setOrderLine(j);
                    bsiList.add(bsi);
                    j++;
               } else {
                    attr = field.getAnnotation(ExcelAttribute.class);
                    SalaryUtil.validateData(valueStr, attr, errorList, i);
                    fieldType = field.getType();
                    if (fieldType != null) {
                         try {
                              // 塞属性
                              SalaryUtil.setFields(field, valueStr, fieldType, bs);
                         } catch (IllegalAccessException ex) {
                              log.error("B端薪资原表导入解析失败!");
                              errorList.add(new ErrorMessage(i, titleStr + "列：导入解析失败：" + valueStr));
                         }
                    }
               }
          }
          this.checkMustInfo(errorList, i, mustMap);
          bs.setBisList(bsiList);
     }

     /**
      * @Description: 必填项校验
      * @Author: hgw
      * @Date: 2021/9/10 15:29
      * @return: void
      **/
     private void checkMustInfo(List<ErrorMessage> errorList, int i, Map<String, Integer> mustMap) {
          if (!mustMap.isEmpty()) {
               StringBuilder sb = new StringBuilder("必填项不可缺少：");
               for (String s : mustMap.keySet()) {
                    sb.append(s).append(" ");
               }
               errorList.add(new ErrorMessage(i, sb.toString()));
          }
     }

     /**
      * @Description: 判断必填和金额
      * @Author: hgw
      * @Date: 2021/9/9 15:44
      * @return: void
      **/
     private void judgeMustAndMoney(List<ErrorMessage> errorList, int i, String valueStr, String titleStr, TBusSalaryConfig scs) {
          if ((CommonConstants.ONE_INT == scs.getIsMustNeed() || CommonConstants.THREE_INT == scs.getIsMustNeed())
                  && Common.isEmpty(valueStr)) {
               errorList.add(new ErrorMessage(i, titleStr + "：不可为空！"));
          }
          // 金额不可瞎写
          if ((CommonConstants.TWO_INT == scs.getIsMustNeed() || CommonConstants.THREE_INT == scs.getIsMustNeed())
                  && Common.isNotNull(valueStr)) {
               try {
                    new BigDecimal(valueStr);
               } catch (Exception ex) {
                    errorList.add(new ErrorMessage(i, titleStr + "列：金额错误：" + valueStr));
               }
          }
     }

}
