package com.engine.salary.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSONObject;
import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.cloudstore.eccom.pc.table.WeaTable;
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.biz.AttendQuoteBiz;
import com.engine.salary.biz.AttendQuoteDataBiz;
import com.engine.salary.biz.AttendQuoteDataValueBiz;
import com.engine.salary.biz.AttendQuoteFieldBiz;
import com.engine.salary.common.LocalDateRange;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.datacollection.bo.AttendQuoteDataBO;
import com.engine.salary.entity.datacollection.dto.*;
import com.engine.salary.entity.datacollection.param.*;
import com.engine.salary.entity.datacollection.po.AttendQuoteDataPO;
import com.engine.salary.entity.datacollection.po.AttendQuoteDataValuePO;
import com.engine.salary.entity.datacollection.po.AttendQuoteFieldPO;
import com.engine.salary.entity.datacollection.po.AttendQuotePO;
import com.engine.salary.entity.salarysob.bo.SalarySobRangeBO;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.param.SalarySobRangeEmpQueryParam;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.entity.salarysob.po.SalarySobRangePO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.datacollection.AttendQuoteSourceTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.datacollection.AttendQuoteDataMapper;
import com.engine.salary.mapper.salarysob.SalarySobMapper;
import com.engine.salary.mapper.salarysob.SalarySobRangeMapper;
import com.engine.salary.mapper.sys.SalarySysConfMapper;
import com.engine.salary.remote.attend.entity.Attend4Salary;
import com.engine.salary.remote.attend.service.RemoteAttend4SalaryService;
import com.engine.salary.remote.attend.service.impl.RemoteAttend4SalaryServiceImpl;
import com.engine.salary.service.*;
import com.engine.salary.sys.entity.po.SalarySysConfPO;
import com.engine.salary.sys.entity.vo.OrderRuleVO;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.excel.ExcelParseHelper;
import com.engine.salary.util.excel.ExcelSupport;
import com.engine.salary.util.excel.ExcelUtil;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.ValidUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.file.ImageFileManager;
import weaver.general.BaseBean;
import weaver.hrm.User;
import weaver.wechat.util.Utils;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Collectors;

import static com.engine.salary.util.excel.ExcelSupport.EXCEL_TYPE_XLSX;

