package jnpf.attendance.excel.listener;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import jnpf.attendance.service.impl.AttendanceDailyRuleServiceImpl;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.entity.attendance.FtbAttendanceLineSchedulingConfig;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.ScheduleImportEnum;
import jnpf.model.attendance.model.ScheduleImportFailModel;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import jnpf.util.attendance.DailyRuleUtil;
import jnpf.util.attendance.RuleExcelImportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

// 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class LineSchedulesDataListener extends AnalysisEventListener<Map<Integer, String>> {

    /**
     * 缓存的数据
     */
    private final List<FtbAttendanceDailyRule> cachedDataList;
    private final List<ScheduleImportFailModel> failList;
    private final FtbAttendanceLineSchedulingConfig lineSchedulingConfig;
    private final Date month;
    private final String groupId;
    private final List<String> heads;

    private final Map<String, PartUserInfoVo> userMap;
    private final Map<String, Integer> selfGroupMap;

    private int headRow = 0;

    public LineSchedulesDataListener(String groupId, List<FtbAttendanceDailyRule> cachedDataList, List<ScheduleImportFailModel> failList, List<String> heads, Date month, Map<String, PartUserInfoVo> userMap, FtbAttendanceLineSchedulingConfig lineSchedulingConfig, Map<String, Integer> selfGroupMap) {
        this.cachedDataList = cachedDataList;
        this.failList = failList;
        this.heads = heads;
        this.month = month;
        this.groupId = groupId;
        this.userMap = userMap;
        this.lineSchedulingConfig = lineSchedulingConfig;
        this.selfGroupMap = selfGroupMap;
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        // 处理表头数据
        // headMap的key是列索引，value是表头名称
        headRow++;
        if (context.readRowHolder().getRowIndex() < 2) {
            return;
        }
        Assert.isFalse(heads.size() != headMap.size() ||
                !CollectionUtils.isEqualCollection(heads, headMap.values()), ScheduleImportEnum.IMPORT_ERROR_FORMAT_WRONG.getMessage());
        Assert.isFalse(Objects.isNull(lineSchedulingConfig), ScheduleImportEnum.IMPORT_ERROR_FORMAT_WRONG.getMessage());
    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        Assert.isFalse(headRow != 3, ScheduleImportEnum.IMPORT_ERROR_FORMAT_WRONG.getMessage());
        // 处理每一行数据
        // data的key是列索引，value是单元格值
        //用户人员信息校验
        String userName = data.get(0);
        String phone = data.get(1);
        //划线排班人员校验
        if (RuleExcelImportUtil.addFail(StringUtil.isEmpty(userName) || StringUtil.isEmpty(phone), ScheduleImportEnum.IMPORT_ERROR_UNIDENTIFIED_MEMBER, userName, failList)) {
            return;
        }
        PartUserInfoVo userEntity = userMap.get(phone);
        if (RuleExcelImportUtil.addFail(Objects.isNull(userEntity), ScheduleImportEnum.IMPORT_ERROR_MEMBER_NOT_IN_GROUP, userName, failList)) {
            return;
        }
        if (RuleExcelImportUtil.addFail(!userEntity.getRealName().equals(userName), ScheduleImportEnum.IMPORT_ERROR_UNIDENTIFIED_MEMBER, userName, failList)) {
            return;
        }
        if (RuleExcelImportUtil.addFail(cachedDataList.stream().anyMatch(vo -> vo.getUserId().equals(userEntity.getUserId())), ScheduleImportEnum.IMPORT_ERROR_DUPLICATE_MEMBERS, userEntity.getRealName(), failList)) {
            return;
        }
        Integer selfGroup = selfGroupMap.get(userEntity.getUserId());
        if (RuleExcelImportUtil.addFail(Objects.isNull(selfGroup), ScheduleImportEnum.IMPORT_ERROR_MEMBER_NOT_IN_GROUP, userName, failList)) {
            return;
        }
        DateTime today = DateUtil.beginOfDay(new Date());
        //班次信息校验
        List<FtbAttendanceDailyRule> cachedDayDataList = CollUtil.newArrayList();
        data.forEach((index, periodSrt) -> {
            if (index < 2 || heads.size() < index - 1) {
                return;
            }
            String head = heads.get(index);
            String dayIndex = head.split("\n")[1];
            DateTime day = DateUtil.offsetDay(month, Integer.parseInt(dayIndex) - 1);
            if (day.isBefore(today)) {
                return;
            }
            Date startTime = DateDetail.getDateByPoint(day, lineSchedulingConfig.getStartTime(), lineSchedulingConfig.getStartType());
            Date endTime = DateUtil.offsetHour(DateDetail.getDateByPoint(day, lineSchedulingConfig.getEndTime(), lineSchedulingConfig.getEndType()), 1);
            if (StringUtil.isEmpty(periodSrt)) {
                FtbAttendanceDailyRule ftbAttendanceDailyRule = AttendanceDailyRuleServiceImpl.buildLineSchedulesRule(groupId, selfGroup, day, day, day, userEntity.getUserId(), lineSchedulingConfig);
                ftbAttendanceDailyRule.setAttendanceType(AttendanceTypeEnum.CLEAR.getCode());
                cachedDataList.add(ftbAttendanceDailyRule);
                return;
            }
            cachedDayDataList.clear();
            String[] periodArr = periodSrt.split("\\|");
            for (String period : periodArr) {
                if (StringUtil.isEmpty(period)) {
                    continue;
                }
                String[] dateArr = period.trim().split("-");
                try {
                    Date start = DateDetail.getDateByPoint(day, dateArr[0], 1);
                    Date end = DateDetail.getDateByPoint(day, dateArr[1], 1);
                    if (start.after(end)) {
                        end = DateUtil.offsetDay(end, 1);
                    }
                    Date ceilStart = new Date(start.getTime());
                    DailyRuleUtil.ceilToHalfHour(start);
                    Date ceilEnd = new Date(end.getTime());
                    DailyRuleUtil.ceilToHalfHour(end);
                    if (ceilStart.compareTo(start) != 0 || ceilEnd.compareTo(end) != 0) {
                        RuleExcelImportUtil.addFail(true, ScheduleImportEnum.IMPORT_ERROR_PERIOD_INVALID, userEntity.getRealName(), failList);
                        return;
                    }
                    if (start.before(startTime) || end.after(endTime)) {
                        RuleExcelImportUtil.addFail(true, ScheduleImportEnum.IMPORT_ERROR_OVERDUE_TIME_INVALID, userEntity.getRealName(), failList);
                        return;
                    }
                    cachedDayDataList.add(AttendanceDailyRuleServiceImpl.buildLineSchedulesRule(groupId, selfGroup, day, start, end, userEntity.getUserId(), lineSchedulingConfig));
                } catch (Exception e) {
                    RuleExcelImportUtil.addFail(true, ScheduleImportEnum.IMPORT_ERROR_PERIOD_INVALID, userEntity.getRealName(), failList);
                    return;
                }
            }
            cachedDataList.addAll(DailyRuleUtil.mergeRules(cachedDayDataList));
        });
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 所有数据解析完成后的操作
        log.error("所有数据解析完成");
    }


}