package com.engine.salary.service.impl;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.biz.SalarySobBiz;
import com.engine.salary.biz.SalarySobItemBiz;
import com.engine.salary.biz.SalarySobItemGroupBiz;
import com.engine.salary.biz.SalarySobItemHideBiz;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.salaryformula.ExpressFormula;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salarysob.bo.SalarySobItemAggregateBO;
import com.engine.salary.entity.salarysob.dto.SalarySobItemAggregateDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobItemFormDTO;
import com.engine.salary.entity.salarysob.param.SalarySobItemSaveParam;
import com.engine.salary.entity.salarysob.po.*;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.SalaryValueTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.salarysob.SalarySobDefaultItemMapper;
import com.engine.salary.mapper.salarysob.SalarySobEmpFieldMapper;
import com.engine.salary.mapper.salarysob.SalarySobItemMapper;
import com.engine.salary.service.*;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.valid.ValidUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import weaver.general.BaseBean;
import weaver.hrm.User;

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

/**
 * 薪资账套的薪资项目副本
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@Slf4j
public class SalarySobItemServiceImpl extends Service implements SalarySobItemService {

    private SalarySobItemBiz salarySobItemMapper = new SalarySobItemBiz();
    private SalarySobBiz salarySobBiz = new SalarySobBiz();

    private SalarySobItemGroupBiz salarySobItemGroupBiz = new SalarySobItemGroupBiz();
    private SalarySobItemHideBiz salarySobItemHideBiz = new SalarySobItemHideBiz();

    private SalarySobEmpFieldMapper getSalarySobEmpFieldMapper() {
        return MapperProxyFactory.getProxy(SalarySobEmpFieldMapper.class);
    }

    private SalarySobItemMapper getSalarySobItemMapper() {
        return MapperProxyFactory.getProxy(SalarySobItemMapper.class);
    }

    private SalarySobEmpFieldService getSalarySobEmpFieldService(User user) {
        return (SalarySobEmpFieldService) ServiceUtil.getService(SalarySobEmpFieldServiceImpl.class, user);
    }

    private TaxAgentService getTaxAgentService(User user) {
        return (TaxAgentService) ServiceUtil.getService(TaxAgentServiceImpl.class, user);
    }

    private SalarySobItemGroupService getSalarySobItemGroupService(User user) {
        return (SalarySobItemGroupService) ServiceUtil.getService(SalarySobItemGroupServiceImpl.class, user);
    }

    private SalarySobItemHideService getSalarySobItemHideService(User user) {
        return (SalarySobItemHideService) ServiceUtil.getService(SalarySobItemHideServiceImpl.class, user);
    }

    private SalaryFormulaService getSalaryFormulaService(User user) {
        return (SalaryFormulaService) ServiceUtil.getService(SalaryFormulaServiceImpl.class, user);
    }

    private SalaryItemService getSalaryItemService(User user) {
        return (SalaryItemService) ServiceUtil.getService(SalaryItemServiceImpl.class, user);
    }

    private SalarySobBackItemService getSalarySobBackItemService(User user) {
        return (SalarySobBackItemService) ServiceUtil.getService(SalarySobBackItemServiceImpl.class, user);
    }

    private SalarySobDefaultItemMapper getSalarySobDefaultItemMapper() {
        return MapperProxyFactory.getProxy(SalarySobDefaultItemMapper.class);
    }

    @Override
    public List<SalarySobItemPO> list() {
        return salarySobItemMapper.listAll();
    }

    @Override
    public List<SalarySobItemPO> listBySalarySobId(Long salarySobId) {
        return salarySobItemMapper.listSome(SalarySobItemPO.builder().salarySobId(salarySobId).build());
    }

    @Override
    public List<SalarySobItemPO> listBySalarySobIdWithHideItem(Long salarySobId) {
        return salarySobItemMapper.listBySalarySobIdWithHideItem(SalarySobItemPO.builder().salarySobId(salarySobId).build());
    }

    @Override
    public List<SalarySobItemPO> listBySalarySobIdAndGroupId(Long salarySobId, Collection<Long> salarySobItemGroupIds) {
        return salarySobItemMapper.listBySalarySobIdAndGroupId(salarySobId, salarySobItemGroupIds);
    }

    @Override
    public List<SalarySobItemPO> listBySalarySobIds(Collection<Long> salarySobIds) {
        return salarySobItemMapper.listSome(SalarySobItemPO.builder().salarySobIds(salarySobIds).build());
    }

    @Override
    public List<SalarySobItemPO> listBySalarySobIdAndSalaryItemIdNotIn(Long salarySobId, Collection<Long> salaryItemIds) {
        return salarySobItemMapper.listSome(SalarySobItemPO.builder().salarySobId(salarySobId).notInSalaryItemIds(salaryItemIds).build());
    }

    @Override
    public List<SalarySobItemPO> listBySalaryItemIds(Collection<Long> salaryItemIds) {
        if (CollectionUtils.isEmpty(salaryItemIds)) {
            return Collections.emptyList();
        }
        return salarySobItemMapper.listSome(SalarySobItemPO.builder().salaryItemIds(salaryItemIds).build());
    }

    @Override
    public List<SalaryItemPO> listBySalarySobId4SalaryItem(Long salarySobId) {
        // 查询薪资项目副本
        List<SalarySobItemPO> salarySobItemPOS = listBySalarySobId(salarySobId);
        if (CollectionUtils.isEmpty(salarySobItemPOS)) {
            return Collections.emptyList();
        }
        // 查询薪资项目
        Set<Long> salaryItemIds = SalaryEntityUtil.properties(salarySobItemPOS, SalarySobItemPO::getSalaryItemId);
        return getSalaryItemService(user).listByIds(salaryItemIds);
    }

    @Override
    public SalarySobItemAggregateDTO getAggregateBySalarySobId(Long salarySobId) {
        // 查询薪资账套
        SalarySobPO salarySobPO = salarySobBiz.getById(salarySobId);
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        // 查询薪资账套的员工信息字段
        List<SalarySobEmpFieldPO> salarySobEmpFieldPOS = getSalarySobEmpFieldService(user).listBySalarySobId(salarySobId);
        // 查询薪资账套的薪资项目分类
        List<SalarySobItemGroupPO> salarySobItemGroupPOS = getSalarySobItemGroupService(user).listBySalarySobIdWithItemHide(salarySobId);
        // 查询薪资账套的薪资项目副本
        List<SalarySobItemPO> salarySobItemPOS = listBySalarySobIdWithHideItem(salarySobId);
        // 薪资项目副本去重
        salarySobItemPOS = salarySobItemPOS.stream().filter(SalaryEntityUtil.distinctByKey(PO -> PO.getSalarySobId() + "-" + PO.getSalaryItemId())).collect(Collectors.toList());
        // 回算薪资项目
        List<SalarySobBackItemPO> salarySobBackItems = getSalarySobBackItemService(user).listBySalarySobId(salarySobId);
        // 薪资账套的薪资项目副本所用的公式id
        Set<Long> formulaIds = SalaryEntityUtil.properties(salarySobItemPOS, SalarySobItemPO::getFormulaId);
        // 添加薪资回算项目的公式id
        formulaIds.addAll(SalaryEntityUtil.properties(salarySobBackItems, SalarySobBackItemPO::getFormulaId));
        // 查询公式详情
        List<ExpressFormula> expressFormulas = getSalaryFormulaService(user).listExpressFormula(formulaIds);
        // 查询薪资账套的薪资项目副本+回算的薪资项目所关联的薪资项目
        Set<Long> salaryItemIds = SalaryEntityUtil.properties(salarySobItemPOS, SalarySobItemPO::getSalaryItemId);
        Set<Long> backCalcItemIds = SalaryEntityUtil.properties(salarySobBackItems, SalarySobBackItemPO::getSalaryItemId);
        salaryItemIds.addAll(backCalcItemIds);

        Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
        final Set<Long> ids = new HashSet<Long>();
        if (needAuth) {
            Set<Long> collect = getTaxAgentService(user).listAllTaxAgents((long) user.getUID())
                    .stream().map(TaxAgentPO::getId).collect(Collectors.toSet());
            ids.addAll(collect);
        }
        List<SalaryItemPO> salaryItemPOS = getSalaryItemService(user).listByIds(salaryItemIds).stream()
                .filter(po -> Boolean.FALSE.equals(needAuth) || getSalaryItemService(user).filterInRange(ids, po))
                .collect(Collectors.toList());

        //获取系统值
        List<SalarySobDefaultItemPO> salarySobDefaultItemPOS = getSalarySobDefaultItemMapper().listAll();

        // 转换成聚合dto
        SalarySobItemAggregateBO salarySobItemAggregateBO = new SalarySobItemAggregateBO(salarySobPO, salarySobEmpFieldPOS,
                salarySobItemGroupPOS, salarySobItemPOS, expressFormulas, salaryItemPOS, salarySobBackItems, salarySobDefaultItemPOS);
        return salarySobItemAggregateBO.convert2AggregateDTO();
    }


    @Override
    public SalarySobItemAggregateDTO getAggregateWithItemHideBySalarySobId(Long salarySobId, boolean isBackCalc) {
        // 查询薪资账套
        SalarySobPO salarySobPO = salarySobBiz.getById(salarySobId);
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        // 查询薪资账套的员工信息字段
        List<SalarySobEmpFieldPO> salarySobEmpFieldPOS = getSalarySobEmpFieldService(user).listBySalarySobId(salarySobId);
        // 查询薪资账套的薪资项目分类
        List<SalarySobItemGroupPO> salarySobItemGroupPOS = getSalarySobItemGroupService(user).listBySalarySobIdWithItemHide(salarySobId);

        // 获取关闭显示的分类
        List<Long> hideGroupIDs = getSalarySobItemHideService(user).listHideGroupBysalarySobId(SalarySobItemHidePO.builder().salarySobId(salarySobId).isGroup(1).build());
        // 过滤关闭显示的薪资项目分类
        salarySobItemGroupPOS = salarySobItemGroupPOS.stream().filter(group -> !(hideGroupIDs.contains(group.getId()))).collect(Collectors.toList());
        // 获取薪资项目分类ID
        List<Long> salarySobItemGroupIds = salarySobItemGroupPOS.stream().map(SalarySobItemGroupPO::getId).collect(Collectors.toList());
        salarySobItemGroupIds.add(0L);

        // 查询薪资账套的薪资项目副本(已经过滤关闭分类显示按钮的薪资项目)
        List<SalarySobItemPO> salarySobItemPOS = listBySalarySobIdAndGroupId(salarySobId, salarySobItemGroupIds);

        // 获取关闭显示的薪资项目
        List<Long> hideItemIDs = getSalarySobItemHideService(user).listHideGroupBysalarySobId(SalarySobItemHidePO.builder().salarySobId(salarySobId).isGroup(0).build());
        salarySobItemPOS = salarySobItemPOS.stream().filter(group -> !(hideItemIDs.contains(group.getSalaryItemId()))).collect(Collectors.toList());

        // 回算薪资项目
        List<SalarySobBackItemPO> salarySobBackItems = Collections.emptyList();
        if (isBackCalc) {
            salarySobBackItems = getSalarySobBackItemService(user).listBySalarySobId(salarySobId);
        }

        // 薪资账套的薪资项目副本所用的公式id
        Set<Long> formulaIds = SalaryEntityUtil.properties(salarySobItemPOS, SalarySobItemPO::getFormulaId);
        formulaIds.addAll(salarySobBackItems.stream().map(SalarySobBackItemPO::getFormulaId).collect(Collectors.toList()));
        // 查询公式详情
        List<ExpressFormula> expressFormulas = getSalaryFormulaService(user).listExpressFormula(formulaIds);
        // 查询薪资账套的薪资项目副本所关联的薪资项目
        Set<Long> salaryItemIds = SalaryEntityUtil.properties(salarySobItemPOS, SalarySobItemPO::getSalaryItemId);
        Set<Long> backCalcItemIds = SalaryEntityUtil.properties(salarySobBackItems, SalarySobBackItemPO::getSalaryItemId);
        salaryItemIds.addAll(backCalcItemIds);
        List<SalaryItemPO> salaryItemPOS = getSalaryItemService(user).listByIds(salaryItemIds);


        // 转换成聚合dto
        SalarySobItemAggregateBO salarySobItemAggregateBO = new SalarySobItemAggregateBO(salarySobPO, salarySobEmpFieldPOS,
                salarySobItemGroupPOS, salarySobItemPOS, expressFormulas, salaryItemPOS, salarySobBackItems, Collections.emptyList());
        return salarySobItemAggregateBO.convert2AggregateDTO();
    }

    @Override
    public void save(SalarySobItemSaveParam saveParam) {

        Long salarySobId = saveParam.getSalarySobId();

        // 校验
        validSaveParam(saveParam);

        //保存
        saveSobItem(saveParam);

        SalarySobPO salarySob = salarySobBiz.getById(salarySobId);

        // 记录日志
        LoggerContext<SalarySobPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId("" + salarySob.getId());
        loggerContext.setTargetName(salarySob.getName());
        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "编辑薪资账套薪资项目"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "编辑薪资账套薪资项目"));
        SalaryElogConfig.salarySobLoggerTemplate.write(loggerContext);
    }

    /**
     * 校验
     */
    private void validSaveParam(SalarySobItemSaveParam saveParam) {

        ValidUtil.doValidator(saveParam);

        //账套存在
        Long salarySobId = saveParam.getSalarySobId();
        SalarySobPO salarySobPO = salarySobBiz.getById(salarySobId);
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }

        //员工信息字段不可重复
        List<SalarySobItemSaveParam.SalarySobEmpFieldParam> empFields = saveParam.getEmpFields();
        if (CollectionUtils.isNotEmpty(empFields)) {
            int count = (int) SalaryEntityUtil.properties(empFields, SalarySobItemSaveParam.SalarySobEmpFieldParam::getFieldId).stream().distinct().count();
            if (count < empFields.size()) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "分类名称重复！"));
            }
        } else {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "员工信息不能为空！"));
        }

        //分类名称唯一
        List<SalarySobItemSaveParam.SalarySobItemGroupParam> itemGroups = saveParam.getItemGroups();
        if (CollectionUtils.isNotEmpty(itemGroups)) {
            int count = (int) SalaryEntityUtil.properties(itemGroups, SalarySobItemSaveParam.SalarySobItemGroupParam::getName).stream().distinct().count();
            if (count < itemGroups.size()) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "分类名称重复！"));
            }
        }
    }


    /**
     * 保存项目信息
     *
     * @param saveParam
     */
    private void saveSobItem(SalarySobItemSaveParam saveParam) {
        //分组和薪资项
        handleGroupAndItem(saveParam);

        //处理人员信息字段
        handleEmpField(saveParam);
    }

    private void handleGroupAndItem(SalarySobItemSaveParam saveParam) {
        long employeeId = (long) user.getUID();
        Date now = new Date();
        Long salarySobId = saveParam.getSalarySobId();

        List<SalarySobItemSaveParam.SalarySobItemGroupParam> itemGroups = saveParam.getItemGroups();
        List<Long> newGroupIds = SalaryEntityUtil.properties(itemGroups, SalarySobItemSaveParam.SalarySobItemGroupParam::getId, Collectors.toList());
        List<SalarySobItemGroupPO> salarySobItemGroupPOS = getSalarySobItemGroupService(user).listBySalarySobId(salarySobId);
        List<Long> oldGroupIds = SalaryEntityUtil.properties(salarySobItemGroupPOS, SalarySobItemGroupPO::getId, Collectors.toList());
        List<SalarySobItemSaveParam.SalarySobItemGroupParam> needAddGroup = itemGroups.stream().filter(f -> f.getId() == null).collect(Collectors.toList());
        List<SalarySobItemSaveParam.SalarySobItemGroupParam> needUpdateGroup = itemGroups.stream().filter(f -> f.getId() != null && oldGroupIds.contains(f.getId())).collect(Collectors.toList());
        List<Long> needDeleteGroupIds = oldGroupIds.stream().filter(f -> !newGroupIds.contains(f)).collect(Collectors.toList());

        // 获取所有薪资项目
        List<SalaryItemPO> allSalaryItemList = getSalaryItemService(user).listAll();
        Map<Long, SalaryItemPO> salaryItemsMap = SalaryEntityUtil.convert2Map(allSalaryItemList, SalaryItemPO::getId);

        // 需要保存的隐藏项目
        List<SalarySobItemHidePO> needInsertItemShow = new ArrayList<>();

        //先保存项目分类获，取分类id
        Collection<SalarySobItemPO> salarySobItems = new ArrayList<>();
        for (SalarySobItemSaveParam.SalarySobItemGroupParam itemGroupParam : needAddGroup) {
            Long salarySobItemGroupId = IdGenerator.generate();
            SalarySobItemGroupPO salarySobItemGroupPO = SalarySobItemGroupPO.builder()
                    .id(salarySobItemGroupId)
                    .salarySobId(salarySobId)
                    .name(itemGroupParam.getName())
                    .sortedIndex(itemGroupParam.getSortedIndex())
                    .description(StringUtils.EMPTY)
                    .creator(employeeId)
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(NumberUtils.INTEGER_ZERO)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
            //保存分类
            salarySobItemGroupBiz.insert(salarySobItemGroupPO);


            // 保存薪资项目分类 字段显隐
            Long salarySobGroupItemShowId = IdGenerator.generate();
            SalarySobItemHidePO salarySobGroupItemHidePO = SalarySobItemHidePO.builder()
                    .id(salarySobGroupItemShowId)
                    .salarySobId(salarySobId)
                    .salaryItemId(salarySobItemGroupId)
                    .isGroup(1)
                    .itemHide(itemGroupParam.getItemHide() == null ? 0L : itemGroupParam.getItemHide())
                    .creator(employeeId)
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(NumberUtils.INTEGER_ZERO)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
            needInsertItemShow.add(salarySobGroupItemHidePO);
//            salarySobItemMapper.InsertItemShow(salarySobGroupItemHidePO);


            for (SalarySobItemSaveParam.SalarySobItemParam itemParam : itemGroupParam.getItems()) {
                SalaryItemPO salaryItemPO = checkItemExists(itemParam.getSalaryItemId(), salaryItemsMap);
                SalarySobItemPO salarySobItemPO = SalarySobItemPO.builder()
                        .salarySobId(salarySobId)
                        .salaryItemId(itemParam.getSalaryItemId())
                        .salarySobItemGroupId(salarySobItemGroupId)
                        .formulaId(Optional.ofNullable(itemParam.getFormulaId()).orElse(NumberUtils.LONG_ZERO))
                        .sortedIndex(itemParam.getSortedIndex())
                        .description(StringUtils.EMPTY)
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .canDelete(itemParam.getCanDelete() == null ? NumberUtils.INTEGER_ONE : (itemParam.getCanDelete() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO))
                        .roundingMode(itemParam.getRoundingMode() == null ? salaryItemPO.getRoundingMode() : itemParam.getRoundingMode())
                        .pattern(itemParam.getPattern() == null ? salaryItemPO.getPattern() : itemParam.getPattern())
                        .valueType(itemParam.getValueType() == null ? salaryItemPO.getValueType() : itemParam.getValueType())
                        .build();
                salarySobItems.add(salarySobItemPO);

                // 保存薪资项目是否展示
                Long salarySobItemShowId = IdGenerator.generate();
                SalarySobItemHidePO salarySobItemHidePO = SalarySobItemHidePO.builder()
                        .id(salarySobItemShowId)
                        .salarySobId(salarySobId)
                        .salaryItemId(itemParam.getSalaryItemId())
                        .isGroup(0)
                        .itemHide(itemParam.getItemHide())
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
//                salarySobItemMapper.InsertItemShow(salarySobItemHidePO);
                needInsertItemShow.add(salarySobItemHidePO);

            }
        }


        //更新分组
        for (SalarySobItemSaveParam.SalarySobItemGroupParam itemGroupParam : needUpdateGroup) {
            Long groupId = itemGroupParam.getId();
            SalarySobItemGroupPO salarySobItemGroupPO = SalarySobItemGroupPO.builder()
                    .id(groupId)
                    .name(itemGroupParam.getName())
                    .sortedIndex(itemGroupParam.getSortedIndex())
                    .build();
            //更新分类
            salarySobItemGroupBiz.update(salarySobItemGroupPO);

            // 保存薪资项目分类 字段显隐
            Long salarySobGroupItemShowId = IdGenerator.generate();
            SalarySobItemHidePO salarySobGroupItemHidePO = SalarySobItemHidePO.builder()
                    .id(salarySobGroupItemShowId)
                    .salarySobId(salarySobId)
                    .salaryItemId(groupId)
                    .isGroup(1)
                    .itemHide(itemGroupParam.getItemHide() == null ? 0L : itemGroupParam.getItemHide())
                    .creator(employeeId)
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(NumberUtils.INTEGER_ZERO)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
            needInsertItemShow.add(salarySobGroupItemHidePO);


            List<SalarySobItemSaveParam.SalarySobItemParam> items = itemGroupParam.getItems();
            List<Long> itemIds = SalaryEntityUtil.properties(items, SalarySobItemSaveParam.SalarySobItemParam::getId, Collectors.toList());
            List<SalarySobItemPO> oldItems = salarySobItemMapper.listBySalarySobIdAndGroupId(salarySobId, Collections.singleton(groupId));
            List<Long> oldItemIds = SalaryEntityUtil.properties(oldItems, SalarySobItemPO::getId, Collectors.toList());
            List<SalarySobItemSaveParam.SalarySobItemParam> needAddItems = items.stream().filter(f -> f.getId() == null).collect(Collectors.toList());
            List<Long> needDeleteItemIds = oldItems.stream().filter(f -> !itemIds.contains(f.getId())).map(SalarySobItemPO::getId).collect(Collectors.toList());
            List<SalarySobItemSaveParam.SalarySobItemParam> needUpdateItems = items.stream().filter(f -> f.getId() != null && oldItemIds.contains(f.getId())).collect(Collectors.toList());

            //新增
            for (SalarySobItemSaveParam.SalarySobItemParam itemParam : needAddItems) {
                SalaryItemPO salaryItemPO = checkItemExists(itemParam.getSalaryItemId(), salaryItemsMap);
                SalarySobItemPO salarySobItemPO = SalarySobItemPO.builder()
                        .salarySobId(salarySobId)
                        .salaryItemId(itemParam.getSalaryItemId())
                        .salarySobItemGroupId(groupId)
                        .formulaId(Optional.ofNullable(itemParam.getFormulaId()).orElse(NumberUtils.LONG_ZERO))
                        .canDelete(itemParam.getCanDelete() == null ? NumberUtils.INTEGER_ONE : (itemParam.getCanDelete() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO))
                        .sortedIndex(itemParam.getSortedIndex())
                        .description(StringUtils.EMPTY)
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .roundingMode(itemParam.getRoundingMode() == null ? salaryItemPO.getRoundingMode() : itemParam.getRoundingMode())
                        .pattern(itemParam.getPattern() == null ? salaryItemPO.getPattern() : itemParam.getPattern())
                        .valueType(itemParam.getValueType() == null ? salaryItemPO.getValueType() : itemParam.getValueType())
                        .build();
                salarySobItems.add(salarySobItemPO);

                // 保存薪资项目是否展示
                Long salarySobItemShowId = IdGenerator.generate();
                SalarySobItemHidePO salarySobItemHidePO = SalarySobItemHidePO.builder()
                        .id(salarySobItemShowId)
                        .salarySobId(salarySobId)
                        .salaryItemId(itemParam.getSalaryItemId())
                        .isGroup(0)
                        .itemHide(itemParam.getItemHide())
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                needInsertItemShow.add(salarySobItemHidePO);
            }
            //更新
            for (SalarySobItemSaveParam.SalarySobItemParam itemParam : needUpdateItems) {
                SalaryItemPO salaryItemPO = checkItemExists(itemParam.getSalaryItemId(), salaryItemsMap);
                SalarySobItemPO salarySobItemPO = SalarySobItemPO.builder()
                        .id(itemParam.getId())
                        .salaryItemId(itemParam.getSalaryItemId())
                        .salarySobItemGroupId(groupId)
                        .formulaId(Optional.ofNullable(itemParam.getFormulaId()).orElse(NumberUtils.LONG_ZERO))
                        .sortedIndex(itemParam.getSortedIndex())
                        .canDelete(itemParam.getCanDelete() == null ? NumberUtils.INTEGER_ONE : (itemParam.getCanDelete() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO))
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .roundingMode(itemParam.getRoundingMode() == null ? salaryItemPO.getRoundingMode() : itemParam.getRoundingMode())
                        .pattern(itemParam.getPattern() == null ? salaryItemPO.getPattern() : itemParam.getPattern())
                        .valueType(itemParam.getValueType() == null ? salaryItemPO.getValueType() : itemParam.getValueType())
                        .build();
                getSalarySobItemMapper().updateIgnoreNull(salarySobItemPO);
                // 保存薪资项目是否展示
                Long salarySobItemShowId = IdGenerator.generate();
                needInsertItemShow.add(SalarySobItemHidePO.builder()
                        .id(salarySobItemShowId)
                        .salarySobId(salarySobId)
                        .salaryItemId(itemParam.getSalaryItemId())
                        .isGroup(0)
                        .itemHide(itemParam.getItemHide())
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build());
            }


            //删除
            salarySobItemMapper.deleteByIds(needDeleteItemIds);

        }

        //删除分组
        salarySobItemGroupBiz.deleteByIds(needDeleteGroupIds);
        salarySobItemMapper.deleteByGroupIds(needDeleteGroupIds);


        //未分类
        List<SalarySobItemSaveParam.SalarySobItemParam> items = saveParam.getItems();
        List<Long> itemIds = SalaryEntityUtil.properties(items, SalarySobItemSaveParam.SalarySobItemParam::getId, Collectors.toList());
        List<SalarySobItemPO> oldItems = salarySobItemMapper.listBySalarySobIdAndGroupId(salarySobId, Collections.singleton(0L));
        List<Long> oldItemIds = SalaryEntityUtil.properties(oldItems, SalarySobItemPO::getId, Collectors.toList());
        List<SalarySobItemSaveParam.SalarySobItemParam> needAddItems = items.stream().filter(f -> f.getId() == null).collect(Collectors.toList());
        List<Long> needDeleteItemIds = oldItems.stream().filter(f -> !itemIds.contains(f.getId())).map(SalarySobItemPO::getId).collect(Collectors.toList());
        List<SalarySobItemSaveParam.SalarySobItemParam> needUpdateItems = items.stream().filter(f -> f.getId() != null && oldItemIds.contains(f.getId())).collect(Collectors.toList());

        for (SalarySobItemSaveParam.SalarySobItemParam itemParam : needAddItems) {
            SalaryItemPO salaryItemPO = checkItemExists(itemParam.getSalaryItemId(), salaryItemsMap);
            SalarySobItemPO salarySobItemPO = SalarySobItemPO.builder()
                    .salarySobId(salarySobId)
                    .salaryItemId(itemParam.getSalaryItemId())
                    .salarySobItemGroupId(NumberUtils.LONG_ZERO)
                    .formulaId(Optional.ofNullable(itemParam.getFormulaId()).orElse(NumberUtils.LONG_ZERO))
                    .sortedIndex(itemParam.getSortedIndex())
                    .description(StringUtils.EMPTY)
                    .creator(employeeId)
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(NumberUtils.INTEGER_ZERO)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .canDelete(itemParam.getCanDelete() == null ? NumberUtils.INTEGER_ONE : (itemParam.getCanDelete() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO))
                    .roundingMode(itemParam.getRoundingMode() == null ? salaryItemPO.getRoundingMode() : itemParam.getRoundingMode())
                    .pattern(itemParam.getPattern() == null ? salaryItemPO.getPattern() : itemParam.getPattern())
                    .valueType(itemParam.getValueType() == null ? salaryItemPO.getValueType() : itemParam.getValueType())
                    .build();
            salarySobItems.add(salarySobItemPO);

            // 保存未分类薪资项目是否展示
            Long salarySobItemShowId = IdGenerator.generate();
            SalarySobItemHidePO salarySobItemHidePO = SalarySobItemHidePO.builder()
                    .id(salarySobItemShowId)
                    .salarySobId(salarySobId)
                    .salaryItemId(itemParam.getSalaryItemId())
                    .isGroup(0)
                    .itemHide(itemParam.getItemHide())
                    .creator(employeeId)
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(NumberUtils.INTEGER_ZERO)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
//            salarySobItemMapper.InsertItemShow(salarySobItemHidePO);
            needInsertItemShow.add(salarySobItemHidePO);
        }

        for (SalarySobItemSaveParam.SalarySobItemParam itemParam : needUpdateItems) {
            SalaryItemPO salaryItemPO = checkItemExists(itemParam.getSalaryItemId(), salaryItemsMap);
            SalarySobItemPO salarySobItemPO = SalarySobItemPO.builder()
                    .id(itemParam.getId())
                    .formulaId(Optional.ofNullable(itemParam.getFormulaId()).orElse(NumberUtils.LONG_ZERO))
                    .sortedIndex(itemParam.getSortedIndex())
                    .updateTime(now)
                    .canDelete(itemParam.getCanDelete() == null ? NumberUtils.INTEGER_ONE : (itemParam.getCanDelete() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO))
                    .roundingMode(itemParam.getRoundingMode() == null ? salaryItemPO.getRoundingMode() : itemParam.getRoundingMode())
                    .pattern(itemParam.getPattern() == null ? salaryItemPO.getPattern() : itemParam.getPattern())
                    .valueType(itemParam.getValueType() == null ? salaryItemPO.getValueType() : itemParam.getValueType())
                    .build();
            getSalarySobItemMapper().updateIgnoreNull(salarySobItemPO);

            // 保存未分类薪资项目是否展示
            Long salarySobItemShowId = IdGenerator.generate();
            SalarySobItemHidePO salarySobItemHidePO = SalarySobItemHidePO.builder()
                    .id(salarySobItemShowId)
                    .salarySobId(salarySobId)
                    .salaryItemId(itemParam.getSalaryItemId())
                    .isGroup(0)
                    .itemHide(itemParam.getItemHide())
                    .creator(employeeId)
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(NumberUtils.INTEGER_ZERO)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
//            salarySobItemMapper.InsertItemShow(salarySobItemHidePO);
            needInsertItemShow.add(salarySobItemHidePO);
        }

        if (CollectionUtils.isNotEmpty(needDeleteItemIds)) {
            getSalarySobItemMapper().deleteByIds(needDeleteItemIds);
        }

        // 保存薪资账套的薪资项目副本
        batchSave(salarySobItems);

        // 删除原薪资项目是否显示
        deleteItemShowBySalarySobIds(Collections.singleton(salarySobId));
        // 保存薪资账套的薪资项目隐藏信息
        batchSaveShow(needInsertItemShow);
    }

    private SalaryItemPO checkItemExists(Long salaryItemId, Map<Long, SalaryItemPO> salaryItemsMap) {
        SalaryItemPO salaryItemPO = salaryItemsMap.get(salaryItemId);
        if (salaryItemPO == null) {
            log.error("薪资项目:{}不存在", salaryItemId);
            throw new SalaryRunTimeException("保存失败！存在薪资项目不存在或已被删除");
        }
        return salaryItemPO;
    }


    private void handleEmpField(SalarySobItemSaveParam saveParam) {
        long employeeId = (long) user.getUID();
        Date now = new Date();
        Long salarySobId = saveParam.getSalarySobId();

        List<SalarySobItemSaveParam.SalarySobEmpFieldParam> empFields = saveParam.getEmpFields();
        List<Long> newEmpIds = SalaryEntityUtil.properties(empFields, SalarySobItemSaveParam.SalarySobEmpFieldParam::getId, Collectors.toList());
        List<SalarySobEmpFieldPO> salarySobEmpFieldPOS = getSalarySobEmpFieldService(user).listBySalarySobId(salarySobId);
        List<Long> needDeleteEmpIds = salarySobEmpFieldPOS.stream().filter(f -> !newEmpIds.contains(f.getId())).map(SalarySobEmpFieldPO::getId).collect(Collectors.toList());

        // 保存薪资账套的员工信息字段
        Collection<SalarySobEmpFieldPO> needInsertSalarySobEmpFields = new ArrayList<>();
        for (SalarySobItemSaveParam.SalarySobEmpFieldParam salarySobEmpFieldParam : empFields) {
            if (salarySobEmpFieldParam.getId() == null) {
                SalarySobEmpFieldPO salarySobEmpFieldPO = SalarySobEmpFieldPO.builder()
                        .salarySobId(saveParam.getSalarySobId())
                        .fieldCode(salarySobEmpFieldParam.getFieldId())
                        .sortedIndex(salarySobEmpFieldParam.getSortedIndex())
                        .canDelete(salarySobEmpFieldParam.getCanDelete() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO)
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                needInsertSalarySobEmpFields.add(salarySobEmpFieldPO);
            } else {
                SalarySobEmpFieldPO salarySobEmpFieldPO = SalarySobEmpFieldPO.builder()
                        .id(salarySobEmpFieldParam.getId())
                        .sortedIndex(salarySobEmpFieldParam.getSortedIndex())
                        .updateTime(now)
                        .build();
                getSalarySobEmpFieldMapper().updateIgnoreNull(salarySobEmpFieldPO);
            }

        }
        getSalarySobEmpFieldService(user).batchSave(needInsertSalarySobEmpFields);
        //删除字段
        getSalarySobEmpFieldService(user).deleteByIds(needDeleteEmpIds);
    }

    @Override
    public void batchSave(Collection<SalarySobItemPO> salarySobItemPOS) {
        if (CollectionUtils.isEmpty(salarySobItemPOS)) {
            return;
        }
        //前端可能传重复数据，去重
        List<SalarySobItemPO> list = new ArrayList<>(salarySobItemPOS.stream()
                .collect(Collectors.toMap(SalarySobItemPO::getSalaryItemId, Function.identity(), (oldValue, newValue) -> oldValue))
                .values());
        salarySobItemMapper.batchInsert(list);
    }

    private void batchSaveShow(List<SalarySobItemHidePO> needInsertItemShow) {
        if (CollectionUtils.isEmpty(needInsertItemShow)) {
            return;
        }
        //前端可能传重复数据，去重
        List<SalarySobItemHidePO> list = new ArrayList<>(needInsertItemShow.stream()
                .collect(Collectors.toMap(SalarySobItemHidePO::getSalaryItemId, Function.identity(), (oldValue, newValue) -> oldValue))
                .values());
        salarySobItemMapper.batchInsertItemShow(list);
    }

    @Override
    public void deleteBySalarySobIds(Collection<Long> salarySobIds) {
        salarySobItemMapper.deleteBySalarySobIds(salarySobIds);
    }

    @Override
    public void deleteItemShowBySalarySobIds(Collection<Long> salarySobIds) {
        salarySobItemMapper.deleteItemShowBySalarySobId(salarySobIds);
    }

    @Override
    public void update(SalarySobItemPO po) {
        salarySobItemMapper.update(po);
    }

    @Override
    public SalarySobItemFormDTO getSalaryItemForm(SalarySobItemPO param) {
        SalarySobItemFormDTO salarySobItemFormDTO = new SalarySobItemFormDTO();
        salarySobItemFormDTO.setCanEdit(1);
        // 默认可以编辑
        if (param.getSalarySobId() != null && param.getSalaryItemId() != null) {
            // 查询薪资账套
            SalarySobPO salarySobPO = salarySobBiz.getById(param.getSalarySobId());
            if (Objects.isNull(salarySobPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
            }
            // 查询薪资项目
            List<SalarySobItemPO> salarySobItemPOS = getSalarySobItemMapper().listSome(SalarySobItemPO.builder().salarySobId(param.getSalarySobId()).salaryItemId(param.getSalaryItemId()).build());
            if (CollectionUtils.isEmpty(salarySobItemPOS)) {
                throw new SalaryRunTimeException("账套中薪资项目不存在");
            }
            SalarySobItemPO salarySobItemPO = salarySobItemPOS.get(0);
            SalaryItemPO salaryItemPO = getSalaryItemService(user).getById(salarySobItemPO.getSalaryItemId());
            if (salaryItemPO == null) {
                throw new SalaryRunTimeException("薪资项目不存在或已被删除");
            }
            //获取系统值
            List<SalarySobDefaultItemPO> salarySobDefaultItemPOS = getSalarySobDefaultItemMapper().listAll();
            salarySobDefaultItemPOS = salarySobDefaultItemPOS.stream().filter(po -> po.getSysSalaryItemId() != 0).collect(Collectors.toList());
            Map<Long, Integer> longIntegerMap = SalaryEntityUtil.convert2Map(salarySobDefaultItemPOS, SalarySobDefaultItemPO::getSysSalaryItemId, SalarySobDefaultItemPO::getCanDelete);
            if (salaryItemPO.getSysSalaryItemId() != null) {
                salarySobItemPO.setCanDelete(longIntegerMap.getOrDefault(salaryItemPO.getSysSalaryItemId(), 1));
            }
            // 获取薪资项目公式
            List<ExpressFormula> expressFormulas = getSalaryFormulaService(user).listExpressFormula(Collections.singleton(salarySobItemPO.getFormulaId()));
            // 强制开启账套的公式配置
            BaseBean baseBean = new BaseBean();
            final Boolean openFormulaForcedEditing = "true".equals(baseBean.getPropValue("hrmSalary", "openFormulaForcedEditing"));
            // 获取核算时隐藏的薪资项目id
            List<Long> hideItemIds = getSalarySobItemHideService(user).listHideGroupBysalarySobId(SalarySobItemHidePO.builder()
                    .salarySobId(param.getSalarySobId())
                    .isGroup(new Integer(0))
                    .salaryItemId(param.getSalaryItemId())
                    .build());

            String formulaContent = CollectionUtils.isEmpty(expressFormulas) ? "" : expressFormulas.get(0).getFormula();
            Integer valueType = salarySobItemPO.getValueType() == null ? salaryItemPO.getValueType() : salarySobItemPO.getValueType();
            salarySobItemFormDTO
                    .setId(salarySobItemPO.getId())
                    .setName(salaryItemPO.getName())
                    .setItemHide(hideItemIds.contains(salaryItemPO.getId()) ? 1 : 0)
                    .setDataType(salaryItemPO.getDataType())
                    .setRoundingMode(salarySobItemPO.getRoundingMode() == null ? salaryItemPO.getRoundingMode() : salarySobItemPO.getRoundingMode())
                    .setPattern(salarySobItemPO.getPattern() == null ? salaryItemPO.getPattern() : salarySobItemPO.getPattern())
                    .setValueType(valueType)
                    .setFormulaId(salarySobItemPO.getFormulaId())
                    .setFormulaContent(CollectionUtils.isNotEmpty(expressFormulas) ? formulaContent : "")
                    .setOriginFormulaContent(valueType.equals(SalaryValueTypeEnum.FORMULA.getValue()) ? formulaContent : "")
                    .setOriginSqlContent(valueType.equals(SalaryValueTypeEnum.SQL.getValue()) ? formulaContent : "")
                    .setUseInEmployeeSalary(salaryItemPO.getUseInEmployeeSalary())
                    .setDescription(salarySobItemPO.getDescription())
                    .setCanEdit((openFormulaForcedEditing || salaryItemPO.getCanEdit().equals(1)) ? 1 : 0);
        }
        return salarySobItemFormDTO;
    }

}
