package com.engine.salary.service.impl;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.biz.*;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.salaryBill.po.SalaryTemplatePO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctRecordPO;
import com.engine.salary.entity.salaryitem.bo.SysSalaryItemBO;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salaryitem.po.SysSalaryItemPO;
import com.engine.salary.entity.salarysob.bo.*;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.param.*;
import com.engine.salary.entity.salarysob.po.*;
import com.engine.salary.entity.taxagent.dto.TaxAgentManageRangeListDTO;
import com.engine.salary.entity.taxagent.param.TaxAgentRangeQueryParam;
import com.engine.salary.entity.taxagent.po.TaxAgentAdminPO;
import com.engine.salary.entity.taxagent.po.TaxAgentExtRangePO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.SalarySystemTypeEnum;
import com.engine.salary.enums.salarysob.IncomeCategoryEnum;
import com.engine.salary.enums.salarysob.SalaryEmployeeStatusEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.salarysob.SalarySobMapper;
import com.engine.salary.mapper.taxagent.TaxAgentExtRangeMapper;
import com.engine.salary.service.*;
import com.engine.salary.sys.enums.TaxDeclarationFunctionEnum;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
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.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.RuntimeTypeEnum;
import com.engine.salary.util.valid.ValidUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import weaver.hrm.User;

import java.time.YearMonth;
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
 **/
public class SalarySobServiceImpl extends Service implements SalarySobService {


    private SalarySobBiz salarySobMapper = new SalarySobBiz();
    private SalarySobRangeBiz salarySobRangeService = new SalarySobRangeBiz();
    private SalarySobEmpFieldBiz empFieldBiz = new SalarySobEmpFieldBiz();
    private SalarySobDefaultItemGroupBiz defaultItemGroupBiz = new SalarySobDefaultItemGroupBiz();
    private SalarySobEmpFieldBiz salarySobEmpFieldService = new SalarySobEmpFieldBiz();
    private SalarySobDefaultItemBiz salarySobDefaultItemService = new SalarySobDefaultItemBiz();
    private SalarySobItemBiz salarySobItemService = new SalarySobItemBiz();
    private SalarySobItemGroupBiz salarySobItemGroupService = new SalarySobItemGroupBiz();

    private SalarySobItemHideBiz salarySobItemHideService = new SalarySobItemHideBiz();

    private SalarySobRangeBiz salarySobRangeBiz = new SalarySobRangeBiz();

//    private SalarySobBackItemMapper getSalarySobBackItemMapper() {
//        return MapperProxyFactory.getProxy(SalarySobBackItemMapper.class);
//    }

    private SalarySobMapper getSalarySobMapper() {
        return MapperProxyFactory.getProxy(SalarySobMapper.class);
    }

    private TaxAgentExtRangeMapper getTaxAgentExtRangeMapper() {
        return MapperProxyFactory.getProxy(TaxAgentExtRangeMapper.class);
    }

    private SalarySobExtRangeService getSalarySobExtRangeService(User user) {
        return ServiceUtil.getService(SalarySobExtRangeServiceImpl.class, user);
    }

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

    private SysSalaryItemService getSysSalaryItemService(User user) {
        return ServiceUtil.getService(SysSalaryItemServiceImpl.class, user);
    }

    private SalarySobAdjustRuleBiz salarySobAdjustRuleService = new SalarySobAdjustRuleBiz();

    private SalarySobCheckRuleService getSalarySobCheckRuleService(User user) {
        return ServiceUtil.getService(SalarySobCheckRuleServiceImpl.class, user);
    }

    private SalaryAcctRecordService getSalaryAcctRecordService(User user) {
        return ServiceUtil.getService(SalaryAcctRecordServiceImpl.class, user);
    }

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

    private TaxAgentAdminService getTaxAgentAdminService(User user) {
        return ServiceUtil.getService(TaxAgentAdminServiceImpl.class, user);
    }

    private TaxAgentManageRangeService getTaxAgentManageRangeService(User user) {
        return ServiceUtil.getService(TaxAgentManageRangeServiceImpl.class, user);
    }

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

    private SalaryTemplateService getSalaryTemplateService(User user) {
        return ServiceUtil.getService(SalaryTemplateServiceImpl.class, user);
    }

    private SalarySysConfService getSalarySysConfService(User user) {
        return ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
    }

    @Override
    public SalarySobPO getById(Long id) {
        return salarySobMapper.getById(id);
    }

    @Override
    public List<SalarySobPO> listByIds(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return salarySobMapper.listSome(SalarySobPO.builder().ids(ids).build());
    }

    @Override
    public List<SalarySobPO> listByName(String name) {
        if (StringUtils.isEmpty(name)) {
            return Collections.emptyList();
        }
        List<SalarySobPO> salarySobPOS = salarySobMapper.listByName(SalarySobPO.builder().name(name).build());
        return salarySobPOS;
    }

