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.SpecialAddDeductionListDTO;
import com.engine.salary.entity.datacollection.dto.SpecialAddDeductionRecordDTO;
import com.engine.salary.entity.datacollection.param.SpecialAddDeductionQueryParam;
import com.engine.salary.entity.datacollection.po.SpecialAddDeductionPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.mapper.datacollection.SpecialAddDeductionMapper;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.MapperProxyFactory;
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 SpecialAddDeductionBiz extends BaseBean {
    private EncryptUtil encryptUtil = new EncryptUtil();

    private SpecialAddDeductionMapper mapper() {
        return MapperProxyFactory.getProxy(SpecialAddDeductionMapper.class);
    }

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

    public List<SpecialAddDeductionRecordDTO> listDTOByParam(SpecialAddDeductionQueryParam param) {
        List<SpecialAddDeductionRecordDTO> specialAddDeductionRecordDTOS = mapper().listDtoByParam(param);
        return encryptUtil.decryptList(specialAddDeductionRecordDTOS, SpecialAddDeductionRecordDTO.class);
    }


    public List<SpecialAddDeductionListDTO> listByParam(SpecialAddDeductionQueryParam param) {
        List<SpecialAddDeductionListDTO> specialAddDeductionListDTOS = mapper().listByParam(param);
        encryptUtil.decryptList(specialAddDeductionListDTOS, SpecialAddDeductionListDTO.class);
        return SalaryI18nUtil.i18nList(specialAddDeductionListDTOS);
    }

    public List<SpecialAddDeductionPO> listByTaxAgentIds(List<Long> taxAgentIds) {
        try (SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession()) {
            SpecialAddDeductionMapper mapper = sqlSession.getMapper(SpecialAddDeductionMapper.class);
            List<SpecialAddDeductionPO> pos = mapper.listByTaxAgentIds(taxAgentIds);
            return encryptUtil.decryptList(pos, SpecialAddDeductionPO.class);
        }
    }


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

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

    /**
     * 条件查询
     *
     * @param param
     * @return
     */
    public List<SpecialAddDeductionPO> listSome(SpecialAddDeductionPO param) {
        SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession();
        try {
            SpecialAddDeductionMapper mapper = sqlSession.getMapper(SpecialAddDeductionMapper.class);
            List<SpecialAddDeductionPO> specialAddDeductionPOS = mapper.listSome(param);
            return encryptUtil.decryptList(specialAddDeductionPOS, SpecialAddDeductionPO.class);
        } finally {
            sqlSession.close();
        }
    }


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

        if (CollectionUtils.isNotEmpty(updateList)) {
            LoggerContext loggerContext = new LoggerContext();
            loggerContext.setUser(user);
            if(updateList.size() == 1) {
                loggerContext.setTargetId(updateList.get(0).getId().toString());
            }
            loggerContext.setTargetName(SalaryI18nUtil.getI18nLabel( 0, "专项附加扣除 "));
            loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "导入"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "导入专项附加扣除 "));
            loggerContext.setNewValueList(updateList);
            SalaryElogConfig.specialAddDeductionLoggerTemplate.write(loggerContext);
        }
    }


    /**
     * @return void
     * @description 批量删除
     */
    public void batchDeleteByIds(List<Long> deleteIds) {
        if (CollectionUtils.isEmpty(deleteIds)) {
            return;
        }
        try (SqlSession sqlSession = MyBatisFactory.sqlSessionFactory.openSession()) {
            SpecialAddDeductionMapper mapper = sqlSession.getMapper(SpecialAddDeductionMapper.class);
            List<List<Long>> partition = Lists.partition(deleteIds, 100);
            partition.forEach(mapper::deleteByIds);
            sqlSession.commit();
        }
    }

    public List<SpecialAddDeductionPO> getByEmployeeId(List<Long> employeeIds, Long taxAgentId) {
        if (CollectionUtils.isEmpty(employeeIds)) {
            employeeIds = Collections.emptyList();
        }
        return mapper().getByEmployeeIds(employeeIds, taxAgentId)
                .stream()
                .filter(Objects::nonNull)
                .filter(s -> s.getEmployeeId() != null)
                .map(item -> encryptUtil.decrypt(item, SpecialAddDeductionPO.class))
                .collect(Collectors.toList());
    }
}
