package com.engine.salary.biz;

import com.engine.salary.config.SalaryElogConfig;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.encrypt.EncryptUtil;
import com.engine.salary.entity.datacollection.dto.OtherDeductionRecordDTO;
import com.engine.salary.entity.datacollection.param.OtherDeductionQueryParam;
import com.engine.salary.entity.datacollection.po.OtherDeductionPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.mapper.datacollection.OtherDeductionMapper;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.session.SqlSession;
import weaver.conn.mybatis.MyBatisFactory;
import weaver.general.BaseBean;
import weaver.hrm.User;

import java.util.*;
import java.util.stream.Collectors;

public class OtherDeductionBiz extends BaseBean {

    private EncryptUtil encryptUtil = new EncryptUtil();

    /**
     * 条件查询
     *
     * @param param
     * @return
     */
    public List<OtherDeductionPO> listSome(OtherDeductionPO param) {
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            OtherDeductionMapper mapper = sqlSession.getMapper(OtherDeductionMapper.class);
            if (CollectionUtils.isNotEmpty(param.getEmployeeIds())) {
                List<List<Long>> partition = Lists.partition(param.getEmployeeIds(), 500);
                List<OtherDeductionPO> otherDeductionPOS = new ArrayList<>();
                partition.forEach(l -> {
                    param.setEmployeeIds(l);
                    otherDeductionPOS.addAll(mapper.listSome(param));
                });
                return encryptUtil.decryptList(otherDeductionPOS, OtherDeductionPO.class);
            }else {
                List<OtherDeductionPO> otherDeductionPOS = mapper.listSome(param);
                return encryptUtil.decryptList(otherDeductionPOS, OtherDeductionPO.class);
            }
        } finally {
            sqlSession.close();
        }
    }


    /**
     * 根据id获取
     *
     * @param id
     * @return
     */
    public OtherDeductionPO getById(Long id) {
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            OtherDeductionMapper mapper = sqlSession.getMapper(OtherDeductionMapper.class);
            OtherDeductionPO byId = mapper.getById(id);
            return encryptUtil.decrypt(byId, OtherDeductionPO.class);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 详情列表
     *
     * @param param
     * @return
     */
    public List<OtherDeductionRecordDTO> recordList(OtherDeductionQueryParam param) {
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            OtherDeductionMapper mapper = sqlSession.getMapper(OtherDeductionMapper.class);
            List<OtherDeductionRecordDTO> otherDeductionRecordDTOS = mapper.recordList(param);
            return encryptUtil.decryptList(otherDeductionRecordDTOS, OtherDeductionRecordDTO.class);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 批量插入
     *
     * @param param
     * @return
     */
    public void batchSave(List<OtherDeductionPO> param) {
        if (CollectionUtils.isEmpty(param)) {
            return;
        }
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            OtherDeductionMapper mapper = sqlSession.getMapper(OtherDeductionMapper.class);
            encryptUtil.encryptList(param, OtherDeductionPO.class);
            List<List<OtherDeductionPO>> partition = Lists.partition(param, 100);
            partition.forEach(mapper::insertData);
            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 批量插入
     *
     * @param param
     * @return
     */
    public void batchUpdate(List<OtherDeductionPO> param) {
        if (CollectionUtils.isEmpty(param)) {
            return;
        }
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            OtherDeductionMapper mapper = sqlSession.getMapper(OtherDeductionMapper.class);
            encryptUtil.encryptList(param, OtherDeductionPO.class);
            List<List<OtherDeductionPO>> partition = Lists.partition(param, 100);
            partition.forEach(mapper::updateData);
            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }


    /**
     * 处理导入数据
     *
     * @param pos
     */
    public void handleImportData(List<OtherDeductionPO> pos, User user) {
        if (CollectionUtils.isEmpty(pos)) {
            return;
        }
        OtherDeductionPO po = pos.get(0);
        // 多条相同人的则以第一条为准，如果逆序排列（用于重复的则以最后一条为准）Collections.reverse(pos);
        // 去重（通过记录的唯一条件(申报月份，人员id，个税扣缴义务人id)拼接）
        List<OtherDeductionPO> finalPos = pos.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getEmployeeId() + "-" + f.getTaxAgentId()))), ArrayList::new));
        // 查询已有数据
        List<OtherDeductionPO> list = listSome(OtherDeductionPO.builder().declareMonth(po.getDeclareMonth()).build());
        // 待修改的 本地已存在则更新【交集】
        List<OtherDeductionPO> updateList = list.stream().map(m -> {
            Optional<OtherDeductionPO> optional = finalPos.stream().filter(p -> (p.getEmployeeId() + "-" + p.getTaxAgentId()).equals(m.getEmployeeId() + "-" + m.getTaxAgentId())).findFirst();
            OtherDeductionPO temp = null;
            if (optional.isPresent()) {
                temp = optional.get();
                // 换成本地库的id
                temp.setId(m.getId());
            }
            return temp;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        // 待新增的 导入比本地多，则新增【差集(导入 - local)】
        List<OtherDeductionPO> saveList = finalPos.stream().map(m -> {
            Optional<OtherDeductionPO> optional = list.stream().filter(p -> (p.getEmployeeId() + "-" + p.getTaxAgentId()).equals(m.getEmployeeId() + "-" + m.getTaxAgentId())).findFirst();
            OtherDeductionPO temp = null;
            if (!optional.isPresent()) {
                temp = m;
            }
            return temp;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        // 修改
        if (CollectionUtils.isNotEmpty(updateList)) {
            batchUpdate(updateList);
        }
        // 保存
        if (CollectionUtils.isNotEmpty(saveList)) {
            batchSave(saveList);
        }

        // 记录日志
        // 根据月份、人员id查出保存的数据
        List<Long> empIds = saveList.stream().map(OtherDeductionPO::getEmployeeId).collect(Collectors.toList());
        List<OtherDeductionPO> insertList = listSome(OtherDeductionPO.builder().declareMonth(po.getDeclareMonth()).employeeIds(empIds).build());
        Map<String, OtherDeductionPO> insertMap = SalaryEntityUtil.convert2Map(insertList, p -> p.getTaxAgentId() + "-" + SalaryDateUtil.getFormatYearMonth(p.getDeclareMonth()) + "-" + p.getEmployeeId());
        saveList.forEach(save -> {
            OtherDeductionPO otherDeductionPO = insertMap.get(save.getTaxAgentId() + "-" + SalaryDateUtil.getFormatYearMonth(save.getDeclareMonth()) + "-" + save.getEmployeeId());
            if (otherDeductionPO != null) {
                updateList.add(otherDeductionPO);
            }
        });

        if (CollectionUtils.isNotEmpty(updateList)) {
            String name = SalaryDateUtil.getFormatYearMonth(po.getDeclareMonth());
            LoggerContext loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetName(SalaryI18nUtil.getI18nLabel( 0, "其他免税扣除 ") + name);
            loggerContext.setOperateType(OperateTypeEnum.EXCEL_IMPORT.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel( 0, "导入"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel( 0, "其他免税扣除") + name);
            loggerContext.setNewValueList(updateList);
            SalaryElogConfig.otherDeductionLoggerTemplate.write(loggerContext);
        }
    }


    /**
     * @return void
     * @description 批量删除
     * @author Harryxzy
     * @date 2022/10/27 16:07
     */
    public void batchDeleteByIDS(List<Long> deleteIds) {
        if (CollectionUtils.isEmpty(deleteIds)) {
            return;
        }
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            OtherDeductionMapper mapper = sqlSession.getMapper(OtherDeductionMapper.class);
            List<List<Long>> partition = Lists.partition(deleteIds, 100);
            partition.forEach(mapper::deleteData);
            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }
}