/**
 * 数据采集-考勤引用数据
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@Slf4j
public class AttendQuoteDataServiceImpl extends Service implements AttendQuoteDataService {
    private final Boolean isLog = "true".equals(new BaseBean().getPropValue("hrmSalary", "log"));

    private AttendQuoteBiz quoteBiz = new AttendQuoteBiz();
    private AttendQuoteDataBiz dataBiz = new AttendQuoteDataBiz();
    private AttendQuoteDataValueBiz dataValueBiz = new AttendQuoteDataValueBiz();
    private AttendQuoteFieldBiz fieldBiz = new AttendQuoteFieldBiz();

    private AttendQuoteFieldSettingService getFieldSettingService(User user) {
        return ServiceUtil.getService(AttendQuoteFieldSettingServiceImpl.class, user);
    }

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

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

    private AttendQuoteService getAttendQuoteService(User user) {
        return ServiceUtil.getService(AttendQuoteServiceImpl.class, user);
    }

    private AttendQuoteDataMapper getAttendQuoteDataMapper() {
        return MapperProxyFactory.getProxy(AttendQuoteDataMapper.class);
    }

    private SalarySobMapper getSalarySobMapper() {
        return MapperProxyFactory.getProxy(SalarySobMapper.class);
    }

    private SalarySobRangeMapper getSalarySobRangeMapper() {
        return MapperProxyFactory.getProxy(SalarySobRangeMapper.class);
    }


    private RemoteAttend4SalaryService getRemoteAttend4SalaryService(User user) {
        return ServiceUtil.getService(RemoteAttend4SalaryServiceImpl.class, user);
    }

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

    private SalarySysConfMapper getSalarySysConfMapper() {
        return SqlProxyHandle.getProxy(SalarySysConfMapper.class);
    }

    @Override
    public PageInfo<AttendQuoteDataBaseDTO> listPage(AttendQuoteDataQueryParam queryParam) {
        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);

        List<AttendQuoteDataBaseDTO> list = getAttendQuoteDataMapper().list(queryParam);
        PageInfo<AttendQuoteDataBaseDTO> page = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), list, AttendQuoteDataBaseDTO.class);
        return page;
    }

    /**
     * 获取所有考勤字段
     *
     * @return
     */
    private List<AttendQuoteFieldPO> getAllAttendQuoteFields() {
        return fieldBiz.listSome(AttendQuoteFieldPO.builder().build());
    }

    /**
     * 获取考勤数据结果
     *
     * @param attendQuoteDataBases
     * @return
     */
    public List<Map<String, Object>> getListMaps(List<AttendQuoteDataBaseDTO> attendQuoteDataBases) {
        if (CollectionUtils.isEmpty(attendQuoteDataBases)) {
            return new ArrayList<>();
        }

        // 考核数据值
        List<AttendQuoteDataValuePO> attendQuoteDataValues = dataValueBiz.listSome(AttendQuoteDataValuePO.builder().attendQuoteId(attendQuoteDataBases.get(0).getAttendQuoteId()).build());

        return attendQuoteDataBases.stream().map(m -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", m.getId());
            map.put("username", m.getUsername());
            map.put("departmentName", m.getDepartmentName());
            map.put("mobile", m.getMobile());
            map.put("jobNum", m.getJobNum());
            // 考勤数据
            attendQuoteDataValues.stream().filter(a -> a.getAttendQuoteDataId().equals(m.getId())).collect(Collectors.toList()).forEach(e -> {
                map.put(e.getAttendQuoteFieldId() + "_attendQuoteData", e.getDataValue());
            });
            return map;
        }).collect(Collectors.toList());
    }


    @Override
    public List<AttendQuoteDataDTO> getAttendQuoteData(YearMonth salaryYearMonth, Long salarySobId, List<Long> employeeIds) {
        if (salaryYearMonth == null || salarySobId == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100358, "参数有误：薪资所属月、薪资账套id"));
        }
        List<AttendQuoteDataDTO> list = new ArrayList<>();
        Date salaryYearMonthDay = SalaryDateUtil.localDateToDate(salaryYearMonth.atDay(1));
        //查询引用主表
        List<AttendQuotePO> attendQuotes = quoteBiz.listSome(AttendQuotePO.builder().salaryYearMonth(salaryYearMonthDay).salarySobId(salarySobId).build());

        if (CollectionUtils.isEmpty(attendQuotes)) {
            return Collections.emptyList();
        }
        AttendQuotePO attendQuote = attendQuotes.get(0);

        //查询考勤数据值
        List<AttendQuoteDataValuePO> attendQuoteDataValues = dataValueBiz.listSome(AttendQuoteDataValuePO.builder().attendQuoteId(attendQuote.getId()).employeeIds(employeeIds).build());


        if (CollectionUtils.isEmpty(employeeIds)) {
            employeeIds = attendQuoteDataValues.stream().map(AttendQuoteDataValuePO::getEmployeeId)
                    .distinct().collect(Collectors.toList());
        }

        employeeIds.forEach(e -> {
            AttendQuoteDataDTO attendQuoteData = new AttendQuoteDataDTO();
            attendQuoteData.setEmployeeId(e);
            List<AttendQuoteDataValueDTO> dataValues = attendQuoteDataValues.stream().filter(v -> v.getEmployeeId().equals(e)).map(m ->
                    AttendQuoteDataValueDTO.builder()
                            .attendQuoteFieldId(m.getAttendQuoteFieldId())
                            .dataValue(m.getDataValue())
                            .build()).collect(Collectors.toList());
            attendQuoteData.setDataValues(dataValues);
            list.add(attendQuoteData);
        });
        return list;
    }

    @Override
    public XSSFWorkbook export(AttendQuoteDataQueryParam queryParam) {
        if (queryParam.getAttendQuoteId() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100253, "考勤引用id不能为空"));
        }

        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);

        // 考勤数据分页主数据
        List<AttendQuoteDataBaseDTO> attendQuoteDataBases = dataBiz.list(queryParam);
        // 所有考勤字段
        List<AttendQuoteFieldPO> attendQuoteFields = getAllAttendQuoteFields();
        // 获取最终结果
        List<Map<String, Object>> listMaps = getListMaps(attendQuoteDataBases);

        // 1.工作簿名称
        String sheetName = SalaryI18nUtil.getI18nLabel(93931, "考勤数据");
        List<Object> header = new ArrayList<>();
        header.add(SalaryI18nUtil.getI18nLabel(85429, "姓名"));
        header.add(SalaryI18nUtil.getI18nLabel(86185, "部门"));
        header.add(SalaryI18nUtil.getI18nLabel(86186, "手机号"));
        header.add(SalaryI18nUtil.getI18nLabel(86317, "工号"));
        // 动态列
        if (CollectionUtils.isNotEmpty(listMaps)) {
            for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
                header.add(attendQuoteField.getFieldName());
            }
        }

        List<List<Object>> rows = new ArrayList<>();
        // 2.表头
        rows.add(header);
        // 3.表数据
        for (Map<String, Object> dto : listMaps) {
            List<Object> row = new ArrayList<>();
            row.add(dto.get("username"));
            row.add(dto.get("departmentName"));
            row.add(dto.get("mobile"));
            row.add(dto.get("jobNum"));

            // 动态列
            for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
                row.add(dto.get(attendQuoteField.getId().toString() + "_attendQuoteData"));
            }
            rows.add(row);
        }

        // 记录日志
        AttendQuotePO attendQuotePO = getAttendQuoteService(user).getById(queryParam.getAttendQuoteId());
        SalarySobPO salarySob = getSalarySobService(user).getById(attendQuotePO.getSalarySobId());

        LoggerContext loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(attendQuotePO.getId()));
        loggerContext.setTargetName(SalaryDateUtil.getFormatYearMonth(attendQuotePO.getSalaryYearMonth()) + " " + (salarySob != null ? salarySob.getName() : ""));
        loggerContext.setOperateType(OperateTypeEnum.EXCEL_EXPORT.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "导出考勤数据"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "考勤数据"));
        SalaryElogConfig.attendQuoteLoggerTemplate.write(loggerContext);

        return ExcelUtil.genWorkbookV2(rows, sheetName);

    }


    /**
     * 获取表头设置字段
     *
     * @param sourceType
     * @return
     */
    private List<AttendQuoteFieldPO> getAttendQuoteSetFields(AttendQuoteSourceTypeEnum sourceType) {
        List<AttendQuoteFieldPO> allAttendQuoteFields = getAllAttendQuoteFields();
        List<AttendQuoteFieldSettingListDTO> attendQuoteFieldSettingList = getFieldSettingService(user).listNoSync(AttendQuoteFieldSettingQueryParam.builder().sourceType(sourceType).isViewChecked(Boolean.TRUE).build());
        List<AttendQuoteFieldPO> attendQuoteFields = new ArrayList<>();
        attendQuoteFieldSettingList.forEach(s -> {
            List<AttendQuoteFieldSettingFieldListDTO> items = s.getItems();
            if (CollectionUtils.isNotEmpty(items)) {
                items.forEach(i -> {
                    Optional<AttendQuoteFieldPO> optional = allAttendQuoteFields.stream().filter(f -> f.getId().equals(i.getId())).findFirst();
                    optional.ifPresent(attendQuoteFields::add);
                });
            }
        });
        return attendQuoteFields;
    }

    @Override
    public String syncAttendQuoteData(AttendQuoteDataSyncParam syncParam) {
        AttendQuoteDataSyncParam.checkParam(syncParam);

        String salaryYearMonth = syncParam.getSalaryYearMonth();
        int year = Integer.parseInt(salaryYearMonth.split("-")[0]);
        int month = Integer.parseInt(salaryYearMonth.split("-")[1]);
        if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100365, "薪资所属月格式有误，正确格式示例为'2021-01'"));
        }
        // 1.获取已设置的可同步的考勤字段
        List<AttendQuoteFieldPO> attendQuoteFields = getAttendQuoteSetFields(AttendQuoteSourceTypeEnum.QUOTE);
        if (CollectionUtils.isEmpty(attendQuoteFields)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100366, "请先设置同步字段"));
        }
        // 获取薪资账套
        SalarySobCycleDTO salarySobCycle = getSalarySobService(user).getSalarySobCycle(syncParam.getSalarySobId(), YearMonth.of(year, month));
        // 2.薪资账套人员
        List<Long> employeeIds = new ArrayList<>();
        // 获取薪资账套人员
        List<SalarySobRangePO> salarySobRanges = getSalarySobRangeMapper().listSome(SalarySobRangePO.builder().includeType(1).salarySobId(salarySobCycle.getSalarySobId()).build());
        List<SalarySobRangeEmpQueryParam> salarySobRangeEmpQueryParams = SalarySobRangeBO.convert2EmployeeQueryParam(salarySobRanges);
        List<List<SalarySobRangeEmpQueryParam>> partition = Lists.partition(salarySobRangeEmpQueryParams, 100);
        List<Long> employeeSalarySobIds = new ArrayList<>();
        partition.forEach(l -> employeeSalarySobIds.addAll(getSalarySobRangeMapper().listEmployeeIds(l)));

        if (CollectionUtils.isEmpty(employeeSalarySobIds) || CollectionUtils.isEmpty(salarySobRangeEmpQueryParams)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100367, "薪资账套还没有人员"));
        }
        // 账套外人员
        List<Long> employeeOtherIds = (List<Long>) syncParam.getEmployeeIds();
        employeeIds.addAll(employeeSalarySobIds);
        employeeIds.addAll(CollectionUtils.emptyIfNull(employeeOtherIds));

        // 4.获取考勤模块数据
        List<Map<String, Object>> attendQuoteSyncData = getAttendQuoteDataFromRemoteAttend(salarySobCycle.getAttendCycle(), employeeIds, attendQuoteFields);
        List<AttendQuoteDataPO> pos = new ArrayList<>();
        List<AttendQuoteDataValuePO> values = new ArrayList<>();
        // 5.考勤引用数据处理
        Date now = new Date();
        if (CollectionUtils.isNotEmpty(attendQuoteSyncData)) {

            // 3.生成考勤引用
            AttendQuotePO attendQuote = getAttendQuote(AttendQuoteSourceTypeEnum.QUOTE, syncParam.getSalarySobId(), year, month, syncParam.getDescription());

            for (Long employeeId : employeeIds) {
                AttendQuoteDataPO po = new AttendQuoteDataPO();
                po.setId(IdGenerator.generate());
                po.setCreateTime(now);
                po.setUpdateTime(now);
                po.setCreator((long) user.getUID());
                po.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
                // 考勤引用表的主键id
                po.setAttendQuoteId(attendQuote.getId());
                po.setEmployeeId(employeeId);
                pos.add(po);
                for (Map<String, Object> attendQuoteData : attendQuoteSyncData) {
                    if (!Objects.isNull(attendQuoteData.get("employeeId")) &&
                            !Objects.isNull(employeeId) &&
                            !Objects.isNull(attendQuoteData.get("attendQuoteFieldId")) &&
                            attendQuoteData.get("employeeId").toString().equals(employeeId.toString())) {
                        values.add(AttendQuoteDataValuePO.builder()
                                .createTime(now)
                                .updateTime(now)
                                .creator((long) user.getUID())
                                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                                .employeeId(employeeId)
                                .attendQuoteId(attendQuote.getId())
                                .attendQuoteDataId(po.getId())
                                .attendQuoteFieldId(Long.valueOf(attendQuoteData.get("attendQuoteFieldId").toString()))
                                .dataValue(Utils.null2String(attendQuoteData.get("dataValue")))
                                .build());
                    }
                }
            }

            // 6.数据落库处理
            handleDataToDB(attendQuote.getId(), pos, values);
            // 记录日志
            recordLog(attendQuote);
        } else {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100368, "暂无考勤数据可以同步"));
        }
        return null;
    }

    private void recordLog(AttendQuotePO attendQuote) {
        SalarySobPO salarySob = getSalarySobService(user).getById(attendQuote.getSalarySobId());
        String sourceType = AttendQuoteSourceTypeEnum.getDefaultLabelByValue(attendQuote.getSourceType());

        LoggerContext loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(attendQuote.getId()));
        loggerContext.setTargetName(SalaryDateUtil.getFormatYearMonth(attendQuote.getSalaryYearMonth()) + " " + (salarySob != null ? salarySob.getName() : ""));
        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
        loggerContext.setOperateTypeName(sourceType + SalaryI18nUtil.getI18nLabel(0, "考勤数据"));
        loggerContext.setOperatedesc(sourceType + SalaryI18nUtil.getI18nLabel(0, "考勤数据"));
        loggerContext.setNewValues(attendQuote);
        SalaryElogConfig.attendQuoteLoggerTemplate.write(loggerContext);
    }


    /**
     * 获取考勤引用
     *
     * @param salarySobId
     * @param year
     * @param month
     * @return
     */
    private AttendQuotePO getAttendQuote(AttendQuoteSourceTypeEnum sourceType, Long salarySobId, int year, int month, String description) {
        SalarySobCycleDTO salarySobCycle = getSalarySobService(user).getSalarySobCycle(salarySobId, YearMonth.of(year, month));

        Date salaryYearMonthDayDate = SalaryDateUtil.localDateToDate(YearMonth.of(year, month).atDay(1));
        List<AttendQuotePO> attendQuotes = quoteBiz.listSome(AttendQuotePO.builder().salarySobId(salarySobId).salaryYearMonth(salaryYearMonthDayDate).build());
        // 考勤引用
        AttendQuotePO attendQuote = new AttendQuotePO();
        if (CollectionUtils.isNotEmpty(attendQuotes)) {
            attendQuote = attendQuotes.get(0);
        }
        attendQuote.setSalarySobId(salarySobCycle.getSalarySobId());
        LocalDateRange salaryCycleRange = salarySobCycle.getSalaryCycle();
        LocalDateRange attendCycleRange = salarySobCycle.getAttendCycle();
        // 考勤周期
        attendQuote.setAttendCycle(SalaryDateUtil.getFormatLocalDate(attendCycleRange.getFromDate()) + " ~ " + SalaryDateUtil.getFormatLocalDate(attendCycleRange.getEndDate()));
        // 薪资周期
        attendQuote.setSalaryCycle(SalaryDateUtil.getFormatLocalDate(salaryCycleRange.getFromDate()) + " ~ " + SalaryDateUtil.getFormatLocalDate(salaryCycleRange.getEndDate()));
        attendQuote.setSalaryYearMonth(salaryYearMonthDayDate);
        // 来源：导入
        attendQuote.setSourceType(sourceType.getValue());
        attendQuote.setDescription(description);
        Date now = new Date();
        attendQuote.setCreateTime(now);
        attendQuote.setUpdateTime(now);
        attendQuote.setCreator((long) user.getUID());
        attendQuote.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        // 新增或修改考勤引用
        if (attendQuote.getId() != null) {
            quoteBiz.updateById(attendQuote);
        } else {
            attendQuote.setId(IdGenerator.generate());
            quoteBiz.insert(attendQuote);
        }
        return attendQuote;
    }

    /**
     * 获取考勤模块数据
     *
     * @param attendCycleRange
     * @param employeeIds
     * @param attendQuoteFields
     * @return
     */
    private List<Map<String, Object>> getAttendQuoteDataFromRemoteAttend(LocalDateRange attendCycleRange, List<Long> employeeIds, List<AttendQuoteFieldPO> attendQuoteFields) {
        List<Map<String, Object>> attendQuoteSyncData = new ArrayList<>();
        Attend4Salary attend4Salary = new Attend4Salary();
        try {
            int partSize = 500;
            List<List<Long>> partition = Lists.partition(employeeIds, partSize);
            for (List<Long> part : partition) {
                attend4Salary.setBeginDate(attendCycleRange.getFromDate());
                attend4Salary.setEndDate(attendCycleRange.getEndDate());
                attend4Salary.setOnlyEmpIds(part);
                List<Map<String, String>> attendResult = getRemoteAttend4SalaryService(user).getDatas(attend4Salary);

                AttendQuoteDataBO.buildAttendDataFromRemote(attendResult, attendQuoteFields, attendQuoteSyncData);
//                attend4Salary.setUnit("day");
//                attendResult = remoteAttend4SalaryService.getWorkTimeSummary(attend4Salary);
//                log.info("考勤数据[按天]:{}", JSONUtils.toJSONString(attendResult.getData()));
//                AttendQuoteDataBO.buildAttendDataFromRemote("day", attendResult.getData(), attendQuoteFields, attendQuoteSyncData);
            }
        } catch (Exception e) {
            log.error("salaryAttend获取考勤数据错误失败:{}", String.format("参数:%s,错误信息:%s", JSONObject.toJSONString(attend4Salary), e.getMessage()), e);
            return attendQuoteSyncData;
        }
        if (isLog) {
            log.info("salaryAttend同步的考勤数据:{}", JSONUtils.toJSONString(attendQuoteSyncData));
        }
        return attendQuoteSyncData;
    }

    /**
     * 引用同步或导入落库处理
     *
     * @param attendQuoteId
     * @param pos
     * @param values
     */
    private void handleDataToDB(Long attendQuoteId, List<AttendQuoteDataPO> pos, List<AttendQuoteDataValuePO> values) {
        // 数据落库处理
        if (CollectionUtils.isEmpty(pos)) {
            return;
        }
        // 多条相同人的则以第一条为准，如果逆序排列（用于重复的则以最后一条为准）Collections.reverse(pos);
        pos = pos.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getEmployeeId()))), ArrayList::new));
        // 删除考勤数据
        ArrayList<Long> quoteIds = new ArrayList<>();
        quoteIds.add(attendQuoteId);
        dataBiz.deleteByAttendQuoteIds(quoteIds);
        // 新增考勤数据
        dataBiz.insertData(pos);
        // 删除考勤值数据
