package com.engine.salary.service.impl;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.annotation.SalaryFormulaVar;
import com.engine.salary.constant.SalaryFormulaFieldConstant;
import com.engine.salary.entity.datacollection.AddUpDeduction;
import com.engine.salary.entity.datacollection.AddUpSituation;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.datacollection.dto.AttendQuoteFieldListDTO;
import com.engine.salary.entity.datacollection.param.AttendQuoteFieldQueryParam;
import com.engine.salary.entity.datacollection.po.OtherDeductionPO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctEmployeePO;
import com.engine.salary.entity.salaryformula.dto.SalaryFormulaTaxRateDTO;
import com.engine.salary.entity.salaryformula.po.FormulaVar;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.po.SalarySobItemPO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.entity.taxrate.TaxRateBase;
import com.engine.salary.enums.salaryformula.ReferenceTypeEnum;
import com.engine.salary.enums.salaryformula.SalaryFormulaReferenceEnum;
import com.engine.salary.enums.salaryformula.SalarySQLReferenceEnum;
import com.engine.salary.formlua.entity.parameter.DataType;
import com.engine.salary.mapper.datacollection.AttendQuoteFieldMapper;
import com.engine.salary.service.*;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.MapperProxyFactory;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import weaver.hrm.User;

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


public class RemoteExcelServiceImpl extends Service implements RemoteExcelService {

    private static final Logger log = LoggerFactory.getLogger(RemoteExcelServiceImpl.class);


    private SIAccountService getSIAccountService(User user) {
        return (SIAccountService) ServiceUtil.getService(SIAccountServiceImpl.class, user);
    }


    private AttendQuoteFieldMapper getAttendQuoteFieldMapper() {
        return MapperProxyFactory.getProxy(AttendQuoteFieldMapper.class);
    }


    private TaxRateBaseService getTaxRateBaseService(User user) {
        return (TaxRateBaseService) ServiceUtil.getService(TaxRateBaseServiceImpl.class, user);
    }


    private TaxRateDetailService getTaxRateDetailService(User user) {
        return (TaxRateDetailService) ServiceUtil.getService(TaxRateDetailServiceImpl.class, user);
    }


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

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

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

//    @Override
//    public ExcelResult aggregation(AggFunc func, String sourceId, String fieldId, List<FormulaFilterData> filterFormDataList, Map<String, Object> extendParam,
//                                   DataCollectionEmployee employee) {
//        return null;
//    }

//    @Override
//    public ExcelPage<FormulaCategory> categoryList(ExcelPage<FormulaCategory> page, Map<String, Object> extendParam, DataCollectionEmployee employee) {
//        log.info("page: {}", JsonUtil.toJsonString(page));
//        List<FormulaCategory> categories = Lists.newArrayList();
//        FormulaCategory category = new FormulaCategory();
//        category.setId("TAX_RATE");
//        category.setName(SalaryI18nUtil.getI18nLabel(employee.getTenantKey(), employee.getEmployeeId(), 85370, "个税税率表"));
//        category.setModule(SalaryFormulaFieldConstant.MODULE);
//        category.setType(SalaryFormulaFieldConstant.MODULE);
//        categories.add(category);
//        page.setCount(1);
//        page.setPageResult(categories);
//        log.info("page: {}", JsonUtil.toJsonString(page));
//        return page;
//    }

