package com.engine.salary.entity.salaryitem.bo;

import com.engine.salary.annotation.SalaryTableColumn;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.salaryformula.ExpressFormula;
import com.engine.salary.entity.salaryitem.dto.SalaryItemFormDTO;
import com.engine.salary.entity.salaryitem.dto.SalaryItemListDTO;
import com.engine.salary.entity.salaryitem.dto.SalaryItemSobListDTO;
import com.engine.salary.entity.salaryitem.param.SalaryItemSaveParam;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salaryitem.po.SysSalaryItemPO;
import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationAnnualListDTO;
import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationLaborListDTO;
import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationWageListDTO;
import com.engine.salary.enums.SalaryRoundingModeEnum;
import com.engine.salary.enums.SalarySystemTypeEnum;
import com.engine.salary.enums.SalaryValueTypeEnum;
import com.engine.salary.enums.salaryitem.SalaryDataTypeEnum;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import weaver.conn.util.IdGenerator;
import weaver.general.BaseBean;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 薪资项目
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalaryItemBO {

    private static final BaseBean baseBean = new BaseBean();

    //强制开启账套的公式配置
    private static final Boolean openFormulaForcedEditing = "true".equals(baseBean.getPropValue("hrmSalary", "openFormulaForcedEditing"));



    /**
     * 构建薪资项目的查询参数
     *
     * @param searchParam
     * @param tenantKey
     * @return
     */
//    public static Wrapper<SalaryItemPO> buildQueryWrapper(SalaryItemSearchParam searchParam, String tenantKey) {
//        LambdaQueryWrapper<SalaryItemPO> wrapper = Wrappers.<SalaryItemPO>lambdaQuery();
//        wrapper.eq(SalaryItemPO::getTenantKey, tenantKey)
//                .eq(SalaryItemPO::getDeleteType, 0)
//                .like(!SalaryEntityUtil.isNullOrEmpty(searchParam.getName()), SalaryItemPO::getName, searchParam.getName())
//                .like(!SalaryEntityUtil.isNullOrEmpty(searchParam.getDescription()), SalaryItemPO::getDescription, searchParam.getDescription())
//                .notIn(SalaryEntityUtil.isNotNullOrEmpty(searchParam.getExcludeIds()), SalaryItemPO::getId, searchParam.getExcludeIds());
//        if (searchParam.getValueType() != null) {
//            wrapper.eq(SalaryItemPO::getValueType, searchParam.getValueType().getValue());
//        }
//        if (searchParam.getUseInEmployeeSalary() != null) {
//            wrapper.eq(SalaryItemPO::getUseInEmployeeSalary, searchParam.getUseInEmployeeSalary().getValue());
//        }
//        if (searchParam.getUseDefault() != null) {
//            wrapper.eq(SalaryItemPO::getUseDefault, searchParam.getUseDefault().getValue());
//        }
//        if (searchParam.getDataType() != null) {
//            wrapper.eq(SalaryItemPO::getDataType, searchParam.getDataType().getValue());
//        }
//        wrapper.orderByDesc(SalaryItemPO::getId);
//        return wrapper;
//    }

    /**
     * 薪资项目po转换成薪资项目列表dto
     *
     * @param salaryItems     薪资项目po
     * @param expressFormulas 公式详情
     * @return
     */
    public static List<SalaryItemListDTO> convert2ListDTO(Collection<SalaryItemPO> salaryItems, List<ExpressFormula> expressFormulas,List<SysSalaryItemPO> sysSalaryItemPOS) {
        if (CollectionUtils.isEmpty(salaryItems)) {
            return Collections.emptyList();
        }
        Map<Long, String> formulaMap = SalaryEntityUtil.convert2Map(expressFormulas, ExpressFormula::getId, ExpressFormula::getFormula);
        Map<Long, String> sysSalaryItemNameMap = SalaryEntityUtil.convert2Map(sysSalaryItemPOS, SysSalaryItemPO::getId, SysSalaryItemPO::getName);
        return salaryItems.stream().map(salaryItemPO -> {
                    SalaryRoundingModeEnum salaryRoundingModeEnum = SalaryRoundingModeEnum.parseByValue(salaryItemPO.getRoundingMode());
                    SalaryValueTypeEnum salaryValueTypeEnum = SalaryValueTypeEnum.parseByValue(salaryItemPO.getValueType());
                    SalaryDataTypeEnum salaryDataTypeEnum = SalaryDataTypeEnum.parseByValue(salaryItemPO.getDataType());
                    return SalaryItemListDTO.builder()
                            .id(salaryItemPO.getId())
                            .code(salaryItemPO.getCode())
                            .name(salaryItemPO.getName())
                            .systemName(sysSalaryItemNameMap.getOrDefault(salaryItemPO.getSysSalaryItemId(), StringUtils.EMPTY))
                            .useInEmployeeSalary(salaryItemPO.getUseInEmployeeSalary())
                            .useDefault(salaryItemPO.getUseDefault())
                            .hideDefault(salaryItemPO.getHideDefault() == null ? 0 : salaryItemPO.getHideDefault())
                            .roundingMode(Optional.ofNullable(salaryRoundingModeEnum)
                                    .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                                    .orElse(StringUtils.EMPTY))
                            .pattern(salaryItemPO.getPattern())
                            .valueType(Optional.ofNullable(salaryValueTypeEnum)
                                    .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                                    .orElse(StringUtils.EMPTY))
                            .dataType(Optional.ofNullable(salaryDataTypeEnum)
                                    .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                                    .orElse(StringUtils.EMPTY))
                            .formulaId(salaryItemPO.getFormulaId())
                            .formulaContent(formulaMap.getOrDefault(salaryItemPO.getFormulaId(), ""))
                            .taxDeclarationColumn(buildTaxDeclarationColumn(salaryItemPO.getCode()))
                            .sortedIndex(salaryItemPO.getSortedIndex())
                            .description(salaryItemPO.getDescription())
                            .canDelete(true)
                            .canEdit(openFormulaForcedEditing ||Objects.equals(salaryItemPO.getCanEdit(), NumberUtils.INTEGER_ONE))
                            .width(salaryItemPO.getWidth())
                            .build();
                }
        ).collect(Collectors.toList());
    }

    /**
     * 薪资项目po转换成薪资账套中薪资项目列表dto
     *
     * @param salaryItems     薪资项目po
     * @param expressFormulas 公式详情
     * @return
     */
    public static List<SalaryItemSobListDTO> convert2itemSobListDTO(Collection<SalaryItemPO> salaryItems, List<ExpressFormula> expressFormulas, List<SysSalaryItemPO> sysSalaryItemPOS) {
        if (CollectionUtils.isEmpty(salaryItems)) {
            return Collections.emptyList();
        }
        Map<Long, String> formulaMap = SalaryEntityUtil.convert2Map(expressFormulas, ExpressFormula::getId, ExpressFormula::getFormula);
        Map<Long, String> sysSalaryItemNameMap = SalaryEntityUtil.convert2Map(sysSalaryItemPOS, SysSalaryItemPO::getId, SysSalaryItemPO::getName);
        return salaryItems.stream().map(salaryItemPO -> {
                    SalaryRoundingModeEnum salaryRoundingModeEnum = SalaryRoundingModeEnum.parseByValue(salaryItemPO.getRoundingMode());
                    SalaryValueTypeEnum salaryValueTypeEnum = SalaryValueTypeEnum.parseByValue(salaryItemPO.getValueType());
                    SalaryDataTypeEnum salaryDataTypeEnum = SalaryDataTypeEnum.parseByValue(salaryItemPO.getDataType());
                    return SalaryItemSobListDTO.builder()
                            .id(salaryItemPO.getId())
                            .code(salaryItemPO.getCode())
                            .name(salaryItemPO.getName())
                            .systemName(sysSalaryItemNameMap.getOrDefault(salaryItemPO.getSysSalaryItemId(), StringUtils.EMPTY))
                            .useInEmployeeSalary(salaryItemPO.getUseInEmployeeSalary())
                            .useDefault(salaryItemPO.getUseDefault())
                            .hideDefault(salaryItemPO.getHideDefault() == null ? 0 : salaryItemPO.getHideDefault())
                            .roundingMode(salaryItemPO.getRoundingMode())
                            .roundingModeShowValue(Optional.ofNullable(salaryRoundingModeEnum)
                                    .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                                    .orElse(StringUtils.EMPTY))
                            .pattern(salaryItemPO.getPattern())
                            .valueType(salaryItemPO.getValueType())
                            .valueTypeShowValue(Optional.ofNullable(salaryValueTypeEnum)
                                    .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                                    .orElse(StringUtils.EMPTY))
                            .dataType(salaryItemPO.getDataType())
                            .dataTypeShowValue(Optional.ofNullable(salaryDataTypeEnum)
                                    .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                                    .orElse(StringUtils.EMPTY))
                            .formulaId(salaryItemPO.getFormulaId())
                            .formulaContent(formulaMap.getOrDefault(salaryItemPO.getFormulaId(),""))
                            .originFormulaContent(salaryValueTypeEnum.getValue() == SalaryValueTypeEnum.FORMULA.getValue() ? formulaMap.getOrDefault(salaryItemPO.getFormulaId(),"") : "")
                            .originSqlContent(salaryValueTypeEnum.getValue() == SalaryValueTypeEnum.SQL.getValue() ? formulaMap.getOrDefault(salaryItemPO.getFormulaId(),"") : "")
                            .taxDeclarationColumn(buildTaxDeclarationColumn(salaryItemPO.getCode()))
                            .canDelete(true)
                            .canEdit(openFormulaForcedEditing ||Objects.equals(salaryItemPO.getCanEdit(), NumberUtils.INTEGER_ONE))
                            .sortedIndex(salaryItemPO.getSortedIndex())
                            .description(salaryItemPO.getDescription())
                            .salaryItemType(salaryItemPO.getUseInEmployeeSalary() == 0 ? "薪资项目" : "档案字段")
                            .build();
                }
        ).collect(Collectors.toList());
    }


    /**
     * 转换成薪资项目详情dto
     *
     * @param salaryItemPO
     * @return
     */
    public static SalaryItemFormDTO convert2FormDTO(SalaryItemPO salaryItemPO) {
        return new SalaryItemFormDTO()
                .setId(salaryItemPO.getId())
                .setName(salaryItemPO.getName())
                .setSystemType(salaryItemPO.getSystemType())
                .setUseDefault(salaryItemPO.getUseDefault())
                .setHideDefault(salaryItemPO.getHideDefault() == null ? 0 : salaryItemPO.getHideDefault())
                .setUseInEmployeeSalary(salaryItemPO.getUseInEmployeeSalary())
                .setRoundingMode(salaryItemPO.getRoundingMode())
                .setPattern(salaryItemPO.getPattern())
                .setValueType(salaryItemPO.getValueType())
                .setDataType(salaryItemPO.getDataType())
                .setFormulaId(salaryItemPO.getFormulaId())
                .setTaxDeclarationColumn(buildTaxDeclarationColumn(salaryItemPO.getCode()))
                .setDescription(salaryItemPO.getDescription())
                .setCanEdit(salaryItemPO.getCanEdit())
                .setTaxAgentIds(salaryItemPO.getTaxAgentIds())
                .setSharedType(salaryItemPO.getSharedType())
                .setSortedIndex(salaryItemPO.getSortedIndex())
                .setWidth(salaryItemPO.getWidth());
    }

    /**
     * 个税申报表中的对应字段
     *
     * @param code
     * @return
     */
    public static String buildTaxDeclarationColumn(String code) {
        // 是否是个税申报表（正常工资薪金所得）中的字段
        for (Field declaredField : TaxDeclarationWageListDTO.class.getDeclaredFields()) {
            if (!declaredField.isAnnotationPresent(SalaryTableColumn.class)) {
                continue;
            }
            if (Objects.equals(code, declaredField.getName())) {
                SalaryTableColumn annotation = declaredField.getAnnotation(SalaryTableColumn.class);
                return SalaryI18nUtil.getI18nLabel((int) annotation.labelId(), annotation.text());
            }
        }
        // 是否是个税申报表（劳务报酬所得）中的字段
        for (Field declaredField : TaxDeclarationLaborListDTO.class.getDeclaredFields()) {
            if (!declaredField.isAnnotationPresent(SalaryTableColumn.class)) {
                continue;
            }
            // 时间紧迫，临时处理
            if (Objects.equals(code, declaredField.getName()) || Objects.equals(code, declaredField.getName() + "4")) {
                SalaryTableColumn annotation = declaredField.getAnnotation(SalaryTableColumn.class);
                return SalaryI18nUtil.getI18nLabel((int) annotation.labelId(), annotation.text());
            }
        }

        // 是否是个税申报表（全年一次性奖金）中的字段
        for (Field declaredField : TaxDeclarationAnnualListDTO.class.getDeclaredFields()) {
            if (!declaredField.isAnnotationPresent(SalaryTableColumn.class)) {
                continue;
            }
            // 时间紧迫，临时处理
            if (Objects.equals(code, declaredField.getName()) || Objects.equals(code, declaredField.getName() + "2")) {
                SalaryTableColumn annotation = declaredField.getAnnotation(SalaryTableColumn.class);
                return SalaryI18nUtil.getI18nLabel((int) annotation.labelId(), annotation.text());
            }
        }
        return StringUtils.EMPTY;
    }

    /**
     * 保存参数/更新参数 转换成薪资项目po
     *
     * @param saveParam  保存参数/更新参数
     * @param employeeId 人员id
     * @return
     */
    public static SalaryItemPO convert2SalaryItemPO(SalaryItemSaveParam saveParam, Long employeeId) {
        Date now = new Date();
        long id = com.engine.salary.util.db.IdGenerator.generate();
        SalaryItemPO salaryItemPO = SalaryItemPO.builder()
                .id(id)
                .code(IdGenerator.getUUID())
                .name(saveParam.getName())
                .systemType(SalarySystemTypeEnum.CUSTOM.getValue())
                .sysSalaryItemId(NumberUtils.LONG_ZERO)
                .useDefault(saveParam.getUseDefault())
                .useInEmployeeSalary(saveParam.getUseInEmployeeSalary())
                .hideDefault(saveParam.getHideDefault())
                .roundingMode(saveParam.getRoundingMode() == null ? SalaryRoundingModeEnum.ROUNDING.getValue() : saveParam.getRoundingMode())
                .pattern(Optional.ofNullable(saveParam.getPattern()).orElse(2))
                .valueType(saveParam.getValueType())
                .dataType(saveParam.getDataType())
                .formulaId(Objects.equals(saveParam.getValueType(), SalaryValueTypeEnum.INPUT.getValue()) ? NumberUtils.LONG_ZERO : Optional.ofNullable(saveParam.getFormulaId()).orElse(NumberUtils.LONG_ZERO))
                .description(saveParam.getDescription())
                .canEdit(NumberUtils.INTEGER_ONE)
                .creator(employeeId)
                .deleteType(NumberUtils.INTEGER_ZERO)
                .createTime(now)
                .updateTime(now)
                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                .sharedType(Optional.ofNullable(saveParam.getSharedType()).orElse(0))
                .taxAgentIds(saveParam.getTaxAgentIds())
                .sortedIndex(saveParam.getSortedIndex())
                .width(saveParam.getWidth())
                .build();
        // 开启了"薪资档案引用"，取值方式固定为输入
//        if (Objects.equals(saveParam.getUseInEmployeeSalary(), NumberUtils.INTEGER_ONE)) {
//            salaryItemPO.setValueType(SalaryValueTypeEnum.INPUT.getValue());
//            salaryItemPO.setFormulaId(NumberUtils.LONG_ZERO);
//        }
        return salaryItemPO;
    }
}