//        dataValueBiz.deleteByAttendQuoteDataIds(pos.stream().map(AttendQuoteDataPO::getId).collect(Collectors.toList()));
        dataValueBiz.deleteByAttendQuoteIds(quoteIds);
        // 新增考勤值数据
        if (CollectionUtils.isNotEmpty(values)) {
            //去除空值
            values = values.stream().filter(po -> StringUtils.isNotBlank(po.getDataValue())).collect(Collectors.toList());
            dataValueBiz.insertData(values);
        }
    }

    @Override
    public XSSFWorkbook downloadTemplate(AttendQuoteDataExportTemplateParam exportParam) {
        try {
            // 考勤主数据
            Date salaryYearMonth = SalaryDateUtil.localDateToDate(exportParam.getSalaryYearMonth().atDay(1));
            List<AttendQuotePO> attendQuotePOS = quoteBiz.listSome(AttendQuotePO.builder()
                    .salarySobId(exportParam.getSalarySobId())
                    .salaryYearMonth(salaryYearMonth)
                    .ids(exportParam.getIds()).build());
            AttendQuotePO po = CollectionUtils.isNotEmpty(attendQuotePOS) ? attendQuotePOS.get(0) : null;
            AttendQuoteDataQueryParam queryParam = AttendQuoteDataQueryParam.builder().attendQuoteId(po == null ? 0L : po.getId()).build();
            List<AttendQuoteDataBaseDTO> attendQuoteDataBases = dataBiz.list(queryParam);

            // 获取已设置的可同步的字段
            List<AttendQuoteFieldPO> attendQuoteFields = getAttendQuoteSetFields(AttendQuoteSourceTypeEnum.IMPORT);
            // 获取最终结果
            List<Map<String, Object>> listMaps = getListMaps(attendQuoteDataBases);

            // 1.工作簿名称
            String sheetName = SalaryI18nUtil.getI18nLabel(101606, "考勤引用导入模板");
            List<Object> header = new ArrayList<>();
            header.add(SalaryI18nUtil.getI18nLabel(85429, "姓名"));
            header.add(SalaryI18nUtil.getI18nLabel(86185, "部门"));
            header.add(SalaryI18nUtil.getI18nLabel(86186, "手机号"));
            header.add(SalaryI18nUtil.getI18nLabel(86317, "工号"));
            // 动态列
            for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
                header.add(attendQuoteField.getFieldName());
            }
            List<List<Object>> rows = new ArrayList<>();
            rows.add(header);
            for (Map<String, Object> dto : listMaps) {
                List<Object> row = new ArrayList<>();
                row.add(dto.get("username"));
                row.add(dto.get("departmentName"));
                row.add(dto.get("mobile"));
                row.add(dto.get("jobNum"));

//                // 动态列
//                Map<String, Object> map = listMaps.get(0);
//                for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
//                    row.add(map.containsKey(attendQuoteField.getId() + "_attendQuoteData") ? dto.get(attendQuoteField.getId() + "_attendQuoteData") : "");
//                }
                rows.add(row);
            }

            return ExcelUtil.genWorkbookV2(rows, sheetName);
        } catch (Exception e) {
            log.error("salaryAttend下载模板失败", e);
        }
        return null;
    }

    /**
     * 导入的数据插入到数据库中
     */
    public Map<String, Object> preview(AttendQuoteDataImportParam param) {
        ValidUtil.doValidator(param);
        Long salarySobId = param.getSalarySobId();
        SalarySobPO salarySobPO = getSalarySobService(user).getById(salarySobId);
        if (salarySobPO == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100537, "薪资账套不存在"));
        }
        String salaryYearMonth = param.getSalaryYearMonth();
        if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100365, "薪资所属月格式有误，正确格式示例为'2021-01'"));
        }

        InputStream fileInputStream = null;
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
            Map<String, Object> apidatas = new HashMap<String, Object>();
            apidatas.put("headers", ExcelSupport.getSheetHeader(sheet, 0));
            apidatas.put("list", ExcelParseHelper.parse2List(sheet, 1));
            return apidatas;
        } finally {
            IOUtils.closeQuietly(fileInputStream);
        }

    }

    /**
     * 导入的数据插入到数据库中
     */
    public Map<String, Object> importAttendQuoteData(AttendQuoteDataImportParam param) {
        ValidUtil.doValidator(param);
        Long salarySobId = param.getSalarySobId();
        SalarySobPO salarySobPO = getSalarySobService(user).getById(salarySobId);
        if (salarySobPO == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100537, "薪资账套不存在"));
        }
        String salaryYearMonth = param.getSalaryYearMonth();
        if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100365, "薪资所属月格式有误，正确格式示例为'2021-01'"));
        }
        int year = Integer.parseInt(salaryYearMonth.split("-")[0]);
        int month = Integer.parseInt(salaryYearMonth.split("-")[1]);

        //查询对于人员信息导入筛选的全局配置
        SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode");
        String confValue = (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0";

        // 获取租户下所有的人员
        List<DataCollectionEmployee> employees = getSalaryEmployeeService(user).listEmployee();
        // 获取已设置的可同步的考勤字段
        List<AttendQuoteFieldPO> attendQuoteFields = getAttendQuoteSetFields(AttendQuoteSourceTypeEnum.IMPORT);
        // 生成获取考勤引用
        AttendQuotePO attendQuote = getAttendQuote(AttendQuoteSourceTypeEnum.IMPORT, salarySobId, year, month, StringUtils.EMPTY);

        int total = 0;

        int index = 0;
        int successCount = 0;
        int errorCount = 0;

        // 待导入数据
        List<AttendQuoteDataPO> pos = new ArrayList<>();
        List<AttendQuoteDataValuePO> values = new ArrayList<>();
        String valI18n = SalaryI18nUtil.getI18nLabel(100581, "请输入数字");

        InputStream fileInputStream = null;
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
            // 表头
            List<String> headers = ExcelSupport.getSheetHeader(sheet, 0);

            // 错误sheet数据
            List<Map<String, Object>> errorData = new ArrayList<>();
            // 错误提示
            List<Map<String, String>> excelComments = new ArrayList<>();

            //验证字段是否缺失
            String isValidHeader = checkHeaders(headers, attendQuoteFields);
            if (StringUtils.isNotBlank(isValidHeader)) {
                Map<String, Object> apidatas = new HashMap<String, Object>();
                apidatas.put("successCount", successCount);
                apidatas.put("errorCount", errorCount);

                Map<String, String> errorMessageMap = Maps.newHashMap();
                errorMessageMap.put("message", isValidHeader);
                excelComments.add(errorMessageMap);
                apidatas.put("errorData", excelComments);
                return apidatas;
            }


            // 处理数值
            List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 1);
            total = data.size();

            Map<String, Object> map;
            Date now = new Date();

            AttendQuoteDataPO po;
            for (int i = 0; i < data.size(); i++) {
                index += 1;
                String rowIndex = "第" + index + "行";
                map = data.get(i);

                po = new AttendQuoteDataPO();
                po.setId(IdGenerator.generate());
                po.setCreateTime(now);
                po.setUpdateTime(now);
                po.setCreator((long) user.getUID());
                po.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
                // 考勤引用表的主键id
                po.setAttendQuoteId(attendQuote.getId());

                int errorSum = 0;

                String userName = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(85429, "姓名"))).orElse("").toString();
                String deparmentName = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86185, "部门"))).orElse("").toString();
                String mobile = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86186, "手机号"))).orElse("").toString();
                String workcode = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86317, "工号"))).orElse("").toString();
                String idNo = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86317, "证件号码"))).orElse("").toString();
                List<Long> employeeSameIds = new ArrayList<>();

                //筛选导入人员信息可以在人力资源池中匹配到的人员信息
                List<DataCollectionEmployee> emps = getSalaryEmployeeService(user).matchImportEmployee(confValue, employees, userName, deparmentName, mobile, workcode, idNo, null);
                //含在职和离职，选在职数据
                if (CollectionUtils.isNotEmpty(emps) && emps.size() > 1) {
                    employeeSameIds = emps.stream()
                            .filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus()))
                            .map(DataCollectionEmployee::getEmployeeId)
                            .collect(Collectors.toList());
                }
                if (CollectionUtils.isNotEmpty(emps) && emps.size() == 1) {
                    employeeSameIds = emps.stream()
                            .map(DataCollectionEmployee::getEmployeeId)
                            .collect(Collectors.toList());
                }


                for (int j = 0; j < headers.size(); j++) {
                    String key = headers.get(j);
                    if (key == null) {
                        continue;
                    }
                    String cellVal = Optional.ofNullable(map.get(key.toString())).orElse("").toString();
                    if (SalaryI18nUtil.getI18nLabel(85429, "姓名").equals(key.toString())) {
                        //当人员信息导入筛选的全局配置为"0"时，姓名才是必填项
                        if (StringUtils.isEmpty(cellVal) && "0".equals(confValue)) {
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", rowIndex + SalaryI18nUtil.getI18nLabel(100579, "姓名不能为空"));
                            excelComments.add(errorMessageMap);
                            errorSum += 1;
                        } else if (CollectionUtils.isEmpty(employeeSameIds) || employeeSameIds.size() > 1) {
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", rowIndex + SalaryI18nUtil.getI18nLabel(100579, "员工信息不存在或者存在多个员工"));
                            excelComments.add(errorMessageMap);
                            errorSum += 1;
                        } else {
                            Long employeeId = CollectionUtils.isNotEmpty(employeeSameIds) && employeeSameIds.size() == 1 ? employeeSameIds.get(0) : null;
                            if (employeeId != null && employeeId > 0) {
                                po.setEmployeeId(employeeId);
                            } else {
                                Map<String, String> errorMessageMap = Maps.newHashMap();
                                errorMessageMap.put("message", rowIndex + SalaryI18nUtil.getI18nLabel(100579, "姓名错误，系统内不存在该姓名"));
                                excelComments.add(errorMessageMap);
                                errorSum += 1;
                            }
                        }
                    }
                    if (po.getEmployeeId() != null) {
                        String bigDecimalValue;
                        for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
                            if (attendQuoteField.getFieldName().equals(key)) {
                                if (1 == attendQuoteField.getFieldType()) {
                                    bigDecimalValue = bigDecimalVal(cellVal, excelComments, valI18n, errorCount + 1, j);
                                    errorSum += StringUtils.isEmpty(bigDecimalValue) ? 1 : 0;
                                    if (StringUtils.isNotEmpty(bigDecimalValue)) {
                                        values.add(AttendQuoteDataValuePO.builder()
                                                .createTime(now)
                                                .updateTime(now)
                                                .creator((long) user.getUID())
                                                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                                                .employeeId(po.getEmployeeId())
                                                .attendQuoteId(attendQuote.getId())
                                                .attendQuoteDataId(po.getId())
                                                .attendQuoteFieldId(attendQuoteField.getId())
                                                .dataValue(Utils.null2String(bigDecimalValue))
                                                .build());
                                    }
                                } else {
                                    values.add(AttendQuoteDataValuePO.builder()
                                            .createTime(now)
                                            .updateTime(now)
                                            .creator((long) user.getUID())
                                            .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                                            .employeeId(po.getEmployeeId())
                                            .attendQuoteId(attendQuote.getId())
                                            .attendQuoteDataId(po.getId())
                                            .attendQuoteFieldId(attendQuoteField.getId())
                                            .dataValue(Utils.null2String(cellVal))
                                            .build());
                                }
                            }
                        }
                    }
                }

                if (errorSum > 0) {
                    errorCount += 1;
                    // 添加错误数据
                    errorData.add(map);
                } else {
                    successCount += 1;
                    // 成功一条就添加一条记录
                    pos.add(po);
                }
                // 导入进度