    @Override
    public List<FormulaVar> fieldList(String sourceId, Map<String, Object> extendParam) {

        List<FormulaVar> vars = new ArrayList<>();

        //sql
        if (extendParam != null) {
            String referenceType = extendParam.get("referenceType") == null ? "" : extendParam.get("referenceType").toString();
            if (ReferenceTypeEnum.SQL.getValue().equals(referenceType)) {
                SalarySQLReferenceEnum referenceEnum = SalarySQLReferenceEnum.parseByValue(sourceId);
                if (referenceEnum != null) {
                    switch (referenceEnum) {
                        case EMPLOYEE_INFO:
                            vars = convert2FormulaVar(DataCollectionEmployee.class, referenceEnum.getValue() + "");
                            break;
                        case SALARY_ACCT_EMPLOYEE:
                            vars = convert2FormulaVar(SalaryAcctEmployeePO.class, referenceEnum.getValue() + "");
                            break;
                        case SALARY_CYCLE:
                            vars = convert2FormulaVar(SalarySobCycleDTO.class, referenceEnum.getValue() + "");
                            break;
                        case SALARY_ITEM:
                            vars = salaryItem2FormulaVar(SalaryFormulaReferenceEnum.SALARY_ITEM, extendParam);
                            break;
                        default:
                            break;
                    }
                    return vars;
                }
            }
        }

        // 如果是其他数据源
        SalaryFormulaReferenceEnum referenceEnum = SalaryFormulaReferenceEnum.parseByValue(sourceId);
        if (referenceEnum != null) {
            switch (referenceEnum) {
                case SALARY_ITEM:
                case ISSUED:
                    vars = salaryItem2FormulaVar(referenceEnum, extendParam);
                    break;
                case SALARY_ARCHIVES:
                    vars = salaryArchives2FormulaVar(referenceEnum, extendParam);
                    break;
                case ADD_UP_SITUATION:
                    vars = convert2FormulaVar(AddUpSituation.class, referenceEnum.getValue() + "");
                    break;
                case ADD_UP_DEDUCTIONS:
                    vars = convert2FormulaVar(AddUpDeduction.class, referenceEnum.getValue() + "");
                    break;
                case EMPLOYEE_INFO:
                    vars = convert2FormulaVar(DataCollectionEmployee.class, referenceEnum.getValue() + "");
                    break;
                case OTHER_DEDUCTION:
                    vars = convert2FormulaVar(OtherDeductionPO.class, referenceEnum.getValue() + "");
                    break;
                case WELFARE:
                    vars = welfare2FormulaVar(referenceEnum);
                    break;
                case ATTEND:
                    vars = attendData2FormulaVar(referenceEnum);
                    break;
                case SALARY_ACCT_EMPLOYEE:
                    vars = convert2FormulaVar(SalaryAcctEmployeePO.class, referenceEnum.getValue() + "");
                    break;
                case SALARY_CYCLE:
                    vars = convert2FormulaVar(SalarySobCycleDTO.class, referenceEnum.getValue() + "");
                    break;
                default:
                    break;
            }
            return vars;
        }
        // 如果是个税税率表的数据源
        List<TaxRateBase> taxRateBatches = getTaxRateBaseService(user).list();
        boolean isTaxRate = taxRateBatches.stream().anyMatch(e -> StringUtils.equals(sourceId, e.getId() + ""));
        if (isTaxRate) {
            vars = convert2FormulaVar(SalaryFormulaTaxRateDTO.class, sourceId);
        }
        return vars;
    }

    @Override
    public List<Map<String, Object>> fieldGroupList(Map<String, Object> extendParam) {

        if (ReferenceTypeEnum.SQL.getValue().equals(extendParam.get("referenceType"))) {
            return Arrays.stream(SalarySQLReferenceEnum.values()).map(e -> {
                Map<String, Object> map = new HashMap<>();
                map.put("key", e.getValue());
                map.put("value", SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()));
                return map;
            }).collect(Collectors.toList());
        }
        // 回算已发
        if (ReferenceTypeEnum.BackCalc.getValue().equals(extendParam.get("referenceType"))) {
            Map<String, Object> map = new HashMap<>();
            map.put("key", SalaryFormulaReferenceEnum.ISSUED.getValue());
            map.put("value", SalaryI18nUtil.getI18nLabel(SalaryFormulaReferenceEnum.ISSUED.getLabelId(), SalaryFormulaReferenceEnum.ISSUED.getDefaultLabel()));
            List<Map<String, Object>> result = new ArrayList<>();
            result.add(map);
            return result;
        }

