package com.boman.web.core.utils;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

import static com.boman.common.core.utils.DateUtils.*;
import static com.boman.common.core.utils.obj.ObjectUtils.isEmpty;
import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
import static com.boman.domain.constant.AttendanceRulesConst.*;

/**
 * @author shiqian
 * @date 2021年08月05日 13:50
 **/
public class LeaveFromUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(LeaveFromUtils.class);


    /**
     * 功能描述:
     *
     * @param startTime    请假开始时间
     * @param endTime      请假结束时间
     * @param yearMonthDay 递归的时候需要，传的是结束时间当天的yyyyMMdd
     * @param rule         规则
     * @return long 请假的总分钟数
     */
    public static long calcTimes(Date startTime, Date endTime, String yearMonthDay, JSONObject rule) {
        long minutes = 0;
        requireNonNull(startTime, "请假开始时间为空");
        requireNonNull(endTime, "请假结束时间为空");
        requireNonNull(rule, "未配置部门上下班规则");
        if (endTime.before(startTime)) {
            throw new IllegalArgumentException("请假结束时间必须大约开始时间");
        } else if (endTime.equals(startTime)) {
            return minutes;
        }

        // 递归的时候，这些时间不能以当天时间来算，而应该以请假结束时间所在的那一天来算(递归时使用)
        // 规定上午上班时间 规定上午下班时间 规定下午上班时间 规定下午下班时间
        Date amStart, amEnd, pmStart, pmEnd;
        if (isEmpty(yearMonthDay)) {
            amStart = strToDate(packRuleTime(rule.getString(ATTENDANCE_RULES_START_TIME)), YYYY_MM_DD_HH_MM_SS);
            amEnd = strToDate(packRuleTime(rule.getString(ATTENDANCE_RULES_END_TIME)), YYYY_MM_DD_HH_MM_SS);
            pmStart = strToDate(packRuleTime(rule.getString(ATTENDANCE_RULES_START_TIME_PM)), YYYY_MM_DD_HH_MM_SS);
            pmEnd = strToDate(packRuleTime(rule.getString(ATTENDANCE_RULES_END_TIME_PM)), YYYY_MM_DD_HH_MM_SS);
        } else {
            String hourAmStart = rule.getString(ATTENDANCE_RULES_START_TIME);
            String hourAmEnd = rule.getString(ATTENDANCE_RULES_END_TIME);
            String hourPmStart = rule.getString(ATTENDANCE_RULES_START_TIME_PM);
            String hourPmEnd = rule.getString(ATTENDANCE_RULES_END_TIME_PM);
            amStart = strToDate(packRuleTime(yearMonthDay, hourAmStart), YYYY_MM_DD_HH_MM_SS);
            amEnd = strToDate(packRuleTime(yearMonthDay, hourAmEnd), YYYY_MM_DD_HH_MM_SS);
            pmStart = strToDate(packRuleTime(yearMonthDay, hourPmStart), YYYY_MM_DD_HH_MM_SS);
            pmEnd = strToDate(packRuleTime(yearMonthDay, hourPmEnd), YYYY_MM_DD_HH_MM_SS);
        }

        // 一天的开始时间   一天的结束时间
        Date todayStart = getTodayStart(), todayEnd = getTodayEnd();

        // startTime 00:00 - 9:00
        if (afterEq(startTime, todayStart) && beforeEq(startTime, amStart)) {
            // 9:00 - 12:00
            if (afterEq(endTime, amStart) && beforeEq(endTime, amEnd)) {
                return calcMinutes(amStart, endTime);
            } else if (afterEq(endTime, amEnd) && beforeEq(endTime, pmStart)) {
                return calcMinutes(amStart, amEnd);
            } else if (afterEq(endTime, pmStart) && beforeEq(endTime, pmEnd)) {
                // 14:00 -  17:00
                // 上午总时长
                minutes = calcMinutes(amStart, amEnd);
                // 下午请假时长
                minutes += calcMinutes(pmStart, endTime);
                return minutes;
            } else if (afterEq(endTime, pmEnd) && beforeEq(endTime, todayEnd)) {
                // 17:00 - 23:59 当天(言外之意就是请了一整天假)
                minutes = calcMinutes(amStart, amEnd);
                minutes += calcMinutes(pmStart, pmEnd);
                return minutes;
            } else if (endTime.after(todayEnd)) {
                int dayOfStartTime = getDayFromTime(startTime);
                int dayOfEndTime = getDayFromTime(endTime);
                int days = dayOfEndTime - dayOfStartTime;
                // 一整天请假时长
                minutes = getWholeDayLeaveFrom(amStart, amEnd, pmStart, pmEnd);

                // 规定的第二天上午(或者 第三天及以后)上班时间
                startTime = amStart;
                startTime = addDays(startTime, days);

                // 请假到第二天
                if (days != 1) {
                    minutes += (days - 1) * minutes;
                }
                minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                return minutes;
            }

        } else if (afterEq(startTime, amStart) && beforeEq(startTime, amEnd)) {
            // startTime 9:00 - 12:00
            // endTime 9:00 - 12:00
            if (afterEq(endTime, amStart) && beforeEq(endTime, amEnd)) {
                return calcMinutes(startTime, endTime);
                // 12:00 - 14:00之间
            } else if (afterEq(endTime, amEnd) && beforeEq(endTime, pmStart)) {
                return calcMinutes(startTime, amEnd);
            } else if (afterEq(endTime, pmStart) && beforeEq(endTime, pmEnd)) {
                // 14:00 -  17:00
                // 上午总时长
                minutes = calcMinutes(startTime, amEnd);
                // 下午请假时长
                minutes += calcMinutes(pmStart, endTime);
                return minutes;
            } else if (afterEq(endTime, pmEnd) && beforeEq(endTime, todayEnd)) {
                // 17:00 - 23:59 当天(言外之意就是请了一整天假)
                minutes = calcMinutes(startTime, amEnd);
                minutes += calcMinutes(pmStart, pmEnd);
                return minutes;
            } else if (endTime.after(todayEnd)) {
                int dayOfStartTime = getDayFromTime(startTime);
                int dayOfEndTime = getDayFromTime(endTime);
                int days = dayOfEndTime - dayOfStartTime;
                // 头一天请假时长
                minutes = getWholeDayLeaveFrom(startTime, amEnd, pmStart, pmEnd);

                // 规定的第二天上午(或者 第三天及以后)上班时间
                startTime = amStart;
                startTime = addDays(startTime, days);

                // 请假到第二天
                if (days == 1) {
                    minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                    return minutes;
                } else {
                    // 一整天请假时长
                    minutes += (days - 1) * getWholeDayLeaveFrom(amStart, amEnd, pmStart, pmEnd);
                    minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                    return minutes;
                }
            }
        } else if (afterEq(startTime, amEnd) && beforeEq(startTime, pmStart)) {
            // startTime 12:00 - 14:00
            if (afterEq(endTime, pmStart) && beforeEq(endTime, pmEnd)) {
                // 14:00 -  17:00
                return calcMinutes(pmStart, endTime);
            } else if (afterEq(endTime, pmEnd) && beforeEq(endTime, todayEnd)) {
                // 17:00 - 23:59
                return calcMinutes(pmStart, pmEnd);
            } else if (endTime.after(todayEnd)) {
                // 请假到第二天
                int dayOfStartTime = getDayFromTime(startTime);
                int dayOfEndTime = getDayFromTime(endTime);
                int days = dayOfEndTime - dayOfStartTime;
                // 头一天请假时长
                minutes = getWholeDayLeaveFrom(null, null, pmStart, pmEnd);

                // 规定的第二天上午(或者 第三天及以后)上班时间
                startTime = amStart;
                startTime = addDays(startTime, days);

                // 请假到第二天
                if (days == 1) {
                    minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                    return minutes;
                } else {
                    minutes += (days - 1) * getWholeDayLeaveFrom(amStart, amEnd, pmStart, pmEnd);
                    minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                    return minutes;
                }
            }
        } else if (afterEq(startTime, pmStart) && beforeEq(startTime, pmEnd)) {
            // startTime 14:00 - 17:00
            if (afterEq(endTime, pmStart) && beforeEq(endTime, pmEnd)) {
                // 14:00 -  17:00
                return calcMinutes(startTime, endTime);
            } else if (afterEq(endTime, pmEnd) && beforeEq(endTime, todayEnd)) {
                // 17:00 - 23:59
                return calcMinutes(startTime, pmEnd);
            } else if (endTime.after(todayEnd)) {
                // 请假到第二天
                // 请假到第二天
                int dayOfStartTime = getDayFromTime(startTime);
                int dayOfEndTime = getDayFromTime(endTime);
                int days = dayOfEndTime - dayOfStartTime;
                // 头一天请假时长
                minutes = getWholeDayLeaveFrom(null, null, startTime, pmEnd);

                // 规定的第二天上午(或者 第三天及以后)上班时间
                startTime = amStart;
                startTime = addDays(startTime, days);

                // 请假到第二天
                if (days != 1) {
                    minutes += (days - 1) * getWholeDayLeaveFrom(amStart, amEnd, pmStart, pmEnd);
                }
                minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                return minutes;
            }
        } else if (afterEq(startTime, pmEnd) && beforeEq(startTime, todayEnd)) {
            // startTime 17:00 - 23:59 实际就等于是第二天的上班时间开始算请假时长
            // 规定的第二天上午(或者 第三天及以后)上班时间
            int tomorrowStartTime = getDayFromTime(startTime);
            int dayOfEndTime = getDayFromTime(endTime);
            int days = dayOfEndTime - tomorrowStartTime;

            if (days == 0) {
                return 0;
            } else if (days == 1) {
                startTime = amStart;
                startTime = addDays(startTime, 1);
                return calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
            } else {
                minutes += calcTimes(startTime, endTime, getYearMonthDayFromTime(endTime), rule);
                minutes += (days - 1) * getWholeDayLeaveFrom(amStart, amEnd, pmStart, pmEnd);
                return minutes;
            }
        }

        return minutes;
    }

    public static boolean beforeEq(Date one, Date another) {
        return (one.before(another) || one.equals(another));
    }


    public static boolean afterEq(Date one, Date another) {
        return (one.after(another) || one.equals(another));
    }

    public static String packTimes(long minutes) {
        long hours = minutes / 60;
        long minute = minutes % 60;
        String h = hours + "小时";
        return minute <= 0 ? h : h + minute + "分钟";
    }

    public static String packRuleTime(String time) {
        String yyyyMmdd = getDate();
        return yyyyMmdd + " " + time + ":00";
    }

    public static String packRuleTime(String yyyyMmdd, String hour) {
        return yyyyMmdd + " " + hour + ":00";
    }


    /**
     * 功能描述: 2021-11-10 15:15:15 => 10
     *
     * @param time 2021-11-10 15:15:15
     * @return 时间中的日期(day)
     */
    public static int getDayFromTime(Date time) {
        String strTime = dateTime1(time);
        String substring = strTime.substring(8, 10);
        return Integer.parseInt(substring);
    }

    /**
     * 功能描述: (amEnd - amStart) + (pmEnd - pmStart) 总请假时长
     *
     * @param amStart 规定上午上班时间
     * @param amEnd   规定上午下班时间
     * @param pmStart 规定下午上班时间
     * @param pmEnd   规定下午上班时间
     * @return 总请假时长
     */
    public static long getWholeDayLeaveFrom(Date amStart, Date amEnd, Date pmStart, Date pmEnd) {
        long minutes = 0;
        if (amStart != null && amEnd != null) {
            minutes = calcMinutes(amStart, amEnd);
        }

        minutes += calcMinutes(pmStart, pmEnd);
        return minutes;
    }


    /**
     * 功能描述: 2021-08-06 16:10:24 => 2021-08-06
     *
     * @param time time 2021-08-06 16:10:24
     * @return 2021-08-06
     */
    public static String getYearMonthDayFromTime(Date time) {
        String strTime = dateTime1(time);
        return strTime.substring(0, 10);
    }

}
