package com.engine.salary.wrapper;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.salaryformula.ExpressFormula;
import com.engine.salary.entity.salaryitem.bo.SalaryItemBO;
import com.engine.salary.entity.salaryitem.dto.SalaryFieldListDTO;
import com.engine.salary.entity.salaryitem.dto.SalaryItemFormDTO;
import com.engine.salary.entity.salaryitem.dto.SalaryItemListDTO;
import com.engine.salary.entity.salaryitem.param.SalaryItemSaveParam;
import com.engine.salary.entity.salaryitem.param.SalaryItemSearchParam;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salaryitem.po.SysSalaryItemPO;
import com.engine.salary.enums.*;
import com.engine.salary.enums.salaryitem.SalaryDataTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.service.SalaryFormulaService;
import com.engine.salary.service.SalaryItemService;
import com.engine.salary.service.SalarySobItemService;
import com.engine.salary.service.SysSalaryItemService;
import com.engine.salary.service.impl.SalaryFormulaServiceImpl;
import com.engine.salary.service.impl.SalaryItemServiceImpl;
import com.engine.salary.service.impl.SalarySobItemServiceImpl;
import com.engine.salary.service.impl.SysSalaryItemServiceImpl;
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.page.Column;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.valid.RuntimeTypeEnum;
import com.engine.salary.util.valid.ValidUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import weaver.hrm.User;

import java.util.*;

