package jnpf.attendance.schedule;

import jnpf.model.attendance.vo.scheduling.FixedSchedulingRuleVo;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 固定排班第十步的五个可配置维度，及「尽量」规则下的<strong>放松顺序</strong>。
 * <p>
 * 与 {@link FixedSchedulingRuleVo} 各 {@code *Enabled} / {@code *Value} / {@code *Priority} 字段一一对应。
 * <p>
 * 约束级别：{@code priority=1} 必须（不可放松）；{@code priority=0} 尽量（可按 {@link #relaxOrder()} 逐条放开）。
 */
public enum FixedSoftRuleKind {
    /** 单日工作小时数上限 */
    DAILY_WORK_HOURS,
    /** 连续工作天数上限 */
    CONSECUTIVE_WORK_DAYS,
    /** 每周工作天数上限 */
    WEEKLY_WORK_DAYS,
    /** 每周工作小时数上限 */
    WEEKLY_WORK_HOURS,
    /** 相邻两班之间最小休息间隔（小时） */
    MIN_REST_BETWEEN_SHIFTS;

    /**
     * 产品文档规定的「尽量」放松顺序；{@link FixedSoftConstraintRelaxationPlanner} 与
     * {@link ShiftPlanFinalStaffAssigner} 均按此顺序逐条加入 {@code relaxed} 集合。
     */
    public static List<FixedSoftRuleKind> relaxOrder() {
        return Collections.unmodifiableList(
                Arrays.asList(
                        DAILY_WORK_HOURS,
                        CONSECUTIVE_WORK_DAYS,
                        WEEKLY_WORK_DAYS,
                        WEEKLY_WORK_HOURS,
                        MIN_REST_BETWEEN_SHIFTS));
    }

    /** 该维度在 VO 中是否启用（{@code *Enabled == true}）。 */
    public boolean isEnabled(FixedSchedulingRuleVo vo) {
        if (vo == null) {
            return false;
        }
        switch (this) {
            case DAILY_WORK_HOURS:
                return Boolean.TRUE.equals(vo.getDailyWorkHoursEnabled());
            case CONSECUTIVE_WORK_DAYS:
                return Boolean.TRUE.equals(vo.getConsecutiveWorkDaysEnabled());
            case WEEKLY_WORK_DAYS:
                return Boolean.TRUE.equals(vo.getWeeklyWorkDaysEnabled());
            case WEEKLY_WORK_HOURS:
                return Boolean.TRUE.equals(vo.getWeeklyWorkHoursEnabled());
            case MIN_REST_BETWEEN_SHIFTS:
                return Boolean.TRUE.equals(vo.getMinRestBetweenShiftsEnabled());
            default:
                return false;
        }
    }

    /**
     * 是否为「必须」级别（{@code *Priority == 1}）。
     * <p>
     * 必须项：违反则不可选，且不能通过放松其它尽量项来绕过；若全员违反必须项则本班次不排。
     */
    public boolean isMustPriority(FixedSchedulingRuleVo vo) {
        if (vo == null) {
            return false;
        }
        Byte p = priorityByte(vo);
        return p != null && p.intValue() == 1;
    }

    private Byte priorityByte(FixedSchedulingRuleVo vo) {
        switch (this) {
            case DAILY_WORK_HOURS:
                return vo.getDailyWorkHoursPriority();
            case CONSECUTIVE_WORK_DAYS:
                return vo.getConsecutiveWorkDaysPriority();
            case WEEKLY_WORK_DAYS:
                return vo.getWeeklyWorkDaysPriority();
            case WEEKLY_WORK_HOURS:
                return vo.getWeeklyWorkHoursPriority();
            case MIN_REST_BETWEEN_SHIFTS:
                return vo.getMinRestBetweenShiftsPriority();
            default:
                return null;
        }
    }

    /**
     * 委托 {@link StaffRuleEvaluationPort} 对应方法判断是否违反本维度。
     */
    public boolean violates(String employeeId, StaffAssignmentContext ctx, StaffRuleEvaluationPort port) {
        switch (this) {
            case DAILY_WORK_HOURS:
                return port.violatesDailyWorkHoursLimit(employeeId, ctx);
            case CONSECUTIVE_WORK_DAYS:
                return port.violatesConsecutiveWorkDaysLimit(employeeId, ctx);
            case WEEKLY_WORK_DAYS:
                return port.violatesWeeklyWorkDaysLimit(employeeId, ctx);
            case WEEKLY_WORK_HOURS:
                return port.violatesWeeklyWorkHoursLimit(employeeId, ctx);
            case MIN_REST_BETWEEN_SHIFTS:
                return port.violatesMinRestBetweenShifts(employeeId, ctx);
            default:
                return false;
        }
    }
}