//            salaryBatchService.sendImportRate(message.getBizId(), total, index);
            }

            // 数据入库处理
            handleDataToDB(attendQuote.getId(), pos, values);


            // 记录日志
            recordLog(attendQuote);

            Map<String, Object> apidatas = new HashMap<String, Object>();
            apidatas.put("successCount", successCount);
            apidatas.put("errorCount", errorCount);
            apidatas.put("errorData", excelComments);
            return apidatas;
        } finally {
            IOUtils.closeQuietly(fileInputStream);
        }

    }

    /**
     * @return null
     * @description 编辑数据
     * @author Harryxzy
     * @date 2022/10/28 14:40
     */
    @Override
    public void editData(AttendQuoteDataEditParam attendQuoteDataEditParam) {
        Map<String, String> attendQuoteData = attendQuoteDataEditParam.getAttendQuoteData();
        AttendQuoteDataBiz dataBiz = new AttendQuoteDataBiz();
        AttendQuoteDataValueBiz attendQuoteDataValueBiz = new AttendQuoteDataValueBiz();
        ArrayList<Long> ids = new ArrayList<>();
        ids.add(attendQuoteDataEditParam.getId());
        AttendQuoteDataQueryParam build = AttendQuoteDataQueryParam.builder().ids(ids).build();
        List<AttendQuoteDataBaseDTO> list = dataBiz.list(build);
        if (list == null || list.size() == 0) {
            throw new SalaryRunTimeException("该数据不存在！");
        }
        Map<String, String> attendQuoteFieldData = new HashMap<>();
        for (Map.Entry<String, String> entrySet : attendQuoteData.entrySet()) {
            String[] s = entrySet.getKey().split("_");
            attendQuoteFieldData.put(s[0], entrySet.getValue());
        }
        for (Map.Entry<String, String> entrySet : attendQuoteFieldData.entrySet()) {
            AttendQuoteDataValuePO updatePO = AttendQuoteDataValuePO.builder().employeeId(list.get(0).getEmployeeId()).attendQuoteFieldId(SalaryEntityUtil.string2Long(entrySet.getKey())).dataValue(entrySet.getValue()).build();
            attendQuoteDataValueBiz.updateDataValue(updatePO);
        }
    }

    /**
     * @return void
     * @description 获取数据
     * @author Harryxzy
     * @date 2022/10/31 14:12
     */
    @Override
    public Map<String, Object> getData(AttendQuoteDataEditParam attendQuoteDataEditParam) {
        ArrayList<Long> ids = new ArrayList<>();
        ids.add(attendQuoteDataEditParam.getId());
        AttendQuoteDataQueryParam build = AttendQuoteDataQueryParam.builder().ids(ids).build();
        List<AttendQuoteDataBaseDTO> list = dataBiz.list(build);
        if (list == null || list.size() == 0) {
            throw new SalaryRunTimeException("该数据不存在！");
        }
        // 所有考勤字段
        List<AttendQuoteFieldPO> attendQuoteFields = getAllAttendQuoteFields();
        // 获取最终结果
        List<Map<String, Object>> listMaps = getListMaps(list);
        List<WeaTableColumn> columns = new ArrayList<>();
        columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(85429, "姓名"), "username"));
        columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(86185, "部门"), "departmentName"));
        columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(86186, "手机号"), "mobile"));
        columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(86317, "工号"), "jobNum"));

        // 动态列
        if (CollectionUtils.isNotEmpty(listMaps)) {
            Map<String, Object> map = listMaps.stream().max(Comparator.comparingInt(m -> m.keySet().size())).get();
            for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
                if (map.containsKey(attendQuoteField.getId() + "_attendQuoteData")) {
                    columns.add(new WeaTableColumn("150", attendQuoteField.getFieldName(), attendQuoteField.getId() + "_attendQuoteData"));
                }
            }
        }
        WeaTable weaTable = new WeaTable();
        weaTable.setColumns(columns);
        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(weaTable.makeDataResult());
        result.success();
        Map<String, Object> datas = new HashMap<>();
        datas.put("data", listMaps.get(0));
        datas.put("dataKey", result.getResultMap());
        return datas;
    }

    /**
     * 获取金额数字值
     *
     * @param bigDecimalValStr
     * @param excelComments
     * @param i
     * @param j
     * @return
     */
    private String bigDecimalVal(String bigDecimalValStr, List<Map<String, String>> excelComments, String valI18n, int i, int j) {
        if (StringUtils.isBlank(bigDecimalValStr)) {
            return BigDecimal.ZERO.toString();
        }
        BigDecimal bigDecimalVal = null;
        try {
            bigDecimalVal = new BigDecimal(bigDecimalValStr);
        } catch (Exception e) {
            Map<String, String> errorMessageMap = Maps.newHashMap();
            errorMessageMap.put("message", valI18n);
            excelComments.add(errorMessageMap);
//            salaryBatchService.createExcelComment(excelComments, valI18n, i, i, j, j);
        }
        return bigDecimalVal == null ? "" : bigDecimalVal.toString();
    }


    /**
     * 检查参数
     *
     * @param message
     * @param params
     * @return
     */