/**
 * 字段管理
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalaryFieldWrapper extends Service {

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

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


    private SalarySobItemService getSalarySobItemService(User user) {
        return ServiceUtil.getService(SalarySobItemServiceImpl.class, user);
    }

    private SalaryItemWrapper getSalaryItemWrapper(User user) {
        return ServiceUtil.getService(SalaryItemWrapper.class, user);
    }

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

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

    /**
     * 薪资项目列表
     *
     * @param searchParam 查询参数
     * @return
     */
    public PageInfo<SalaryItemListDTO> listPage(SalaryItemSearchParam searchParam) {

        SalaryItemServiceImpl.UsingItem usingItem = getSalaryItemService(user).getUsingItem();
        List<Long> usingFormulaIds = usingItem.getUsingFormulaIds();
        List<Long> usingItemIds = usingItem.getUsingItemIds();
        List<String> usingCodes = usingItem.getUsingCodes();

        // 1、查询薪资项目
        //设置查询档案引用项目
        searchParam.setUseInEmployeeSalary(SalaryOnOffEnum.ON.getValue());

        PageInfo<SalaryItemPO> page = getSalaryItemService(user).listPageByParam(searchParam);
        List<SalaryItemPO> salaryItemList = page.getList();

        //最终返回的分页对象
        PageInfo<SalaryItemListDTO> salaryItemListDTOPage = new PageInfo<>(SalaryItemListDTO.class);
        salaryItemListDTOPage.setPageSize(page.getPageSize());
        salaryItemListDTOPage.setPageNum(page.getPageNum());
        salaryItemListDTOPage.setTotal(page.getTotal());
        //获取字段管理的字段列表
        PageInfo<SalaryFieldListDTO> fieldColumnsPage = new PageInfo<>(SalaryFieldListDTO.class);
        List<Column> fieldColumns = fieldColumnsPage.getColumns();
        salaryItemListDTOPage.getColumns().clear();
        salaryItemListDTOPage.setColumns(fieldColumns);

        //是否需要系统算税，不需要则去除系统项目
        TaxDeclarationFunctionEnum taxDeclarationFunctionEnum = getSalarySysConfService(user).getTaxDeclaration();

        // 被薪资账套引用的薪资项目
        if (CollectionUtils.isNotEmpty(salaryItemList)) {
            // 查询系统薪资项目
            Set<Long> sysSalaryItemIds = SalaryEntityUtil.properties(salaryItemList, SalaryItemPO::getSysSalaryItemId);
            List<SysSalaryItemPO> sysSalaryItemPOS = getSysSalaryItemService(user).listByIds(sysSalaryItemIds);
            // 转换成薪资项目列表dto
            List<SalaryItemListDTO> salaryItemListDTOS = SalaryItemBO.convert2ListDTO(salaryItemList, Collections.emptyList(), sysSalaryItemPOS);
            //系统项目不删除
            salaryItemListDTOS.forEach(dto -> {
                if ((taxDeclarationFunctionEnum != TaxDeclarationFunctionEnum.CLOSURE && StringUtils.isNotBlank(dto.getSystemName()))
                        || usingItemIds.contains(dto.getId())
                        || usingCodes.contains(dto.getCode())) {
                    dto.setCanDelete(false);
                }
            });
            salaryItemListDTOPage.setList(salaryItemListDTOS);
        }
        return salaryItemListDTOPage;

    }

    /**
     * 薪资项目详情
     *
     * @param id 主键id
     * @return
     */
    public SalaryItemFormDTO getForm(Long id) {
        SalaryItemFormDTO salaryItemFormDTO = new SalaryItemFormDTO();
        // 默认可以编辑
        salaryItemFormDTO.setCanEdit(NumberUtils.INTEGER_ONE);
        if (!Objects.isNull(id)) {
            // 查询薪资项目
            SalaryItemPO salaryItemPO = getSalaryItemService(user).getById(id);
            // 系统薪资项目
            if (Objects.isNull(salaryItemPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98299, "参数错误，薪资项目不存在或已被删除"));
            }
            ExpressFormula expressFormula;
//            // 转换成薪资项目详情dto

            salaryItemFormDTO = SalaryItemBO.convert2FormDTO(salaryItemPO);
            expressFormula = getSalaryFormulaService(user).getExpressFormula(salaryItemPO.getFormulaId());
            salaryItemFormDTO.setFormulaContent(Optional.ofNullable(expressFormula).map(ExpressFormula::getFormula).orElse(""));
        }
        return salaryItemFormDTO;
    }

    /**
     * 保存薪资项目
     *
     * @param saveParam 保存参数
     */
    public void save(SalaryItemSaveParam saveParam) {
        saveParam.setValueType(SalaryValueTypeEnum.INPUT.getValue());
        if (null == saveParam.getUseInEmployeeSalary()) {
            saveParam.setUseInEmployeeSalary(NumberUtils.INTEGER_ONE);
        }
        saveParam.setSystemType(SalarySystemTypeEnum.CUSTOM.getValue());

        ValidUtil.doValidator(saveParam);
        validParam(saveParam);

        SalaryItemPO salaryItemPO = getSalaryItemService(user).save(saveParam);
        // 记录日志
        LoggerContext<SalaryItemPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(salaryItemPO.getId()));
        loggerContext.setTargetName(salaryItemPO.getName());
        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新建字段"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新建字段") + ": " + salaryItemPO.getName());
        loggerContext.setNewValues(salaryItemPO);
        SalaryElogConfig.salaryArchiveFieldLoggerTemplate.write(loggerContext);
    }

    private void validParam(SalaryItemSaveParam saveParam) {
        if (SalarySystemTypeEnum.parseByValue(saveParam.getSystemType()) == null) {
            throw new SalaryRunTimeException("系统内置的薪资项目异常");
        }
        if (SalaryRoundingModeEnum.parseByValue(saveParam.getRoundingMode()) == null) {
            throw new SalaryRunTimeException("舍入规则异常");
        }
        if (SalaryValueTypeEnum.parseByValue(saveParam.getValueType()) == null) {
            throw new SalaryRunTimeException("取值方式异常");
        }
        if (SalaryDataTypeEnum.parseByValue(saveParam.getDataType()) == null) {
            throw new SalaryRunTimeException("字段类型异常");
        }
    }

    /**
     * 编辑薪资项目
     *
     * @param saveParam 更新参数
     */
    public void update(SalaryItemSaveParam saveParam) {
        saveParam.setValueType(SalaryValueTypeEnum.INPUT.getValue());
        if (null == saveParam.getUseInEmployeeSalary()) {
            saveParam.setUseInEmployeeSalary(NumberUtils.INTEGER_ONE);
        }
        saveParam.setSystemType(SalarySystemTypeEnum.CUSTOM.getValue());

        ValidUtil.doValidator(saveParam, RuntimeTypeEnum.UPDATE);
        validParam(saveParam);
        SalaryItemPO salaryItemPO = getSalaryItemService(user).update(saveParam);

        // 记录日志
        SalaryItemPO newSalaryItemPO = getSalaryItemService(user).getById(salaryItemPO.getId());
        LoggerContext<SalaryItemPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(newSalaryItemPO.getId()));
        loggerContext.setTargetName(newSalaryItemPO.getName());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "编辑字段"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "编辑字段") + ": " + newSalaryItemPO.getName());
        loggerContext.setOldValues(salaryItemPO);
        loggerContext.setNewValues(newSalaryItemPO);
        SalaryElogConfig.salaryArchiveFieldLoggerTemplate.write(loggerContext);
    }

    /**
     * 删除薪资项目
     *
     * @param ids 主键id
     */
    public void delete(Collection<Long> ids) {
        getSalaryItemService(user).deleteByIds(ids);
    }

    /**
     * 保存字段排序信息
     *
     * @param salaryItemPOS
     */
    public void saveSortedIndex(List<SalaryItemPO> salaryItemPOS) {
        getSalaryItemService(user).batchUpdateSortedIndex(salaryItemPOS);
    }
}
