import { ICalendarCell } from "./ICalendarCell";
import { ItemCalendarDay } from "./ItemCalendarDay";

/*
 * @Author       : -------
 * @Date         : 2025-05-15 20:58:37
 * @LastEditors  : -------
 * @LastEditTime : 2025-05-16 17:00:28
 * @Description  : file content
 * 如果需要扩展为滑动，可以使用虚拟PageView，以calendar_table_page为子页进行扩展
 * 由于虚拟PageView很多实现都不相同，各个项目也可能不同，我也没有非常好用PageView
 * 所以需要使用可以选择自己合适的实现
 */
const { ccclass, property } = cc._decorator;
@ccclass
export class CalendarView extends cc.Component {
    @property(cc.Node)
    private nextPgaeNd: cc.Node = null;

    @property(cc.Node)
    private prevPgaeNd: cc.Node = null;

    @property(cc.Label)
    private lblCurDate: cc.Label = null;

    @property(cc.Label)
    private lblSelectDate: cc.Label = null;

    private _currentYear: number = 0;
    private _currentMonth: number = 0;
    private _curSelectCell: ICalendarCell = null;
    protected onLoad() {
        this._initData();
        this._initUI();
    }

    protected onEnable(): void {
        this._addEvent();
    }

    protected onDisable(): void {
        this._removeEvent();
    }

    private _initData() {
        const currentDate = new Date();
        this._currentYear = currentDate.getFullYear();
        this._currentMonth = currentDate.getMonth() + 1;
    }

    private _initUI() {
        this._refreshCurrentMonthView();
    }

    private _addEvent() {
        cc.director.getScene().on("event_select_cell_day", this._onSelectCellDay, this);
        this.prevPgaeNd?.on(cc.Node.EventType.TOUCH_END, this._onPrevPage, this);
        this.nextPgaeNd?.on(cc.Node.EventType.TOUCH_END, this._onNextPage, this);
    }

    private _removeEvent() {
        cc.director.getScene().off("event_select_cell_day", this._onSelectCellDay, this);
        this.prevPgaeNd?.off(cc.Node.EventType.TOUCH_END, this._onPrevPage, this);
        this.nextPgaeNd?.off(cc.Node.EventType.TOUCH_END, this._onNextPage, this);
    }

    private _onSelectCellDay(date: Readonly<ICalendarCell>) {
        if (this._curSelectCell && this._isSameDate(date, this._curSelectCell)) {
            return;
        }

        this.lblSelectDate && (this.lblSelectDate.string = `${date.year}-${date.month}-${date.day}`);

        this._curSelectCell = date;
        this._refreshCurrentMonthView();
    }

    private _onPrevPage() {
        if (this._currentMonth === 1) {
            this._currentYear -= 1;
            this._currentMonth = 12;
        } else {
            this._currentMonth -= 1;
        }

        this._refreshCurrentMonthView();
    }

    private _onNextPage() {
        if (this._currentMonth === 12) {
            this._currentYear += 1;
            this._currentMonth = 1;
        } else {
            this._currentMonth += 1;
        }

        this._refreshCurrentMonthView();
    }

    private _isSameDate(a: ICalendarCell, b: ICalendarCell): boolean {
        return a.year === b.year && a.month === b.month && a.day === b.day;
    }

    protected _refreshCurrentMonthView() {
        const monthGrid = this._getMonthGrid(this._currentYear, this._currentMonth);
        const weekdayRows = this._rearrangeByWeekday(monthGrid);

        const calenderTable = this.node.getChildByName("calendar_table_page");

        for (let i = 0; i < weekdayRows.length; ++i) {
            const weekDaysNd = calenderTable.children[i];
            const weekDays = weekdayRows[i];

            for (let j = 0; j < weekDays.length; ++j) {
                const dayData = weekDays[j];
                const dayItem = weekDaysNd.children[j].getComponent(ItemCalendarDay);

                dayItem.date = dayData;
                dayItem.isSelected = this._curSelectCell && this._isSameDate(dayData, this._curSelectCell);
                dayItem.updateView();
            }
        }

        this.lblCurDate && (this.lblCurDate.string = `${this._currentYear}-${this._currentMonth}`);
    }

    /**
     * 获取当前月份的数据，其中包括补足的上月和下月的部分日期
     * @example
     * [
     *      ........
     *    { year: 2025, month: 4, day: 30, isCurrentMonth: false },
     *    { year: 2025, month: 5, day: 1, isCurrentMonth: true },
     *    { year: 2025, month: 5, day: 2, isCurrentMonth: true },
     *    { year: 2025, month: 5, day: 3, isCurrentMonth: true },
     *    { year: 2025, month: 5, day: 4, isCurrentMonth: true },
     *    { year: 2025, month: 5, day: 5, isCurrentMonth: true },
     *      ........
     *      ........
     *      ........
     *    { year: 2025, month: 5, day: 31, isCurrentMonth: true },
     *      ........
     * ]
     * @param year
     * @param month
     * @returns
     */
    protected _getMonthGrid(year: number, month: number): ICalendarCell[] {
        const result: ICalendarCell[] = [];

        // 当前月第一天
        const firstDay = new Date(year, month - 1, 1);

        // 当前月第一天是星期几
        const firstWeekDay = firstDay.getDay(); // 0 = Sunday

        // 上个月
        const prevMonth = month === 1 ? 12 : month - 1;
        // 上一年
        const prevYear = month === 1 ? year - 1 : year;
        // 上一年的最后一天
        const prevLastDate = new Date(prevYear, prevMonth, 0).getDate();

        // 填充上个月
        for (let i = firstWeekDay - 1; i >= 0; i--) {
            result.push({
                year: prevYear,
                month: prevMonth,
                day: prevLastDate - i,
                isCurrentMonth: false,
            });
        }

        // 填充当前月
        const currentLastDate = new Date(year, month, 0).getDate();
        for (let day = 1; day <= currentLastDate; day++) {
            result.push({
                year,
                month,
                day,
                isCurrentMonth: true,
            });
        }

        // 补足到 7*6 = 42 格，填充下个月
        while (result.length < 42) {
            const nextDay = result.length - (firstWeekDay + currentLastDate - 1) + 1;
            const nextMonth = month === 12 ? 1 : month + 1;
            const nextYear = month === 12 ? year + 1 : year;

            result.push({
                year: nextYear,
                month: nextMonth,
                day: nextDay,
                isCurrentMonth: false,
            });
        }

        return result;
    }

    /**
     * 根据星期分组，一个星期编号对应5个日期
     * @example
        "星期日: 30, 6, 13, 20, 27" 
        "星期一: 31, 7, 14, 21, 28" 
        "星期二: 1, 8, 15, 22, 29" 
        "星期三: 2, 9, 16, 23, 30" 
        "星期四: 3, 10, 17, 24, 2" 
        "星期五: 4, 11, 18, 25, 3" 
        "星期六: 5, 12, 19, 26, 4" 
     * @param flatArray 
     * @returns 
     */
    protected _rearrangeByWeekday(flatArray: ICalendarCell[]): ICalendarCell[][] {
        const weekdayRows: ICalendarCell[][] = [[], [], [], [], [], [], []]; // 0 = Sunday

        for (let i = 0; i < flatArray.length; i++) {
            const weekday = i % 7;
            weekdayRows[weekday].push(flatArray[i]);
        }

        return weekdayRows;
    }
}