    @Override
    public List<SalarySobPO> listByNameLike(String nameLike) {
        if (StringUtils.isEmpty(nameLike)) {
            return Collections.emptyList();
        }
        List<SalarySobPO> salarySobPOS = salarySobMapper.listByParam(SalarySobPO.builder().name(nameLike).build());
        return filterByAuthority(salarySobPOS);
    }

    @Override
    public List<SalarySobPO> listByDisable(Integer disable) {
        List<SalarySobPO> salarySobPOS = salarySobMapper.listSome(SalarySobPO.builder().disable(disable).build());
        return filterByAuthority(salarySobPOS);
    }

    @Override
    public List<SalarySobPO> listAll() {
        return salarySobMapper.listSome(SalarySobPO.builder().build());
    }

    @Override
    public List<SalarySobPO> listByAdmin() {
        List<SalarySobPO> salarySobPOS = salarySobMapper.listSome(SalarySobPO.builder().build());
        return filterByAdmin(salarySobPOS);
    }

    @Override
    public List<SalarySobPO> listByTaxAgentId(Long taxAgentId) {
        return salarySobMapper.listSome(SalarySobPO.builder().disable(NumberUtils.INTEGER_ZERO).taxAgentId(taxAgentId).build());
    }

    @Override
    public List<SalarySobPO> listByIncomeCategory(IncomeCategoryEnum incomeCategory) {
        return salarySobMapper.listSome(SalarySobPO.builder().incomeCategory(incomeCategory.getValue()).build());
    }

    @Override
    public PageInfo<SalarySobPO> listPageByParam(SalarySobListQueryParam queryParam) {
        long employeeId = user.getUID();
        // 分页参数
        PageInfo<SalarySobPO> page = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize());
        // 判断是否是“总管理员”
        Boolean isChief = getTaxAgentService(user).isChief(employeeId);
        // 是否开启分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        // 总管理员拥有全部权限
        // 开启分权后需要过滤薪资账套
        String name = queryParam.getName();
        // 查询所有的薪资账套
        SalarySobPO build = SalarySobPO.builder().build();
        if (StringUtils.isNotBlank(name)) {
            build.setName(name);
        }
        if (queryParam.getTaxAgentId() != null) {
            build.setTaxAgentId(queryParam.getTaxAgentId());
        }

