import dayjs from "dayjs";
import utc from "dayjs/plugin/utc.js";
import timezone from "dayjs/plugin/timezone.js";
import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js";
import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js";
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);

const CST = "Asia/Shanghai";
const PT = "America/Los_Angeles";
export class Plan {
    constructor(dt, params) {
        this.dt = dayjs.tz(dt ?? new Date(), CST);
        this.setHandler();
        this.table = new Proxy({}, this.handler);
        this.params = [];
        params?.forEach(param => this._addParam(...param));
    }
    setHandler() {
        this.handler = {
            dt: this.dt,
            order: [],  // 逆序
            get(obj, prop) {
                if (prop in obj) return obj[prop];
                const idx = this.order.find(x => prop - x >= 0);
                return obj[idx];
            },
            set(obj, prop, value) {
                const result = Reflect.set(...arguments);
                this.order = Object.keys(obj).sort((a, b) => b - a);
                let [x1, x2] = value.period, dt = this.dt;
                if (this.dt.date() < parseInt(x2) || x2 === 0) {
                    dt = this.dt.subtract(1, "month");
                }
                let year = dt.year();
                let month = dt.month() + 1;
                x2 = x2 === 0 ? dt.daysInMonth() : x2;
                month = (month + '').padStart(2, "0");

                value.period = [
                    `${year}-${month}-${x1}`,
                    `${year}-${month}-${x2}`
                ];
                return result;
            }
        };
    }
    get(day = null) {
        return (day ? this.table[day] : this.table[this.dt.date()]) ?? {};
    }
    next() {
        let dt = this.dt;
        const order = this.handler.order;
        const idx = (
            order.indexOf(this.get().dt.date() + '') - 1 + order.length  // 向上
        ) % order.length;
        if (idx == order.length - 1) {
            dt = dt.add(1, "month");
        }
        let year = dt.year();
        let month = dt.month();
        dt = this.table[order[idx]].dt
            .set("year", year)
            .set("month", month);
        return new Plan(dt, this.params);
    }
    _addParam(execTime, period, isMmonthly = false) {
        // MM-dd HH:mm:ss
        const dt = dayjs.tz(new Date(), CST)
            .set("date", +execTime.substring(0, 2))
            .set("hour", +execTime.substring(3, 5));
        this.table[dt.date()] = { period, dt, isMmonthly };
        this.params.push(arguments);
    }
}
export const makeLogEntry = (message) => {
    return {
        time: dayjs.tz(new Date(), CST).format("HH:mm:ss"),
        message
    }
};
export const addLog = (message, push) => {
    if (typeof chrome !== 'undefined' && chrome.runtime) {
        chrome.runtime.sendMessage({ type: "addLog", data: makeLogEntry(message), push });
    }
};

const checkTime = (time) => {
    if (!time.isValid()) throw new Error("无效时间");
}
export function getMouth(dt, offset = 0) {
    let time = dayjs.tz(dt ?? new Date(), CST).add(offset, "month");
    checkTime(time);
    return time.format("YYYY-MM");
}
export function cutDate(period, date) {
    const d1 = dayjs(period[0]);
    const d2 = dayjs(period[1]);
    if (!date || (d1.isSameOrAfter(date, "day") && d2.isSameOrAfter(date, "day"))) {
        return [[1, 2], false];
    } else if (d1.isSameOrBefore(date, "day") && d2.isSameOrBefore(date, "day")) {
        return [[0, 1], false];
    } else {
        return [[0, 2], true];
    }
}
export function isLatestDate(dt) {
    const time = dayjs.tz(dt ?? new Date(), PT);
    checkTime(time);
    const now = dayjs.tz(undefined, PT);
    return time.isSame(now, "day")
        || time.isSame(now.subtract(1, "day"), "day")
        || time.isSame(now.add(1, "day"), "day");
}
export function getTimeDiff(dt, offset = 0) {
    const time = dayjs
        .tz(dt ?? new Date(), PT)
        .add(offset, "day");
    checkTime(time);
    return (dayjs().valueOf() - time.valueOf()) / 1000 / 60 / 60;  // h
}
