package jnpf.attendance.service.filter.impl;

import jnpf.attendance.service.OvertimeRuleService;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.attendance.OvertimeRuleDetailVo;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import jnpf.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 加班过滤器
 *
 * @author yanwenfu
 * @create 2025-09-25
 */
@Component
public class OvertimeFilter implements RuleFilter {

    @Resource
    private OvertimeRuleService overtimeRuleService;

    @Override
    public RuleFilterResult keepRule(FtbAttendanceDailyRule rule, RuleFilterContext context, UserInfo userInfo) {

        if (rule.getAttendanceType().equals(AttendanceTypeEnum.WORKOVERTIME.getCode())) {
            if (StringUtils.isEmpty(rule.getPeriodInfo())) {
                return RuleFilterResult.discard();
            }
            OvertimeRuleDetailVo ruleDetail;
            try {
                ruleDetail = JsonUtil.getJsonToBean(rule.getPeriodInfo(), OvertimeRuleDetailVo.class);
                if (null == ruleDetail) {
                    throw new Exception("加班规则异常");
                }
            } catch (Exception e) {
                return RuleFilterResult.discard();
            }
            // 查询加班规则
            rule.setOvertimeRuleDetail(ruleDetail);
            // 出勤规则是加班
            if (DateDetail.checkSameDay(context.getCurDate(), rule.getInPoint())) {
                // 今天的加班
                if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
                    addMapValue(rule, context);
                }
                return RuleFilterResult.keep();
            }
            // 昨天的加班 查询下一个班次
            FtbAttendanceDailyRule nextRule = null;
            if (rule.getRn() - 1 > 0) {
                nextRule = context.getRuleList().get(rule.getRn() - 2);
            }
            if (null == nextRule || DateDetail.checkSameDay(context.getCurDate(), nextRule.getInPoint())) {
                addMapValue(rule, context);
                return RuleFilterResult.keep();
            }
        } else {
            OvertimeRuleDetailVo vo = generateOvertimeRuleDetail(context, rule, userInfo);
            if (null == vo) {
                return RuleFilterResult.discard();
            }
            // 昨天 或 今天
            if (DateDetail.checkSameDay(context.getCurDate(), rule.getDay())) {
                // 今天
                if (StringUtils.isNotEmpty(vo.getId()) && vo.getCalcMethod().equals(3)) {
                    if (AttendanceTypeEnum.ORDINARY.getCode().equals(rule.getAttendanceType())) {
                        if (!DateDetail.checkSameDay(rule.getInPoint(), context.getCurDate())) {
                            return RuleFilterResult.discard();
                        }
                    }
                    rule.setOvertimeRuleDetail(vo);
                    rule.setOvertime(ConstantUtil.NUM_TRUE);
                    return RuleFilterResult.keep();
                }
            } else {
                if (!rule.getAttendanceType().equals(AttendanceTypeEnum.ORDINARY.getCode())) {
                    return RuleFilterResult.discard();
                }
                // 昨天 出勤规则不是加班 判定是不是昨天最后一个班次
                FtbAttendanceDailyRule lastRule = context.getYesterdayLastRule();
                if (null != lastRule && rule.getId().equals(lastRule.getId())) {
                    if (vo.getCalcMethod().equals(3)) {
                        rule.setOvertimeRuleDetail(vo);
                        rule.setOvertime(ConstantUtil.NUM_TRUE);
                        return RuleFilterResult.keep();
                    }
                }
            }
        }
        return RuleFilterResult.discard();
    }

    private OvertimeRuleDetailVo generateOvertimeRuleDetail(RuleFilterContext context, FtbAttendanceDailyRule rule, UserInfo userInfo) {

        OvertimeRuleVo vo = context.getOvertimeRule();
        if (null == vo && context.getHasRuleQuery().equals(ConstantUtil.NUM_TRUE)) {
            // 是否已经查询过用户加班规则
            return null;
        }
        if (null == context.getOvertimeMap()) {
            return null;
        }
        FtbAttendanceDailyRule nextRule = null;
        if (rule.getRn() - 1 > 0) {
            nextRule = context.getRuleList().get(rule.getRn() - 2);
        }
        Integer attendanceType = getAttendanceType(rule, nextRule);
        if (null == vo) {
            // 查询用户加班配置
            OvertimeRuleVo overtimeRule = context.getOvertimeMap().get(userInfo.getUserId());
            context.setOvertimeRule(overtimeRule);
            context.setHasRuleQuery(ConstantUtil.NUM_TRUE);
            return null == overtimeRule ? null : overtimeRuleService.getEffectWorkDetail(context.getOvertimeRule(), rule.getDay(), attendanceType);
        }
        return overtimeRuleService.getEffectWorkDetail(context.getOvertimeRule(), rule.getDay(), attendanceType);
    }

    private Integer getAttendanceType(FtbAttendanceDailyRule rule, FtbAttendanceDailyRule nextRule) {
        Integer attendanceType;
        if (rule.getAttendanceType().equals(AttendanceTypeEnum.DEFAULT.getCode())) {
            return AttendanceTypeEnum.ORDINARY.getCode();
        }
        if (null == nextRule) {
            attendanceType = rule.getAttendanceType();
        } else {
            // rule 和 nextRule 中有一个休 则出勤类型为休, 否则为工作日
            if (rule.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode()) || nextRule.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode())) {
                attendanceType = AttendanceTypeEnum.REST.getCode();
            } else {
                attendanceType = AttendanceTypeEnum.ORDINARY.getCode();
            }
        }
        return attendanceType;
    }

    private void addMapValue(FtbAttendanceDailyRule rule, RuleFilterContext context) {
        // 加班上班有连续
        if (rule.getRn() + 1 < context.getRuleList().size()) {
            FtbAttendanceDailyRule dailyRule = context.getRuleList().get(rule.getRn());
            if (dailyRule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
                context.getMap().put(rule.getId(), dailyRule);
            }
        }
        // 加班下班有连续
        if (rule.getRn() - 1 > 0) {
            FtbAttendanceDailyRule dailyRule = context.getRuleList().get(rule.getRn() - 2);
            if (dailyRule.getInUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
                context.getMap().put(rule.getId(), dailyRule);
            }
        }
    }

    @Override
    public int getOrder() {
        return 2;
    }
}