        if (BooleanUtils.isTrue(openDevolution) && !isChief) {
            List<SalarySobPO> salarySobPOS = salarySobMapper.listSome(build);
            // 根据权限过滤
            List<SalarySobPO> salarySobsFilterByAuthority = filterByAuthority(salarySobPOS);
            if (CollectionUtils.isEmpty(salarySobsFilterByAuthority)) {
                return page;
            }
            List<SalarySobPO> subSalarySobs = SalaryPageUtil.subList((int) page.getPageNum(), (int) page.getPageSize(), salarySobsFilterByAuthority);
            page.setTotal(salarySobsFilterByAuthority.size());
            page.setList(subSalarySobs);
            return page;
        } else {
            List<SalarySobPO> salarySobPOS = salarySobMapper.listSome(build);
            return SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(),
                    salarySobPOS, SalarySobPO.class);
        }
    }

    @Override
    public List<SalarySobPO> listByParam(SalarySobListQueryParam queryParam) {
        long employeeId = user.getUID();
        // 判断是否是“总管理员”
        Boolean isChief = getTaxAgentService(user).isChief(employeeId);
        // 是否开启分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        // 总管理员拥有全部权限
        // 开启分权后需要过滤薪资账套
        String name = queryParam.getName();
        // 查询所有的薪资账套
        SalarySobPO build = SalarySobPO.builder().build();
        if (StringUtils.isNotBlank(name)) {
            build.setName(name);
        }
        if (BooleanUtils.isTrue(openDevolution) && !isChief) {

            Boolean adminEnable = getTaxAgentService(user).isAdminEnable(employeeId);
            //非管理员
            if (!adminEnable) {
                return new ArrayList<>();
            }

            List<SalarySobPO> salarySobPOS = salarySobMapper.listSome(build);

            // 根据权限过滤
            List<SalarySobPO> salarySobsFilterByAuthority = filterByAuthority(salarySobPOS);
            if (CollectionUtils.isEmpty(salarySobsFilterByAuthority)) {
                return new ArrayList<>();
            }
            return salarySobsFilterByAuthority;

        } else {
            return salarySobMapper.listSome(build);
        }
    }

    @Override
    public Long save(SalarySobBasicSaveParam saveParam) {

        ValidUtil.doValidator(saveParam);

        // 薪资账套的名称不能重复
        List<SalarySobPO> salarySobPOS = listByName(saveParam.getName());
        if (CollectionUtils.isNotEmpty(salarySobPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98403, "薪资账套名称已存在"));
        }

        // 保存参数转换成薪资账套po
        SalarySobPO salarySobPO = SalarySobBO.convert2PO(saveParam, (long) user.getUID());
        // 保存薪资账套
        salarySobMapper.insert(salarySobPO);
        // 记录日志
       LoggerContext<SalarySobPO> loggerContext = new LoggerContext<>();
       loggerContext.setUser(user);
       loggerContext.setTargetId(String.valueOf(salarySobPO.getId()));
       loggerContext.setTargetName(salarySobPO.getName());
       loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
       loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新建薪资账套"));
       loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新建薪资账套") + ": " + salarySobPO.getName());
       loggerContext.setNewValues(salarySobPO);
       SalaryElogConfig.salarySobLoggerTemplate.write(loggerContext);
        // 新建薪资账套时，保存默认的员工信息字段
        saveDefaultEmpField(salarySobPO);
        // 新建薪资账套时，保存默认的薪资项目
        saveDefaultItem(salarySobPO);
        // 新建薪资账套时，保存默认的关联人员范围及从范围中排除
        saveDefaultEmployeeRange(salarySobPO);
        // 返回薪资账套的主键id
        return salarySobPO.getId();
    }


    /**
     * 新建薪资账套时，保存默认的员工信息字段
     *
     * @param salarySobPO 薪资账套
     */
    private void saveDefaultEmpField(SalarySobPO salarySobPO) {
        // 查询薪资账套默认的员工信息字段
        List<SalarySobDefaultEmpFieldPO> salarySobDefaultEmpFieldPOS = empFieldBiz.listDefaultEmpField();
        // 转换成薪资账套员工信息字段po
        List<SalarySobEmpFieldPO> salarySobEmpFieldPOS = SalarySobItemBO.convert2EmpFieldPO(salarySobPO.getId(), salarySobDefaultEmpFieldPOS, (long) user.getUID());
        // 保存
        empFieldBiz.batchInsert(salarySobEmpFieldPOS);
    }

    /**
     * 新建薪资账套时，保存默认的薪资项目
     * 1、薪资账套默认引用的系统薪资项目
     * 2、自定义薪资项目中开启了"默认使用"的薪资项目
     *
     * @param salarySobPO 薪资账套
     */
    private void saveDefaultItem(SalarySobPO salarySobPO) {
        // 1、根据薪资类型查询薪资账套默认使用的薪资项目分类以及薪资项目
        IncomeCategoryEnum incomeCategoryEnum = IncomeCategoryEnum.parseByValue(salarySobPO.getIncomeCategory());
        List<SalarySobDefaultItemGroupPO> salarySobDefaultItemGroupPOS = defaultItemGroupBiz.listByIncomeCategory(incomeCategoryEnum);
        List<SalarySobDefaultItemPO> salarySobDefaultItemPOS = salarySobDefaultItemService.listByIncomeCategory(SalarySobDefaultItemPO.builder().incomeCategory(incomeCategoryEnum.getValue()).build());

        //是否需要系统算税，不需要则去除系统项目
        TaxDeclarationFunctionEnum taxDeclarationFunctionEnum = getSalarySysConfService(user).getTaxDeclaration();
        if (taxDeclarationFunctionEnum == TaxDeclarationFunctionEnum.CLOSURE) {
            salarySobDefaultItemGroupPOS = new ArrayList<>();
            salarySobDefaultItemPOS = new ArrayList<>();
        }

        // 2、薪资账套默认引用的系统薪资项目如果没有添加到薪资项目中，这里要给添加保存
        // 2.1、查询已经添加到薪资项目中的系统薪资项目
        Set<Long> defaultSysSalaryItemIds = SalaryEntityUtil.properties(salarySobDefaultItemPOS, SalarySobDefaultItemPO::getSysSalaryItemId);
        // 薪资账套的默认的回算薪资项目
        Set<Long> SalarySobBackItemIds = SalaryEntityUtil.properties(SalarySobBackItemBO.getDefault(), SalarySobDefaultBackItemPO::getSysSalaryItemId);
        defaultSysSalaryItemIds.addAll(SalarySobBackItemIds);

        List<SalaryItemPO> salaryItemPOS = getSalaryItemService(user).listBySysSalaryItemIds(defaultSysSalaryItemIds);
        Set<Long> sysSalaryItemIds = SalaryEntityUtil.properties(salaryItemPOS, SalaryItemPO::getSysSalaryItemId);
        // 2.2、需要添加进薪资项目中的系统薪资项目id
        Set<Long> needAddSysSalaryItemIds = salarySobDefaultItemPOS.stream()
                .map(SalarySobDefaultItemPO::getSysSalaryItemId)
                .filter(sysSalaryItemId -> !sysSalaryItemIds.contains(sysSalaryItemId))
                .collect(Collectors.toSet());
        // 需要添加进薪资项目中的回算薪资项目
        needAddSysSalaryItemIds.addAll(SalarySobBackItemIds.stream().filter(salarySobBackItemId -> !sysSalaryItemIds.contains(salarySobBackItemId)).collect(Collectors.toList()));
        List<SysSalaryItemPO> needAddSysSalaryItemPOS = getSysSalaryItemService(user).listByIds(needAddSysSalaryItemIds);
        // 2.3、需要保存的薪资项目
        List<SalaryItemPO> needInsertSalaryItemPOS = SysSalaryItemBO.convert2SalaryItemPO(needAddSysSalaryItemPOS, (long) user.getUID());
        if (CollectionUtils.isNotEmpty(needInsertSalaryItemPOS)) {
            getSalaryItemService(user).batchSave(needInsertSalaryItemPOS);
        }

        // 3、查询开启了"默认使用"的自定义薪资项目
        List<SalaryItemPO> useDefaultSalaryItemPOS = getSalaryItemService(user).listBySystemTypeAndUseDefault(SalarySystemTypeEnum.CUSTOM, NumberUtils.INTEGER_ONE);

        // 4、默认引用的薪资项目（=薪资账套默认引用的系统薪资项目(已添加进薪资项目中的) + 薪资账套默认引用的系统薪资项目(待添加进薪资项目中的) + 自定义薪资项目中开启了"默认使用"的薪资项目）
        List<SalaryItemPO> defaultSalaryItemPOS = Lists.newArrayListWithExpectedSize(salaryItemPOS.size() + needInsertSalaryItemPOS.size() + useDefaultSalaryItemPOS.size());
        defaultSalaryItemPOS.addAll(salaryItemPOS);
        defaultSalaryItemPOS.addAll(needInsertSalaryItemPOS);
        defaultSalaryItemPOS.addAll(useDefaultSalaryItemPOS);

        // 5、保存
        SalarySobItemBO.Result result = SalarySobItemBO.initSalarySobItem(salarySobPO.getId(), salarySobDefaultItemGroupPOS, salarySobDefaultItemPOS, defaultSalaryItemPOS, (long) user.getUID(), SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        if (CollectionUtils.isNotEmpty(result.getNeedInsertSalarySobItems())) {

            List<SalarySobItemPO> list = new ArrayList<>(result.getNeedInsertSalarySobItems().stream()
                    .collect(Collectors.toMap(SalarySobItemPO::getSalaryItemId, Function.identity(), (oldValue, newValue) -> oldValue))
                    .values());

            salarySobItemService.batchInsert(list);
        }
        if (CollectionUtils.isNotEmpty(result.getNeedInsertSalarySobItemGroups())) {
            salarySobItemGroupService.batchInsert(result.getNeedInsertSalarySobItemGroups());
        }
        if (CollectionUtils.isNotEmpty(result.getNeedInsertSalarySobBackItems())) {
            getSalarySobBackItemService(user).batchInsert(result.getNeedInsertSalarySobBackItems());
        }
        if (CollectionUtils.isNotEmpty(result.getNeedInsertItemHides())) {
            //去重
            List<SalarySobItemHidePO> list = new ArrayList<>(result.getNeedInsertItemHides().stream()
                    .collect(Collectors.toMap(SalarySobItemHidePO::getSalaryItemId, Function.identity(), (oldValue, newValue) -> oldValue))
                    .values());
            salarySobItemService.batchInsertItemShow(list);
        }
    }

    /**
     * @return void
     * @description 新建薪资账套时，保存默认的关联人员范围及从范围中排除
     * @author Harryxzy
     * @date 2022/10/9 15:30
     */
    public void saveDefaultEmployeeRange(SalarySobPO salarySobPO) {
        // 获取人员范围列表
        TaxAgentRangeQueryParam queryParam = TaxAgentRangeQueryParam.builder().taxAgentId(salarySobPO.getTaxAgentId()).build();
        queryParam.setCurrent(1);
        queryParam.setPageSize(100000);
        List<TaxAgentManageRangeListDTO> includeList = (List<TaxAgentManageRangeListDTO>) getTaxAgentManageRangeService(user).listPageByParamAndIncludeType(queryParam, NumberUtils.INTEGER_ONE).getList();
        includeList.stream().forEach(item -> {
            item.setEmployeeStatus(parseEnum2ValueStr(item.getEmployeeStatus()));
        });
        // 获取从范围中排除
        List<TaxAgentManageRangeListDTO> excludeList = (List<TaxAgentManageRangeListDTO>) getTaxAgentManageRangeService(user).listPageByParamAndIncludeType(queryParam, NumberUtils.INTEGER_ZERO).getList();
        excludeList.stream().forEach(item -> {
            item.setEmployeeStatus(parseEnum2ValueStr(item.getEmployeeStatus()));
        });
        // 将TaxAgentManageRangeListDTO转换为SalarySobRangePO
        List<SalarySobRangePO> rangeList = convert2SalarySobRangePO(salarySobPO.getId(), includeList, excludeList);
        // 保存SalarySobRangePO
        if (CollectionUtils.isNotEmpty(rangeList)) {
            salarySobRangeBiz.batchInsert(rangeList);
        }

        //非系统人员
        List<TaxAgentExtRangePO> taxAgentExtRangePOS = getTaxAgentExtRangeMapper().listSome(TaxAgentExtRangePO.builder().taxAgentId(salarySobPO.getTaxAgentId()).build());
        taxAgentExtRangePOS.forEach(po -> {
            SalarySobRangeExtSaveParam build = SalarySobRangeExtSaveParam.builder().salarySobId(salarySobPO.getId()).targetIds(Collections.singletonList(po.getTargetId())).targetType(1L).build();
            getSalarySobExtRangeService(user).saveExtRange(build);
        });


    }


    /**
     * @return List<SalarySobRangePO>
     * @description 将TaxAgentManageRangeListDTO转换为SalarySobRangePO
     * @author Harryxzy
     * @date 2022/10/9 16:06
     */
    private List<SalarySobRangePO> convert2SalarySobRangePO(Long salarySobID, List<TaxAgentManageRangeListDTO> includeList, List<TaxAgentManageRangeListDTO> excludeList) {
        Date now = new Date();
        ArrayList<SalarySobRangePO> result = new ArrayList<SalarySobRangePO>();
        // 关联人员范围
        includeList.stream().forEach(item -> {
            SalarySobRangePO salarySobRangePO = SalarySobRangePO.builder()
                    .salarySobId(salarySobID)
                    .targetType(item.getTargetType().getValue())
                    .targetId(item.getTargetId())
                    .employeeStatuses(item.getEmployeeStatus())
                    .includeType(1)
                    .creator(Long.valueOf(user.getUID()))
                    .createTime(now)
                    .updateTime(now)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .deleteType(0)
                    .build();
            result.add(salarySobRangePO);
        });
        // 从范围中排除
        excludeList.stream().forEach(item -> {
            SalarySobRangePO salarySobRangePO = SalarySobRangePO.builder()
                    .salarySobId(salarySobID)
                    .targetType(item.getTargetType().getValue())
                    .targetId(item.getTargetId())
                    .employeeStatuses(item.getEmployeeStatus())
                    .includeType(0)
                    .creator(Long.valueOf(user.getUID()))
                    .createTime(now)
                    .updateTime(now)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .deleteType(0)
                    .build();
            result.add(salarySobRangePO);
        });
        return result;
    }


    /**
     * @return String
     * @description 将枚举的defaultLabel转换为value
     * @author Harryxzy
     * @date 2022/10/9 16:56
     */
    private String parseEnum2ValueStr(String employeeStatus) {
        String[] split = employeeStatus.split(",");
        StringBuilder sb = new StringBuilder();
        for (SalaryEmployeeStatusEnum statusEnum : SalaryEmployeeStatusEnum.values()) {
            for (int i = 0; i < split.length; i++) {
                if (statusEnum.getDefaultLabel().equals(split[i])) {
                    sb.append(statusEnum.getValue());
                    if (i + 1 != split.length) {
                        sb.append(",");
                    }
                }
            }
        }
        return sb.toString();
    }


    @Override
    public Long update(SalarySobBasicSaveParam saveParam) {

        ValidUtil.doValidator(saveParam, RuntimeTypeEnum.UPDATE);

        // 查询薪资账套
        SalarySobPO salarySobPO = getById(saveParam.getId());
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        // 薪资账套的名称不能重复
        List<SalarySobPO> salarySobPOS = listByName(saveParam.getName());
        boolean duplicateName = salarySobPOS.stream().anyMatch(e -> !Objects.equals(e.getId(), saveParam.getId()));
        if (duplicateName) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98403, "薪资账套名称已存在"));
        }
        // 更新薪资账套
        SalarySobPO newSalarySobPO = new SalarySobPO();
        BeanUtils.copyProperties(salarySobPO, newSalarySobPO);
        newSalarySobPO.setId(saveParam.getId())
                .setName(saveParam.getName())
                .setTaxAgentId(saveParam.getTaxAgentId())
                .setIncomeCategory(saveParam.getTaxableItems())
                .setSalaryCycleType(saveParam.getSalaryCycleType())
                .setSalaryCycleFromDay(saveParam.getSalaryCycleFromDay())
                .setTaxCycleType(saveParam.getTaxCycleType())
                .setAttendCycleType(saveParam.getAttendCycleType())
                .setAttendCycleFromDay(saveParam.getAttendCycleFromDay())
                .setSocialSecurityCycleType(saveParam.getSocialSecurityCycleType())
                .setDescription(saveParam.getDescription())
                .setUpdateTime(new Date());
        salarySobMapper.updateById(newSalarySobPO);
        // 记录日志
        SalarySobPO salarySobPO4log = getSalarySobMapper().getById(newSalarySobPO.getId());
        LoggerContext<SalarySobPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(newSalarySobPO.getId()));
        loggerContext.setTargetName(newSalarySobPO.getName());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "编辑薪资账套基础设置"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "编辑薪资账套基础设置"));
        loggerContext.setOldValues(salarySobPO);
        loggerContext.setNewValues(salarySobPO4log);
        SalaryElogConfig.salarySobLoggerTemplate.write(loggerContext);
        // 返回薪资账套的主键id
        return salarySobPO.getId();
    }

    @Override
    public void updateDisable(SalarySobDisableParam disableParam) {
        // 查询薪资账套
        SalarySobPO salarySobPO = getById(disableParam.getId());
        SalarySobPO oldSalarySobPO = new SalarySobPO();
        BeanUtils.copyProperties(salarySobPO, oldSalarySobPO);
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        // 启用/禁用 薪资账套
        salarySobPO.setDisable(disableParam.getDisable());
        salarySobPO.setUpdateTime(new Date());
        salarySobMapper.updateById(salarySobPO);
        // 记录日志
       String operateTypeName = Objects.equals(disableParam.getDisable(), NumberUtils.INTEGER_ONE) ?
               SalaryI18nUtil.getI18nLabel(0, "禁用薪资账套") : SalaryI18nUtil.getI18nLabel(0, "启用薪资账套");
       LoggerContext<SalarySobPO> loggerContext = new LoggerContext<>();
       loggerContext.setUser(user);
       loggerContext.setTargetId("" + salarySobPO.getId());
       loggerContext.setTargetName(salarySobPO.getName());
       loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
       loggerContext.setOperateTypeName(operateTypeName);
       loggerContext.setOperatedesc(operateTypeName + ": " + salarySobPO.getName());
       loggerContext.setOldValues(oldSalarySobPO);
       loggerContext.setNewValues(salarySobPO);
       SalaryElogConfig.salarySobLoggerTemplate.write(loggerContext);
    }

    @Override
    public void deleteByIds(Collection<Long> ids) {

        //分权
        Boolean isOpenDevolution = getTaxAgentService(user).isOpenDevolution();
        if (isOpenDevolution) {
            List<SalarySobPO> salarySobPOS = listByAdmin();
            Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
            Optional<Long> first = ids.stream().filter(f -> !salarySobIds.contains(f)).findFirst();
            if (first.isPresent()) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "无权限删除"));
            }
        }


        // 查询薪资账套
        List<SalarySobPO> salarySobPOS = listByIds(ids);
        if (CollectionUtils.isEmpty(salarySobPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        ids = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
        // 根据薪资账套id查询薪资核算记录，存在薪资核算记录就不能删除账套了
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = getSalaryAcctRecordService(user).listBySalarySobIds(ids);
        if (CollectionUtils.isNotEmpty(salaryAcctRecordPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99713, "账套已用于薪资核算，不能删除"));
        }

        // 根据薪资账套id查询工资单模板，存在该账套下的工资单模板就不能删除账套了
        List<SalaryTemplatePO> salaryTemplatePOS = getSalaryTemplateService(user).getBySalarySobIds(ids);
        if (CollectionUtils.isNotEmpty(salaryTemplatePOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99713, "账套存在工资单模板，不能删除，请先删除该账套所对应的工资单模板"));
        }

        //关联其他的删除
        // 删除薪资账套
        salarySobMapper.deleteByIds(ids);
        // 删除薪资账套的人员范围
        salarySobRangeService.deleteBySalarySobIds(ids);
        // 删除薪资账套的人员信息字段
        salarySobEmpFieldService.deleteBySalarySobIds(ids);
        // 删除薪资账套的薪资项目
        salarySobItemService.deleteBySalarySobIds(ids);
        // 删除薪资账套的薪资项目分类
        salarySobItemGroupService.deleteBySalarySobIds(ids);
        // 删除薪资账套的薪资项目隐藏信息
        salarySobItemHideService.deleteBySalarySobIds(ids);
        // 删除薪资账套的调薪计薪规则
        salarySobAdjustRuleService.deleteBySalarySobIds(ids);
        // 删除薪资账套的回算薪资项目
        getSalarySobBackItemService(user).deleteBySalarySobIds(ids);
        // 删除薪资账套的校验规则
        getSalarySobCheckRuleService(user).deleteBySalarySobIds(ids);
       // 记录日志
       salarySobPOS.forEach(salarySobPO -> {
           LoggerContext<SalarySobPO> loggerContext = new LoggerContext<>();
           loggerContext.setUser(user);
           loggerContext.setTargetId("" + salarySobPO.getId());
           loggerContext.setTargetName(salarySobPO.getName());
           loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
           loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "删除薪资账套"));
           loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "删除薪资账套"));
           loggerContext.setOldValues(salarySobPO);
           SalaryElogConfig.salarySobLoggerTemplate.write(loggerContext);
       });
    }

    @Override
    public void duplicate(SalarySobDuplicateParam duplicateParam) {
        ValidUtil.doValidator(duplicateParam);

        // 查询薪资账套
        SalarySobPO salarySobPO = getById(duplicateParam.getId());
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        // 薪资账套名称不能重复
        List<SalarySobPO> salarySobPOS = listByName(duplicateParam.getName());
        if (CollectionUtils.isNotEmpty(salarySobPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98403, "薪资账套名称已存在"));
        }

        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        if (openDevolution) {
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin((long) user.getUID());
            Set<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);
            if (!taxAgentIds.contains(duplicateParam.getTaxAgentId())) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98403, "该扣缴义务人不在权限范围内！"));
            }
        }

        // 查询薪资账套的员工信息字段
        List<SalarySobEmpFieldPO> salarySobEmpFieldPOS = salarySobEmpFieldService.listSome(SalarySobEmpFieldPO.builder().salarySobId(duplicateParam.getId()).build());
        // 查询薪资账套的薪资项目副本
        List<SalarySobItemPO> salarySobItemPOS = salarySobItemService.listBySalarySobIdWithHideItem(SalarySobItemPO.builder().salarySobId(duplicateParam.getId()).build());
        // 薪资项目副本去重
        salarySobItemPOS = salarySobItemPOS.stream().filter(SalaryEntityUtil.distinctByKey(PO -> PO.getSalarySobId() + "-" + PO.getSalaryItemId())).collect(Collectors.toList());
        // 查询薪资账套的薪资项目分类
        List<SalarySobItemGroupPO> salarySobItemGroupPOS = salarySobItemGroupService.listSomeWithItemHide(SalarySobItemGroupPO.builder().salarySobId(duplicateParam.getId()).build());
        // 查询薪资账套的调薪计薪规则
        List<SalarySobAdjustRulePO> salarySobAdjustRulePOS = salarySobAdjustRuleService.listBySalarySobId(duplicateParam.getId());
        // 查询薪资账套的校验规则
        List<SalarySobCheckRulePO> salarySobCheckRulePOS = getSalarySobCheckRuleService(user).listBySalarySobId(duplicateParam.getId());
        // 查询薪资账套的回算薪资项目
        List<SalarySobBackItemPO> salarySobBackItemPOS = getSalarySobBackItemService(user).listBySalarySobId(duplicateParam.getId());


        // 复制薪资账套的基础设置
        SalarySobPO newSalarySob = SalarySobPO.builder()
                .name(duplicateParam.getName())
                .taxAgentId(duplicateParam.getTaxAgentId())
                .incomeCategory(salarySobPO.getIncomeCategory())
                .salaryCycleType(salarySobPO.getSalaryCycleType())
                .salaryCycleFromDay(salarySobPO.getSalaryCycleFromDay())
                .taxCycleType(salarySobPO.getTaxCycleType())
                .attendCycleType(salarySobPO.getAttendCycleType())
                .attendCycleFromDay(salarySobPO.getAttendCycleFromDay())
                .socialSecurityCycleType(salarySobPO.getSocialSecurityCycleType())
                .disable(salarySobPO.getDisable())
                .creator((long) user.getUID())
                .createTime(new Date())
                .updateTime(new Date())
                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                .deleteType(NumberUtils.INTEGER_ZERO)
                .build();
        salarySobMapper.insert(newSalarySob);
        // 复制
        SalarySobDuplicateBO salarySobDuplicateBO = new SalarySobDuplicateBO(newSalarySob, salarySobEmpFieldPOS, salarySobItemPOS,
                salarySobItemGroupPOS, salarySobAdjustRulePOS, salarySobCheckRulePOS, salarySobBackItemPOS);
        SalarySobDuplicateBO.Result result = salarySobDuplicateBO.duplicate((long) user.getUID());
        // 复制薪资账套的员工信息字段
        if (CollectionUtils.isNotEmpty(result.getSalarySobEmpFields())) {
            salarySobEmpFieldService.batchInsert(result.getSalarySobEmpFields());
        }
        // 复制薪资账套的薪资项目副本
        if (CollectionUtils.isNotEmpty(result.getSalarySobItems())) {
            salarySobItemService.batchInsert(result.getSalarySobItems());
        }

        // 复制薪资账套的回算薪资项目
        if (CollectionUtils.isNotEmpty(result.getSalarySobBackItems())) {
            getSalarySobBackItemService(user).batchInsert(result.getSalarySobBackItems());
        }

        // 复制薪资账套的薪资项目隐藏副本
        if (CollectionUtils.isNotEmpty(result.getSalarySobItems())) {
            List<SalarySobItemPO> salarySobItems = result.getSalarySobItems();
            Date now = new Date();
            salarySobItems.stream().forEach(k -> {
                Long salarySobItemShowId = IdGenerator.generate();
                SalarySobItemHidePO salarySobItemHidePO = SalarySobItemHidePO.builder()
                        .id(salarySobItemShowId)
                        .salarySobId(k.getSalarySobId())
                        .salaryItemId(k.getSalaryItemId())
                        .isGroup(0)
                        .itemHide(k.getItemHide())
                        .creator((long) user.getUID())
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .createTime(now)
                        .updateTime(now)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                if (k.getItemHide() == null) {
                    salarySobItemHidePO.setItemHide(Long.valueOf(0));
                }
                salarySobItemService.InsertItemShow(salarySobItemHidePO);
            });
        }

        // 复制薪资账套的薪资项目分类
        if (CollectionUtils.isNotEmpty(result.getSalarySobItemGroups())) {
            salarySobItemGroupService.batchInsert(result.getSalarySobItemGroups());
        }

        // 复制薪资账套的薪资项目分类隐藏信息
        if (CollectionUtils.isNotEmpty(result.getSalarySobItemGroups())) {
            List<SalarySobItemGroupPO> salarySobItemGroups = result.getSalarySobItemGroups();
            Date now = new Date();
            salarySobItemGroups.stream().forEach(k -> {
                Long salarySobItemShowId = IdGenerator.generate();
                SalarySobItemHidePO salarySobItemHidePO = SalarySobItemHidePO.builder()
                        .id(salarySobItemShowId)
                        .salarySobId(k.getSalarySobId())
                        .salaryItemId(k.getId())
                        .isGroup(1)
                        .itemHide(k.getItemHide())
                        .creator((long) user.getUID())
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .createTime(now)
                        .updateTime(now)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                if (k.getItemHide() == null) {
                    salarySobItemHidePO.setItemHide(Long.valueOf(0));
                }
                salarySobItemService.InsertItemShow(salarySobItemHidePO);
            });
        }

        // 复制薪资账套的调薪计薪规则
        if (CollectionUtils.isNotEmpty(result.getSalaryAdjustmentRules())) {
            salarySobAdjustRuleService.batchInsert(result.getSalaryAdjustmentRules());
        }
        // 复制薪资账套的校验规则
        if (CollectionUtils.isNotEmpty(result.getSalarySobCheckRules())) {
            getSalarySobCheckRuleService(user).batchSave(result.getSalarySobCheckRules());
        }
       // 记录日志
       LoggerContext<SalarySobPO> loggerContext = new LoggerContext<>();
       loggerContext.setUser(user);
       loggerContext.setTargetId("" + result.getSalarySob().getId());
       loggerContext.setTargetName(result.getSalarySob().getName());
       loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
       loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(98570, "复制薪资账套"));
       loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(98570, "复制薪资账套") + ": " + salarySobPO.getName());
       SalaryElogConfig.salarySobLoggerTemplate.write(loggerContext);
    }

    @Override
    public SalarySobCycleDTO getSalarySobCycle(Long id, YearMonth salaryMonth) {
        // 查询薪资账套
        SalarySobPO salarySobPO = getById(id);
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }
        return SalarySobCycleBO.buildSalarySobCycle(salarySobPO, salaryMonth);
    }

    @Override
    public List<SalarySobPO> filterByAuthority(List<SalarySobPO> salarySobPOS) {
        long employeeId = user.getUID();
        // 判断是否是“总管理员”
        Boolean isChief = getTaxAgentService(user).isChief(employeeId);
        // 是否开启分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        // 开启分权后
        // 总管理员都能看见
        // 管理员自己管理的个税下的
        if (!openDevolution || isChief) {
            return salarySobPOS;
        }
        // 查询所有的个税扣缴义务人
        Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAll();
        Set<Long> allTaxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);
        // 查询个税扣缴义务人的管理员
        List<TaxAgentAdminPO> taxAgentAdminPOS = getTaxAgentAdminService(user).listByTaxAgentIds(allTaxAgentIds);
        Map<Long, Set<Long>> adminMap = SalaryEntityUtil.group2Map(taxAgentAdminPOS, TaxAgentAdminPO::getEmployeeId, TaxAgentAdminPO::getTaxAgentId);
        return salarySobPOS.stream().filter(salarySobPO -> {
            Set<Long> taxAgentIds = adminMap.get(employeeId);
            if (CollectionUtils.isEmpty(taxAgentIds)) {
                return false;
            }
            return taxAgentIds.contains(salarySobPO.getTaxAgentId());
        }).collect(Collectors.toList());
    }

    @Override
    public List<SalarySobPO> listByTaxAgentIds(Collection<Long> taxAgentIds) {
        if (CollectionUtils.isEmpty(taxAgentIds)) {
            return new ArrayList<>();
        }
        return getSalarySobMapper().listSome(SalarySobPO.builder().taxAgentIds(taxAgentIds).build());
    }


    public List<SalarySobPO> filterByAdmin(List<SalarySobPO> salarySobPOS) {
        long employeeId = user.getUID();
        // 是否开启分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        // 开启分权后
        // 管理员自己管理的个税下的
        if (!openDevolution) {
            return salarySobPOS;
        }
        // 查询所有的个税扣缴义务人
        Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAll();
        Set<Long> allTaxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);
        // 查询个税扣缴义务人的管理员
        List<TaxAgentAdminPO> taxAgentAdminPOS = getTaxAgentAdminService(user).listByTaxAgentIds(allTaxAgentIds);
        Map<Long, Set<Long>> adminMap = SalaryEntityUtil.group2Map(taxAgentAdminPOS, TaxAgentAdminPO::getEmployeeId, TaxAgentAdminPO::getTaxAgentId);
        return salarySobPOS.stream().filter(salarySobPO -> {
            Set<Long> taxAgentIds = adminMap.get(employeeId);
            if (CollectionUtils.isEmpty(taxAgentIds)) {
                return false;
            }
            return taxAgentIds.contains(salarySobPO.getTaxAgentId());
        }).collect(Collectors.toList());
    }

}
