package com.sencorsta.rabs.util;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sencorsta.rabs.obj.ai.api.Status;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.Date;
import java.util.function.Supplier;

@AllArgsConstructor
@NoArgsConstructor
public class ResettableData<T extends Status> {
    private T data;
    private long nextResetTime;  // 下一次重置的时间戳
    @Getter
    @Setter
    private ResetType resetType = ResetType.DAILY;

    public enum ResetType {
        /**
         * 每日重置
         */
        DAILY {
            @Override
            long getNextResetTime() {
                return DateUtil.beginOfDay(DateUtil.tomorrow()).offset(DateField.HOUR, 5).getTime();
            }
        },
        /**
         * 每周重置
         */
        WEEKLY {
            @Override
            long getNextResetTime() {
                return DateUtil.beginOfWeek(DateUtil.nextWeek()).offset(DateField.HOUR, 5).getTime();
            }
        },
        /**
         * 每周重置（周一和周四的5点）
         */
        WEEKLY1_4 {
            @Override
            long getNextResetTime() {
                DateTime now = DateUtil.date();
                DateTime nextMonday5AM = DateUtil.beginOfWeek(now).offset(DateField.HOUR, 5); // 下一个周一的5点
                DateTime nextThursday5AM = DateUtil.beginOfWeek(now).offset(DateField.DAY_OF_WEEK, 4).offset(DateField.HOUR, 5); // 下一个周四的5点

                if (now.isBefore(nextMonday5AM)) {
                    return nextMonday5AM.getTime();
                } else if (now.isBefore(nextThursday5AM)) {
                    return nextThursday5AM.getTime();
                } else {
                    // 如果当前时间已经过了周四的5点，则下一个重置时间为再下一个周一的5点
                    return nextMonday5AM.offset(DateField.WEEK_OF_YEAR, 1).getTime();
                }
            }
        },
        /**
         * 每2周重置
         */
        WEEKLY_DOUBLE {
            @Override
            long getNextResetTime() {
                return DateUtil.beginOfWeek(DateUtil.offsetWeek(new DateTime(), 2)).offset(DateField.HOUR, 5).getTime();
            }
        },
        /**
         * 每月重置
         */
        MONTHLY {
            @Override
            long getNextResetTime() {
                return DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), 1)).offset(DateField.HOUR, 5).getTime();
            }
        },
        /**
         * 每3小时重置
         */
        HOUR_3 {
            @Override
            long getNextResetTime() {
                return System.currentTimeMillis() + 1000L * 60 * 60 * 3;  // 24小时的毫秒数，可替换为具体的时间间隔
            }
        },
        /**
         * 每天的10点 16点 20点重置
         * 如果当前大于10点就返回16点的时间戳
         * 如果当前大于16点就返回20点的时间戳
         * 如果当前大于20点就返回第二天10点的时间戳
         */
        SPECIAL_RULES {
            @Override
            long getNextResetTime() {
                // 获取当前时间
                long currentTime = System.currentTimeMillis();

                // 获取今天的日期
                String today = DateUtil.today();

                // 定义重置时间
                String resetTime10 = today + " 10:00:00";
                String resetTime16 = today + " 16:00:00";
                String resetTime20 = today + " 20:00:00";

                // 将重置时间转换为时间戳
                long resetTime10Millis = DateUtil.parse(resetTime10).getTime();
                long resetTime16Millis = DateUtil.parse(resetTime16).getTime();
                long resetTime20Millis = DateUtil.parse(resetTime20).getTime();

                // 比较当前时间与各个重置时间，并返回最近的重置时间的时间戳
                if (currentTime < resetTime10Millis) {
                    return resetTime10Millis;
                } else if (currentTime < resetTime16Millis) {
                    return resetTime16Millis;
                } else if (currentTime < resetTime20Millis) {
                    return resetTime20Millis;
                } else {
                    return DateUtil.offsetDay(DateUtil.parse(resetTime10), 1).getTime();
                }
            }
        };

        abstract long getNextResetTime();
    }

    public static void main(String[] args) {
        Date date = new Date();
        for (int i = 0; i < 48; i++) {
            DateTime dateTime = DateUtil.beginOfDay(date);
            DateTime offset = dateTime.offset(DateField.HOUR, i);
            long test = test(offset.getTime());
            System.out.println(offset + " = " + DateTime.of(test).toString());
        }
    }

    private static long test(long currentTime) {
        // 获取今天的日期
        String today = DateUtil.today();

        // 定义重置时间
        String resetTime10 = today + " 10:00:00";
        String resetTime16 = today + " 16:00:00";
        String resetTime20 = today + " 20:00:00";

        // 将重置时间转换为时间戳
        long resetTime10Millis = DateUtil.parse(resetTime10).getTime();
        long resetTime16Millis = DateUtil.parse(resetTime16).getTime();
        long resetTime20Millis = DateUtil.parse(resetTime20).getTime();

        // 比较当前时间与各个重置时间，并返回最近的重置时间的时间戳
        if (currentTime < resetTime10Millis) {
            return resetTime10Millis;
        } else if (currentTime < resetTime16Millis) {
            return resetTime16Millis;
        } else if (currentTime < resetTime20Millis) {
            return resetTime20Millis;
        } else {
            return DateUtil.offsetDay(DateUtil.parse(resetTime10), 1).getTime();
        }
    }

    // 使用枚举来构造，确定重置的类型
    public ResettableData(ResetType type, Supplier<T> dataSupplier) {
        this.data = (dataSupplier != null) ? dataSupplier.get() : null;
        this.resetType = type;
        this.nextResetTime = resetType.getNextResetTime();
    }

    public T getData() {
        maybeReset();
        return data;
    }

    public void setData(T data) {
        maybeReset();
        this.data = data;
    }

    public void maybeReset() {
        long now = System.currentTimeMillis();
        if (now >= nextResetTime) {
            resetData();
            this.nextResetTime = resetType.getNextResetTime();
        }
    }

    private void resetData() {
        if (data != null) {
            data.reset();
        }
    }
}