        return Arrays.stream(SalaryFormulaReferenceEnum.values()).map(e -> {
            Map<String, Object> map = new HashMap<>();
            map.put("key", e.getValue());
            map.put("value", SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()));
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public Map<String, List<FormulaVar>> allFieldList(ReferenceTypeEnum referenceTypeEnum) {

        Map<String, List<FormulaVar>> result = new HashMap<>();

        //sql
        if (ReferenceTypeEnum.SQL.equals(referenceTypeEnum)) {
            result.put(SalarySQLReferenceEnum.EMPLOYEE_INFO.getDefaultLabel(),
                    convert2FormulaVar(DataCollectionEmployee.class, SalarySQLReferenceEnum.EMPLOYEE_INFO.getValue() + ""));
            result.put(SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getDefaultLabel(),
                    convert2FormulaVar(SalaryAcctEmployeePO.class, SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getValue() + ""));
            result.put(SalarySQLReferenceEnum.SALARY_CYCLE.getDefaultLabel(),
                    convert2FormulaVar(SalarySobCycleDTO.class, SalarySQLReferenceEnum.SALARY_CYCLE.getValue() + ""));
            result.put(SalarySQLReferenceEnum.SALARY_ITEM.getDefaultLabel(),
                    salaryItem2FormulaVar(SalaryFormulaReferenceEnum.SALARY_ITEM, null));
           return result;
        }

        // 如果是其他数据源
        if (ReferenceTypeEnum.FORMULA.equals(referenceTypeEnum)) {
            result.put(SalaryFormulaReferenceEnum.SALARY_ITEM.getDefaultLabel(),
                    salaryItem2FormulaVar(SalaryFormulaReferenceEnum.SALARY_ITEM, null));
            result.put(SalaryFormulaReferenceEnum.ISSUED.getDefaultLabel(),
                    salaryItem2FormulaVar(SalaryFormulaReferenceEnum.ISSUED, null));
            result.put(SalaryFormulaReferenceEnum.SALARY_ARCHIVES.getDefaultLabel(),
                    salaryArchives2FormulaVar(SalaryFormulaReferenceEnum.SALARY_ARCHIVES, null));
            result.put(SalaryFormulaReferenceEnum.ADD_UP_SITUATION.getDefaultLabel(),
                    convert2FormulaVar(AddUpSituation.class, SalaryFormulaReferenceEnum.ADD_UP_SITUATION.getValue() + ""));
            result.put(SalaryFormulaReferenceEnum.ADD_UP_DEDUCTIONS.getDefaultLabel(),
                    convert2FormulaVar(AddUpDeduction.class, SalaryFormulaReferenceEnum.ADD_UP_DEDUCTIONS.getValue() + ""));
            result.put(SalaryFormulaReferenceEnum.EMPLOYEE_INFO.getDefaultLabel(),
                    convert2FormulaVar(DataCollectionEmployee.class, SalaryFormulaReferenceEnum.EMPLOYEE_INFO.getValue() + ""));
            result.put(SalaryFormulaReferenceEnum.OTHER_DEDUCTION.getDefaultLabel(),
                    convert2FormulaVar(OtherDeductionPO.class, SalaryFormulaReferenceEnum.OTHER_DEDUCTION.getValue() + ""));
            result.put(SalaryFormulaReferenceEnum.WELFARE.getDefaultLabel(),
                    welfare2FormulaVar(SalaryFormulaReferenceEnum.WELFARE));
            result.put(SalaryFormulaReferenceEnum.ATTEND.getDefaultLabel(),
                    attendData2FormulaVar(SalaryFormulaReferenceEnum.ATTEND));
            result.put(SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getDefaultLabel(),
                    convert2FormulaVar(SalaryAcctEmployeePO.class, SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getValue() + ""));
            result.put(SalarySQLReferenceEnum.SALARY_CYCLE.getDefaultLabel(),
                    convert2FormulaVar(SalarySobCycleDTO.class, SalarySQLReferenceEnum.SALARY_CYCLE.getValue() + ""));
            return result;
        }
        return result;
    }

//    @Override
//    public ExcelPage<FormulaDataSource> dataSourceList(String categoryId, ExcelPage<FormulaDataSource> page, Map<String, Object> extendParam, DataCollectionEmployee employee) {
//        log.info("categoryId: {}, page: {}", categoryId, JsonUtil.toJsonString(page));
//        if (StringUtils.equals("TAX_RATE", categoryId)) {
//            taxRate2FormulaDataSource(page, employee.getTenantKey());
//        }
//        log.info("page: {}", JsonUtil.toJsonString(page));
//        return page;
//    }
//
//    @Override
//    public List<FormulaVar> findProperData(String dataId, String fieldId, String fieldType, Map<String, Object> extendParam, DataCollectionEmployee employee) {
//        return null;
//    }
//
//    @Override
//    public List<DataType> choose(String sourceId, List<FormulaFilterData> filterFormDataList, Map<String, Object> extendParam, DataCollectionEmployee employee) {
//        return null;
//    }
//
////    @Override
//    public List<DataType> vlookups(String sourceId, List<FormulaFilterData> filterFormDataList, List<String> returnFields, Map<String, Object> extendParam,
//                                   DataCollectionEmployee employee) {
//        log.info("sourceId: {}, filterFormDataList: {}, returnFields: {}", sourceId, JsonUtil.toJsonString(filterFormDataList), JsonUtil.toJsonString(returnFields));
//        Map<String, String> columnMap = Maps.newHashMap();
//        for (Field declaredField : SalaryFormulaTaxRateDTO.class.getDeclaredFields()) {
//            if (!declaredField.isAnnotationPresent(SalaryFormulaVar.class)) {
//                continue;
//            }
//            SalaryFormulaVar annotation = declaredField.getAnnotation(SalaryFormulaVar.class);
//            columnMap.put(annotation.fieldId(), declaredField.getName());
//        }
//        List<DataType> resultList = Lists.newArrayList();
//        Long taxRateBatchId = Long.valueOf(sourceId);
//        boolean isOr = filterFormDataList.stream().anyMatch(e -> StringUtils.equals(e.getCondition(), FormulaFilterData.CONDITION_OR));
//        TaxRateDetailPO taxRateRecord = taxRateDetailService.getByFormulaFilterData(taxRateBatchId, isOr, filterFormDataList, employee.getTenantKey());
//        if (taxRateRecord == null) {
//            return Collections.emptyList();
//        }
//        Map<String, String> valueMap = JsonUtil.parseMap(JsonUtil.toJsonString(taxRateRecord), String.class);
//        for (String returnField : returnFields) {
//            DataType dataType = new DataType();
//            dataType.setFieldId(returnField);
//            dataType.setFormId(0L);
//            dataType.setSubFormId(0L);
//            dataType.setName("");
//            dataType.setContent(valueMap.getOrDefault(columnMap.get(returnField), "0"));
//            dataType.setDataType(DataType.NUMBER);
//            dataType.setComponentKey("NumberComponent");
//            dataType.setModule(SalaryFormulaFieldConstant.MODULE);
//            resultList.add(dataType);
//        }
//        log.info("resultList: {}", JsonUtil.toJsonString(resultList));
//        return resultList;
//    }
//
//    @Override
//    public Map<String, SimpleExcelEntity> findSourceName(String Module, List<String> idList, Map<String, Object> extendParam, DataCollectionEmployee employee) {
//        return null;
//    }
//
////    @Override
////    public List<DataType> getFieldData(String dataId, List<String> fieldIds, DataCollectionEmployee employee) {
////        return null;
////    }
//
//    private void taxRate2FormulaDataSource(ExcelPage<FormulaDataSource> resultPage, String tenantKey) {
//        List<TaxRateBasePO> taxRateBatches = taxRateBaseService.list(tenantKey);
//        List<TaxRateBasePO> subList = SalaryPageUtil.subList(resultPage.getPageNo(), resultPage.getPageSize(), taxRateBatches);
//        if (CollectionUtils.isEmpty(subList)) {
//            resultPage.setPageResult(Collections.emptyList());
//            return;
//        }
//        List<FormulaDataSource> formulaDataSources = subList.stream()
//                .map(e -> {
//                    FormulaDataSource formulaDataSource = new FormulaDataSource();
//                    formulaDataSource.setTitle(e.getName());
//                    formulaDataSource.setDataId("" + e.getId());
//                    formulaDataSource.setModule(SalaryFormulaFieldConstant.MODULE);
//                    return formulaDataSource;
//                })
//                .collect(Collectors.toList());
//        resultPage.setCount(taxRateBatches.size());
//        resultPage.setPageResult(formulaDataSources);
//    }

    private List<FormulaVar> salaryItem2FormulaVar(SalaryFormulaReferenceEnum referenceEnum, Map<String, Object> extendParam) {
        Set<Long> salaryItemIds = Collections.emptySet();
        Object salarySobId = extendParam == null ? null : extendParam.get("salarySobId");
        if (Objects.nonNull(salarySobId)) {
            List<SalarySobItemPO> salarySobItems = getSalarySobItemService(user).listBySalarySobId(Long.valueOf(String.valueOf(salarySobId)));
            salaryItemIds = SalaryEntityUtil.properties(salarySobItems, SalarySobItemPO::getSalaryItemId);
        }
        List<SalaryItemPO> salaryItems;
        if (CollectionUtils.isEmpty(salaryItemIds)) {
            salaryItems = getSalaryItemService(user).listAll();
        } else {
            salaryItems = getSalaryItemService(user).listByIds(salaryItemIds);
        }
        Set<Long> taxAgentIds = getTaxAgentService(user).listAllTaxAgents((long) user.getUID())
                .stream().map(TaxAgentPO::getId)
                .collect(Collectors.toSet());
        return salaryItems.stream()
                //薪资项目取消过滤档案，使得导入功能一页面为准
//                .filter(e -> e.getUseInEmployeeSalary() == 0)
                .filter(e -> getSalaryItemService(user).filterInRange(taxAgentIds, e))
                .map(e -> {
                    FormulaVar formulaVar = new FormulaVar();
                    formulaVar.setFieldId(referenceEnum.getValue() + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + e.getCode());
                    formulaVar.setName(e.getName());
                    formulaVar.setSource("" + referenceEnum.getValue());
                    formulaVar.setFieldType(e.getDataType());
                    return formulaVar;
                }).collect(Collectors.toList());

    }


    private List<FormulaVar> salaryArchives2FormulaVar(SalaryFormulaReferenceEnum referenceEnum, Map<String, Object> extendParam) {
        Set<Long> salaryItemIds = Collections.emptySet();
        Object salarySobId = extendParam == null ? null : extendParam.get("salarySobId");
        if (Objects.nonNull(salarySobId)) {
            List<SalarySobItemPO> salarySobItems = getSalarySobItemService(user).listBySalarySobId(Long.valueOf(String.valueOf(salarySobId)));
            salaryItemIds = SalaryEntityUtil.properties(salarySobItems, SalarySobItemPO::getSalaryItemId);
        }
        List<SalaryItemPO> salaryItems;
        if (CollectionUtils.isEmpty(salaryItemIds)) {
            salaryItems = getSalaryItemService(user).listAll();
        } else {
            salaryItems = getSalaryItemService(user).listByIds(salaryItemIds);
        }
        Set<Long> taxAgentIds = getTaxAgentService(user).listAllTaxAgents((long) user.getUID())
                .stream().map(TaxAgentPO::getId).collect(Collectors.toSet());
        return salaryItems.stream()
                .filter(e -> e.getUseInEmployeeSalary() == 1)
                .filter(e-> getSalaryItemService(user).filterInRange(taxAgentIds, e))
                .map(e -> {
                    FormulaVar formulaVar = new FormulaVar();
                    formulaVar.setFieldId(referenceEnum.getValue() + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + e.getCode());
                    formulaVar.setName(e.getName());
                    formulaVar.setSource("" + referenceEnum.getValue());
                    formulaVar.setFieldType(e.getDataType());
                    return formulaVar;
                }).collect(Collectors.toList());
    }

    private <T> List<FormulaVar> convert2FormulaVar(Class<T> clazz, String formId) {
        Field[] declaredFields = clazz.getDeclaredFields();
        List<FormulaVar> formulaVars = Lists.newArrayListWithExpectedSize(declaredFields.length);
        for (Field declaredField : declaredFields) {
            if (!declaredField.isAnnotationPresent(SalaryFormulaVar.class)) {
                continue;
            }
            SalaryFormulaVar annotation = declaredField.getAnnotation(SalaryFormulaVar.class);
            FormulaVar formulaVar = new FormulaVar();
            if (StringUtils.isEmpty(annotation.fieldId())) {
                formulaVar.setFieldId(formId + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + declaredField.getName());
            } else {
                formulaVar.setFieldId(annotation.fieldId());
            }
            formulaVar.setName(SalaryI18nUtil.getI18nLabel(annotation.labelId(), annotation.defaultLabel()));
            formulaVar.setSource(formId);
            formulaVar.setFieldType(annotation.dataType());
//            if (StringUtils.equals(formId, "" + SalaryFormulaReferenceEnum.EMPLOYEE_INFO.getValue())) {
//                formulaVar.setSource(DataType.STRING);
//            }
            formulaVars.add(formulaVar);
        }
        return formulaVars;
    }

    private List<FormulaVar> welfare2FormulaVar(SalaryFormulaReferenceEnum referenceEnum) {
        Map<String, String> welfareColumns = getSIAccountService(user).welfareColumns();
        if (MapUtils.isEmpty(welfareColumns)) {
            return null;
        }
        List<FormulaVar> formulaVars = Lists.newArrayListWithExpectedSize(welfareColumns.size());
        welfareColumns.forEach((k, v) -> {
            FormulaVar formulaVar = new FormulaVar();
            formulaVar.setFieldId(referenceEnum.getValue() + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + v);
            formulaVar.setName(k);
            formulaVar.setSource("" + referenceEnum.getValue());
            formulaVar.setFieldType(DataType.NUMBER);
            formulaVars.add(formulaVar);
        });
        return formulaVars;
    }

    private List<FormulaVar> attendData2FormulaVar(SalaryFormulaReferenceEnum referenceEnum) {
        List<AttendQuoteFieldListDTO> fields = getAttendQuoteFieldMapper().list(AttendQuoteFieldQueryParam.builder().enableStatus(1).build());
        if (CollectionUtils.isEmpty(fields)) {
            return null;
        }
        List<FormulaVar> formulaVars = fields.stream().map(e -> {
            FormulaVar formulaVar = new FormulaVar();
            formulaVar.setFieldId(referenceEnum.getValue() + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + e.getId());
            formulaVar.setName(e.getFieldName());
            formulaVar.setSource("" + referenceEnum.getValue());
            formulaVar.setFieldType(DataType.NUMBER);
            return formulaVar;
        }).collect(Collectors.toList());
        return formulaVars;
    }
}