//    private boolean checkParams(BatchDocumentMessage message, Map<String, Object> params) {
//        boolean isValid = true;
//        String errorMsg = "";
//        if (params == null) {
//            errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100582, "参数必传");
//        } else {
//            if (!params.containsKey("salaryYearMonth")
//                    || !params.containsKey("salarySobId")
//                    || params.get("salaryYearMonth") == null
//                    || params.get("salarySobId") == null) {
//                errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100588, "薪资所属月和薪资账套必传");
//            } else {
//                String salaryYearMonth = params.get("salaryYearMonth").toString();
//                if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
//                    errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100365, "薪资所属月格式有误，正确格式示例为'2021-01'");
//                } else {
//                    List<SalarySobPO> salarySobs = new LambdaQueryChainWrapper<>(getSalarySobMapper())
//                            .eq(SalarySobPO::getTenantKey, message.getTenantKey())
//                            .eq(SalarySobPO::getDeleteType, 0)
//                            .eq(SalarySobPO::getId, Long.valueOf(params.get("salarySobId").toString()))
//                            .list();
//                    if (CollectionUtils.isEmpty(salarySobs)) {
//                        errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100537, "薪资账套不存在");
//                    }
//                }
//            }
//        }
//        // 有错误信息发送
//        if (StringUtils.isNotEmpty(errorMsg)) {
//            // 发送导入回调信息
//            salaryBatchService.sendImportCallBackInfo(message, errorMsg);
//            isValid = false;
//        }
//        return isValid;
//    }

    /**
     * 检查列头
     *
     * @return
     */
    private String checkHeaders(List<String> headerList, List<AttendQuoteFieldPO> attendQuoteFields) {
        boolean isValid = true;
        String userNameI18n = SalaryI18nUtil.getI18nLabel(85429, "姓名");

        List<String> mustHeaders = attendQuoteFields.stream().map(AttendQuoteFieldPO::getFieldName).collect(Collectors.toList());
        mustHeaders.add(userNameI18n);

        // 缺少的必须列
        List<String> lackHeaders = mustHeaders.stream().filter(item -> !headerList.contains(item)).collect(Collectors.toList());

        String errorMsg = "";
        String checkHeaderI18n = SalaryI18nUtil.getI18nLabel(101850, "缺少如下列，请检查：");
        if (CollectionUtils.isEmpty(attendQuoteFields)) {
            errorMsg = SalaryI18nUtil.getI18nLabel(101849, "考勤字段列缺失，请补充");
        } else if (CollectionUtils.isNotEmpty(lackHeaders)) {
            errorMsg = checkHeaderI18n + Joiner.on(",").join((Iterable<?>) lackHeaders);
        }

        return errorMsg;
    }
}
