package com.engine.salary.wrapper;

import com.cloudstore.eccom.pc.table.WeaTableColumn;
import com.cloudstore.eccom.result.WeaResultMsg;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.component.SalaryWeaTable;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.salaryarchive.bo.SalaryArchiveBO;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveBaseInfoFormDTO;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveFormDTO;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveListDTO;
import com.engine.salary.entity.salaryarchive.param.*;
import com.engine.salary.entity.salaryarchive.po.SalaryArchiveDimissionPO;
import com.engine.salary.entity.salaryarchive.po.SalaryArchiveItemPO;
import com.engine.salary.entity.salaryarchive.po.SalaryArchivePO;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.taxagent.dto.TaxAgentListDTO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.salaryarchive.*;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.process.salaryArchive.SalaryArchiveProcessQueryParam;
import com.engine.salary.service.*;
import com.engine.salary.service.impl.*;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.page.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
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 SalaryArchiveWrapper extends Service {

    private SalaryArchiveService getSalaryArchiveService(User user) {
        return ServiceUtil.getService(SalaryArchiveServiceImpl.class, user);
    }

    private SalaryArchiveItemService getSalaryArchiveItemService(User user) {
        return ServiceUtil.getService(SalaryArchiveItemServiceImpl.class, user);
    }


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

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

    private SalaryArchiveExcelService getSalaryArchiveExcelService(User user) {
        return ServiceUtil.getService(SalaryArchiveExcelServiceImpl.class, user);
    }

    private SalaryEmployeeService getSalaryEmployeeService(User user) {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }


    /**
     * 薪资档案列表（分页）
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> list(SalaryArchiveQueryParam queryParam) {
        //薪资档案列表
        PageInfo<SalaryArchiveListDTO> pageInfo = getSalaryArchiveService(user).listPage(queryParam);
        Collection<SalaryArchiveListDTO> salaryArchives = pageInfo.getList();

        //所有个税扣缴义务人
        Collection<TaxAgentPO> taxAgentLists = getTaxAgentService(user).listAll();

        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = getSalaryArchiveItemService(user).getCanAdjustSalaryItems();

        //整合所有的显示列（固定列+薪资项目动态列）
        List<Map<String, Object>> listMaps = getSalaryArchiveService(user).buildSalaryArchiveData(salaryArchives, taxAgentLists, salaryItems, Boolean.TRUE);

        PageInfo<Map<String, Object>> pageInfos = new PageInfo<Map<String, Object>>(listMaps);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(pageInfo.getPageNum());
        pageInfos.setPageSize(pageInfo.getPageSize());


        //动态列组装
        List<WeaTableColumn> columns = SalaryArchiveBO.buildSalaryArchiveTable(salaryItems);

        SalaryWeaTable<SalaryArchiveListDTO> table = new SalaryWeaTable<SalaryArchiveListDTO>(user, SalaryArchiveListDTO.class);
        table.setColumns(columns);


        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();


        Map<String, Object> datas = new HashMap<>();
        datas.put("pageInfo", pageInfos);
        datas.put("dataKey", result.getResultMap());
        datas.put("salaryArchives", salaryArchives);
        return datas;
    }


    /**
     * 薪资档案列表（分页）
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> list(SalaryArchiveQueryParam queryParam, SalaryArchiveListTypeEnum listTypeEnum) {
        //薪资档案列表
        PageInfo<SalaryArchiveListDTO> pageInfo = getSalaryArchiveService(user).listPage(queryParam);
        Collection<SalaryArchiveListDTO> salaryArchives = pageInfo.getList();

        //所有个税扣缴义务人
        Collection<TaxAgentPO> taxAgentLists = getTaxAgentService(user).listAll();

        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = getSalaryArchiveItemService(user).getCanAdjustSalaryItems();

        Set<Long> userTaxAgentIds = getTaxAgentService(user).listAllTaxAgents((long) user.getUID())
                .stream().map(TaxAgentPO::getId).collect(Collectors.toSet());
        salaryItems = salaryItems.stream()
                .filter(po -> getSalaryItemService(user).filterInRange(userTaxAgentIds, po))
                .collect(Collectors.toList());

        //整合所有的显示列（固定列+薪资项目动态列）
        List<Map<String, Object>> listMaps = getSalaryArchiveService(user).buildSalaryArchiveData(salaryArchives, taxAgentLists, salaryItems, Boolean.TRUE);

        PageInfo<Map<String, Object>> pageInfos = new PageInfo<Map<String, Object>>(listMaps);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(pageInfo.getPageNum());
        pageInfos.setPageSize(pageInfo.getPageSize());


        //动态列组装
        List<WeaTableColumn> columns = SalaryArchiveBO.buildSalaryArchiveTable(salaryItems);

        SalaryWeaTable<SalaryArchiveListDTO> table = new SalaryWeaTable<SalaryArchiveListDTO>(user, SalaryArchiveListDTO.class);
        table.setColumns(columns);


        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();


        Map<String, Object> datas = new HashMap<>();
        datas.put("pageInfo", pageInfos);
        datas.put("dataKey", result.getResultMap());
        datas.put("salaryArchives", salaryArchives);
        datas.put("listType", listTypeEnum.getValue());

        //记录操作日志
        LoggerContext loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetName(listTypeEnum.getDefaultLabel());
        loggerContext.setOperateType(OperateTypeEnum.READ.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "查看薪资档案列表"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "查看薪资档案列表"));
        SalaryElogConfig.salaryArchiveLoggerTemplate.write(loggerContext);
        return datas;
    }


    /**
     * 获取各tab总人数
     *
     * @return
     */
    public Map<String, Long> queryTabTotal() {
        return getSalaryArchiveService(user).queryTabTotal();
    }

    /**
     * 待定薪列表
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> listPage(SalaryArchiveQueryParam queryParam) {
        Map<String, Object> list = list(queryParam);
        return list;
    }


    /**
     * 待定薪列表
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> pendingList(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.PENDING.getValue()));
        return list(queryParam, SalaryArchiveListTypeEnum.PENDING);
    }

    /**
     * 删除待定薪待办
     *
     * @param ids
     * @return
     */
    public String deletePendingTodo(Collection<Long> ids) {
        return getSalaryArchiveService(user).deletePendingTodo(ids);
    }

    /**
     * 定薪列表
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> fixedList(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.FIXED.getValue(), SalaryArchiveStatusEnum.SUSPEND.getValue()));
        return list(queryParam, SalaryArchiveListTypeEnum.FIXED);
    }

    /**
     * 待停薪列表
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> suspendList(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.SUSPEND.getValue()));
        return list(queryParam, SalaryArchiveListTypeEnum.SUSPEND);
    }

    /**
     * 停薪列表
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> stopList(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.STOP_FROM_PENDING.getValue(), SalaryArchiveStatusEnum.STOP_FROM_SUSPEND.getValue()));
        return list(queryParam, SalaryArchiveListTypeEnum.STOP);
    }

    /**
     * 设为定薪员工
     *
     * @param ids
     * @return
     */
    public Map<String, Object> gotoFixed(Collection<Long> ids) {
        return getSalaryArchiveService(user).gotoFixed(ids);
    }

    /**
     * 一键全部定薪
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> allGotoFixed(SalaryArchiveQueryParam queryParam) {
        return getSalaryArchiveService(user).allGotoFixed(queryParam);
    }


    /**
     * 停薪
     *
     * @param ids
     * @return
     */
    public Map<String, Object> gotoStop(Collection<Long> ids) {
        return getSalaryArchiveService(user).gotoStop(ids);
    }

    /**
     * 一键全部停薪
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> allGotoStop(SalaryArchiveQueryParam queryParam) {
        return getSalaryArchiveService(user).allGotoStop(queryParam);
    }

    /**
     * 删除待停薪待办
     *
     * @param ids
     * @return
     */
    public String deleteSuspendTodo(Collection<Long> ids) {
        return getSalaryArchiveService(user).deleteSuspendTodo(ids);
    }

    /**
     * 取消停薪
     *
     * @param ids
     * @return
     */
    public String cancelStop(Collection<Long> ids) {
        return getSalaryArchiveService(user).cancelStop(ids);
    }


    /**
     * 外部人员
     *
     * @param queryParam
     * @return
     */
    public Map<String, Object> extList(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.FIXED.getValue()));
        queryParam.setExtSalaryArchiveList(true);
        return list(queryParam, SalaryArchiveListTypeEnum.EXT);
    }


    /**
     * 获取薪资档案详情表单
     *
     * @param salaryArchiveId
     * @return
     */
    public SalaryArchiveFormDTO getFrom(Long salaryArchiveId) {
        if (salaryArchiveId == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100425, "薪资档案id不能为空"));
        }
        SalaryArchivePO po = getSalaryArchiveService(user).getById(salaryArchiveId);
        if (po == null) {
            throw new SalaryRunTimeException(String.format(SalaryI18nUtil.getI18nLabel(100463, "薪资档案不存在") + "[id:%s]", salaryArchiveId));
        }

        List<DataCollectionEmployee> employeeList = getSalaryEmployeeService(user).getEmployeeByIdsAll(Collections.singletonList(po.getEmployeeId()));
        if (CollectionUtils.isEmpty(employeeList)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100465, "薪资档案员工信息不存在"));
        }

        Long taxAgentId = po.getTaxAgentId();
        TaxAgentPO taxAgent = getTaxAgentService(user).getById(taxAgentId);

        // 1.基本信息表单
        Map<String, Object> baseInfo = new HashMap<>();
        DataCollectionEmployee employee = employeeList.get(0);
        SalaryArchiveBaseInfoFormDTO build = SalaryArchiveBaseInfoFormDTO.builder()
                .username(employee.getUsername())
                .department(employee.getDepartmentName())
                .position(employee.getJobtitleName() == null ? "" : employee.getJobtitleName())
                .hiredate(employee.getCompanystartdate())
                .mobile(employee.getMobile())
                .taxAgent(taxAgent.getName())
                .build();
        baseInfo.put("employee", build);

        List<Map<String, Object>> salaryItems = Lists.newArrayList();

        // 2.发薪设置表单
        Map<String, Object> paySetForm = new HashMap<>();
        paySetForm.put("data", po);


        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItemList = getSalaryArchiveItemService(user).getCanAdjustSalaryItems()
                .stream().filter(item -> getSalaryItemService(user).filterInRange(Collections.singleton(taxAgentId), item))
                .collect(Collectors.toList());
        Collection<Long> salaryItemIds = salaryItemList.stream().map(SalaryItemPO::getId).collect(Collectors.toList());
        List<SalaryArchiveItemPO> salaryArchiveItemList = getSalaryArchiveService(user).getCurrentEffectiveItemList(Collections.singletonList(salaryArchiveId), salaryItemIds);
        salaryItemList.forEach(s -> {
            Optional<SalaryArchiveItemPO> optionalItem = salaryArchiveItemList.stream().filter(f -> f.getSalaryItemId().equals(s.getId())).findFirst();
            Map<String, Object> salaryItemMap = new LinkedHashMap<>();
            salaryItemMap.put("id", s.getId());
            salaryItemMap.put("name", s.getName());
            salaryItemMap.put("value", optionalItem.isPresent() ? optionalItem.get().getItemValue() : "");
            salaryItemMap.put("dataType", s.getDataType());
            salaryItemMap.put("pattern", s.getPattern());
            salaryItems.add(salaryItemMap);
        });

        return SalaryArchiveFormDTO.builder()
                .id(salaryArchiveId)
                .employeeId(employee.getEmployeeId())
                .baseInfo(baseInfo)
                .paySet(paySetForm)
                .adjustSalaryItems(salaryItems)
                .build();
    }


    /**
     * 保存发薪设置
     *
     * @param saveParam
     * @return
     */
    public String savePaySet(SalaryArchiveSetPaySaveParam saveParam) {
        return getSalaryArchiveService(user).savePaySet(saveParam);
    }

    /**
     * 获取离职时段设置表单
     *
     * @return
     */
    public Map<String, Object> getDimissionSetForm() {
        List<SalaryArchiveDimissionPO> dimissionSets = getSalaryArchiveService(user).dimissionSets();
        Map<String, Object> data = new LinkedHashMap<>();
        if (CollectionUtils.isNotEmpty(dimissionSets)) {
            data.put("dimissionTimeInterval", dimissionSets.get(0).getDimissionTimeInterval());
        }
        return data;
    }

    /**
     * 保存离职时段设置
     *
     * @param saveParam
     * @return
     */
    public String saveDimissionSet(SalaryArchiveDimissionSaveParam saveParam) {
        return getSalaryArchiveService(user).saveDimissionSet(saveParam);
    }

    public List<Map<String, Object>> getImportTypes() {
        List<Map<String, Object>> importTypes = Arrays.stream(SalaryArchiveImportTypeEnum.values()).map(m -> {
            Map<String, Object> map = new HashMap<>(2);
            map.put("id", String.valueOf(m.getValue()));
            map.put("content", SalaryI18nUtil.getI18nLabel(m.getLabelId(), m.getDefaultLabel()));
            return map;
        }).collect(Collectors.toList());
        return importTypes;
    }


    /**
     * 下载导入模板
     *
     * @param queryParam
     * @return
     */
    public XSSFWorkbook downloadTemplate(SalaryArchiveQueryParam queryParam) {
        if (!queryParam.isExtSalaryArchiveList()) {
            if (queryParam.getListType() == null) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109712, "列表类型必传"));
            } else {
                // 定薪列表导入有调薪导入和初始化导入
                if (queryParam.getListType().equals(SalaryArchiveListTypeEnum.FIXED)) {
                    Optional<SalaryArchiveImportTypeEnum> optional = Arrays.stream(SalaryArchiveImportTypeEnum.values())
                            .filter(e -> StringUtils.isNotEmpty(queryParam.getImportType()) && e.getValue().equals(queryParam.getImportType())).findFirst();
                    if (!optional.isPresent()) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100593, "导入类型不正确"));
                    }
                }
            }
        }
        return getSalaryArchiveExcelService(user).downloadTemplate(queryParam);
    }

    /**
     * 预览
     *
     * @param param
     * @return
     */
    public Map<String, Object> preview(SalaryArchiveImportHandleParam param) {
        return getSalaryArchiveService(user).preview(param);
    }

    /**
     * 导入档案
     *
     * @param param
     * @return
     */
    public Map<String, Object> importSalaryArchive(SalaryArchiveImportHandleParam param) {
        return getSalaryArchiveExcelService(user).batchImportEbatch(param);
    }

    /**
     * 导出列表
     *
     * @param queryParam
     * @return
     */
    public XSSFWorkbook exportList(SalaryArchiveQueryParam queryParam) {
        return getSalaryArchiveService(user).exportList(queryParam);
    }


    /**
     * 检查导入文件
     *
     * @param param
     * @return
     */
    public Map<String, Object> checkImportSalaryArchiveParam(SalaryArchiveImportHandleParam param) {
        param.setOnlyCheck(true);
        return getSalaryArchiveExcelService(user).batchImportEbatch(param);
    }

    /**
     * 人员状态列表
     *
     * @return
     */
    public Map<String, Object> searchCondition() {
        List<Map<String, String>> userStatus = UserStatusEnum.getList();
        List<Map<String, String>> itemAdjustReasons = SalaryArchiveItemAdjustReasonEnum.getList();
        List<Map<String, String>> TaxAgentAdjustReason = SalaryArchiveTaxAgentAdjustReasonEnum.getList();
        Collection<TaxAgentListDTO> taxAgentList = getTaxAgentService(user).findAll();
        HashMap map = Maps.newHashMap();
        map.put("userStatus", userStatus);
        map.put("itemAdjustReasons", itemAdjustReasons);
        map.put("TaxAgentAdjustReason", TaxAgentAdjustReason);
        map.put("taxAgentList", taxAgentList);
        return map;
    }

    public Map<String, Object> selectSalaryArchiveColumns(String importType) {
        return getSalaryArchiveService(user).selectSalaryArchiveColumns(SalaryArchiveImportTypeEnum.parseByValue(importType));
    }


    public Map<String, Object> checkSalaryArchiveInit(SalaryArchiveImportActionParam importData) {
        importData.setImportType("init");
        importData.setListType("FIXED");
        importData.setAddData(false);
        return getSalaryArchiveExcelService(user).processInit(importData);
    }

    public Map<String, Object> importSalaryArchiveInit(SalaryArchiveImportActionParam importData) {
        importData.setImportType("init");
        importData.setListType("FIXED");
        importData.setAddData(true);
        return getSalaryArchiveExcelService(user).processInit(importData);
    }

    public Map<String, Object> checkAdjustmentSalaryArchive(SalaryArchiveImportActionParam importData) {
        importData.setImportType("salaryItemAdjust");
        importData.setListType("FIXED");
        importData.setAddData(false);
        return getSalaryArchiveExcelService(user).processInit(importData);
    }

    public Map<String, Object> adjustmentSalaryArchive(SalaryArchiveImportActionParam importData) {
        importData.setImportType("salaryItemAdjust");
        importData.setListType("FIXED");
        importData.setAddData(true);
        return getSalaryArchiveExcelService(user).processInit(importData);
    }

    /**
     * 停薪
     *
     * @param stopSalaryParam
     * @return
     */
    public void stopSalary(SalaryArchiveStopParam stopSalaryParam) {
        getSalaryArchiveService(user).stopSalary(stopSalaryParam);
    }


    public Map<String, Object> handleRepeatData() {
        return getSalaryArchiveService(user).handleRepeatData();
    }

    @Deprecated
    public SalaryArchivePO getSalaryArchiveInfo(SalaryArchiveProcessQueryParam param) {
        if (param.getEmployeeId() == null) {
            throw new SalaryRunTimeException("人员id为空!");
        }
        SalaryArchivePO po = SalaryArchivePO.builder().employeeId(param.getEmployeeId()).build();
        if (param.getTaxAgentId() != null) {
            po.setTaxAgentId(param.getTaxAgentId());
        }
        if (CollectionUtils.isNotEmpty(param.getRunStatusList())) {
            po.setRunStatusList(param.getRunStatusList());
        }

        List<SalaryArchivePO> list = getSalaryArchiveService(user).listSome(po);
        if (CollectionUtils.isEmpty(list)) {
            throw new SalaryRunTimeException("薪资档案不存在!");
        }
        if (list.size() > 1) {
            throw new SalaryRunTimeException("存在多个薪资档案!");
        }
        return list.get(0);
    }

    public List<SalaryArchiveFormDTO> getSalaryArchiveInfoV2(SalaryArchiveProcessQueryParam param) {
        if (param.getEmployeeId() == null) {
            throw new SalaryRunTimeException("人员id为空!");
        }
        SalaryArchivePO po = SalaryArchivePO.builder().employeeId(param.getEmployeeId()).build();
        if (param.getTaxAgentId() != null) {
            po.setTaxAgentId(param.getTaxAgentId());
        }
        if (CollectionUtils.isNotEmpty(param.getRunStatusList())) {
            po.setRunStatusList(param.getRunStatusList());
        }

        List<SalaryArchivePO> list = getSalaryArchiveService(user).listSome(po);
        if (CollectionUtils.isEmpty(list)) {
            throw new SalaryRunTimeException("薪资档案不存在!");
        }

        return list.stream().map(a -> getFrom(a.getId())).collect(Collectors.toList());
    }


    /**
     * 删除薪资档案
     *
     * @param salaryArchiveIds
     */
    public void deleteSalaryArchive(Collection<Long> salaryArchiveIds) {
        getSalaryArchiveService(user).deleteSalaryArchive(salaryArchiveIds);
    }

    /**
     * 同步所有档案起始发薪日期变为入职日期
     *
     * @return
     */
    public String syncPayStartDate() {
        return getSalaryArchiveService(user).syncPayStartDate();
    }
}
