package com.engine.salary.wrapper;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
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.SalarySobBO;
import com.engine.salary.entity.salarysob.bo.SalarySobBackItemBO;
import com.engine.salary.entity.salarysob.dto.SalarySobBasicFormDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobListDTO;
import com.engine.salary.entity.salarysob.param.SalarySobBasicSaveParam;
import com.engine.salary.entity.salarysob.param.SalarySobDisableParam;
import com.engine.salary.entity.salarysob.param.SalarySobDuplicateParam;
import com.engine.salary.entity.salarysob.param.SalarySobListQueryParam;
import com.engine.salary.entity.salarysob.po.SalarySobBackItemPO;
import com.engine.salary.entity.salarysob.po.SalarySobDefaultBackItemPO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.salarysob.IncomeCategoryEnum;
import com.engine.salary.enums.sicategory.DeleteTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.service.*;
import com.engine.salary.service.impl.*;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.SalarySobUtil;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.db.IdGenerator;
import org.apache.commons.collections4.CollectionUtils;
import weaver.hrm.User;

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

/**
 * 薪资账套
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalarySobWrapper extends Service {


    public SalarySobService getSalarySobService(User user) {
        return ServiceUtil.getService(SalarySobServiceImpl.class, user);
    }


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

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

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

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


    /**
     * 薪资账套列表
     *
     * @param queryParam 列表查询参数
     * @return
     */
    public PageInfo<SalarySobListDTO> listPage(SalarySobListQueryParam queryParam) {

        // 处理历史数据，将薪资账套中将关联人员状态转换为List
        SalarySobUtil.handleEmployeeStatusHistory();
        // 查询薪资账套
        PageInfo<SalarySobPO> page = getSalarySobService(user).listPageByParam(queryParam);
        // 薪资账套po转换成薪资账套列表dto
        List<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAll();
        Map<Long, String> taxAgentIdTONameMap = SalaryEntityUtil.convert2Map(taxAgentPOS, TaxAgentPO::getId, TaxAgentPO::getName);

        List<SalarySobListDTO> salarySobListDTOS = SalarySobBO.convert2ListDTO(page.getList(),taxAgentIdTONameMap);
        PageInfo<SalarySobListDTO> dtoPage = new PageInfo<>(salarySobListDTOS, SalarySobListDTO.class);
        dtoPage.setTotal(page.getTotal());
        dtoPage.setPageNum(page.getPageNum());
        dtoPage.setPageSize(page.getPageSize());
        // 处理历史数据，为薪资账套默认添加回算薪资项目
        handleSalarySobBackItemHistory(queryParam);
        // 转换成前端所需的数据格式
        return dtoPage;
    }


    /**
     * 薪资账套列表
     *
     * @return
     */
    public List<SalarySobPO> listAll() {
        return getSalarySobService(user).listAll();
    }

    private void handleSalarySobBackItemHistory(SalarySobListQueryParam queryParam) {
        queryParam.setPageSize(100000);
        List<SalarySobPO> list = getSalarySobService(user).listPageByParam(queryParam).getList();
        if(list != null && list.size()>0){
            List<Long> salarySobIds = list.stream().map(SalarySobPO::getId).collect(Collectors.toList());
            Long count = getSalarySobBackItemService(user).getCountBySalarySobIdIn(salarySobIds);
            if(count.equals(0L)){
                // 薪资账套的默认的回算薪资项目
                Set<Long> SalarySobBackItemIds = SalaryEntityUtil.properties(SalarySobBackItemBO.getDefault(), SalarySobDefaultBackItemPO::getSysSalaryItemId);
                // 获取薪资项目中是否已经添加回算薪资项目
                List<SalaryItemPO> salaryItemPOS = getSalaryItemService(user).listBySysSalaryItemIds(SalarySobBackItemIds);
                Set<Long> salaryBackItemSysIds = SalaryEntityUtil.properties(salaryItemPOS, SalaryItemPO::getSysSalaryItemId);
                // 需要添加进薪资项目中的回算薪资项目
                List<Long> needAddSalaryBackItemIds = SalarySobBackItemIds.stream().filter(salarySobBackItemId -> !salaryBackItemSysIds.contains(salarySobBackItemId)).collect(Collectors.toList());
                List<SysSalaryItemPO> needAddSysSalaryBackItemPOS = getSysSalaryItemService(user).listByIds(needAddSalaryBackItemIds);
                // 需要保存的回算薪资项目
                List<SalaryItemPO> needInsertSalaryItemPOS = SysSalaryItemBO.convert2SalaryItemPO(needAddSysSalaryBackItemPOS, (long) user.getUID());
                if (CollectionUtils.isNotEmpty(needInsertSalaryItemPOS)) {
                    getSalaryItemService(user).batchSave(needInsertSalaryItemPOS);
                }
                // 没有回算薪资项目数据，给所有薪资账套添加默认回算薪资项目
                List<SalarySobBackItemPO> salarySobBackItems = new ArrayList<>();
                // 获取默认添加后的回算薪资项目
                List<SalaryItemPO> salaryBackItemPOS = getSalaryItemService(user).listBySysSalaryItemIds(SalarySobBackItemIds);
                for(Long id : salarySobIds){
                    for (SalarySobDefaultBackItemPO salarySobDefaultBackItemPO : SalarySobBackItemBO.getDefault()) {
                        Date now = new Date();
                        Map<Long, SalaryItemPO> sysSalaryItemMap = SalaryEntityUtil.convert2Map(salaryBackItemPOS, SalaryItemPO::getSysSalaryItemId);
                        SalaryItemPO salaryItemPO = sysSalaryItemMap.get(salarySobDefaultBackItemPO.getSysSalaryItemId());
                        SalarySobBackItemPO salarySobBackItemPO = SalarySobBackItemPO.builder()
                                .id(IdGenerator.generate())
                                .salarySobId(id)
                                .salaryItemId(salaryItemPO.getId())
                                .salaryItemCode(salaryItemPO.getCode())
                                .dataType(salaryItemPO.getDataType())
                                .roundingMode(salaryItemPO.getRoundingMode())
                                .pattern(salaryItemPO.getPattern())
                                .valueType(salaryItemPO.getValueType())
                                .formulaId(salarySobDefaultBackItemPO.getFormulaId())
                                .backCalcType(salarySobDefaultBackItemPO.getBackCalcType())
                                .creator((long)user.getUID())
                                .createTime(now)
                                .updateTime(now)
                                .deleteType(DeleteTypeEnum.NOT_DELETED.getValue())
                                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY).build();
                        salarySobBackItems.add(salarySobBackItemPO);
                    }
                }
                // 入库
                getSalarySobBackItemService(user).batchInsert(salarySobBackItems);
            }
        }

    }

    /**
     * 薪资账套详情
     *
     * @param id 薪资账套id
     * @return
     */
    public Map<String, Object> getForm(Long id) {
        long employeeId = user.getUID();
        Map<String, Object> data = new HashMap<>(16);

        // 是否可以编辑（分权后，总管理员不可以编辑管理员新建的账套）
        boolean canEdit = Objects.isNull(id) || canEdit(id, employeeId);

        // 薪资账套基础设置详情（目前核算人员范围的值固定为"1"）
        SalarySobBasicFormDTO basicForm = new SalarySobBasicFormDTO()
                .setEmployeeRange("1")
                .setTaxableItems(IncomeCategoryEnum.WAGES_AND_SALARIES.getValue())
                .setCanEdit(canEdit);
        if (!Objects.isNull(id)) {
            // 查询薪资账套
            SalarySobPO salarySobPO = getSalarySobService(user).getById(id);
            if (Objects.isNull(salarySobPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
            }
            // 薪资装套po转换成薪资账套详情dto
            basicForm = SalarySobBO.convert2FormDTO(basicForm,salarySobPO);
        }
        // 转换成前端所需的数据格式
        data.put("basicForm", basicForm);
        return data;

    }

    /**
     * 保存
     *
     * @param saveParam 保存参数
     * @return
     */
    public Long save(SalarySobBasicSaveParam saveParam) {
        return getSalarySobService(user).save(saveParam);
    }

    /**
     * 更新薪资账套的基础设置
     *
     * @param saveParam 更新参数
     * @return
     */
    public Long update(SalarySobBasicSaveParam saveParam) {
        return getSalarySobService(user).update(saveParam);
    }

    /**
     * 启用/禁用薪资账套
     *
     * @param disableParam 更新参数
     */
    public void updateDisable(SalarySobDisableParam disableParam) {
        getSalarySobService(user).updateDisable(disableParam);
    }

    /**
     * 删除薪资账套
     *
     * @param ids 薪资账套的id
     */
    public void delete(Collection<Long> ids) {
        getSalarySobService(user).deleteByIds(ids);
    }

    /**
     * 复制
     *
     * @param duplicateParam 复制参数
     */
    public void duplicate(SalarySobDuplicateParam duplicateParam) {
        getSalarySobService(user).duplicate(duplicateParam);
    }

    /**
     * 判断是否可以编辑薪资账套
     *
     * @param id
     * @param employeeId
     * @return
     */
    public boolean canEdit(Long id, Long employeeId) {
        // 查询薪资账套
        SalarySobPO salarySobPO = getSalarySobService(user).getById(id);
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98379, "参数错误，薪资账套不存在或者已被删除"));
        }

        // 判断是否开启了分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        if (!openDevolution) {
            return true;
        }
        Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(employeeId);
        Set<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);

        return taxAgentIds.contains(salarySobPO.getTaxAgentId())||Objects.isNull(salarySobPO.getTaxAgentId());
    }

}
