import type { Ele as PopoverEle, EventMap as PopoverEvent } from '../popover';
import {
    type BaseAttrs,
    type BaseEmits,
    type Emit2EventMap,
    UiBase
} from '../web-component-base';
import {
    Ele as YyyyMmDdListGrpEle,
    type EventMap as YyyyMmDdListGrpEvent
} from '../yyyymmdd-list-grp';
import styleStr from './index.css';
import html from './index.html';

export interface Attrs extends BaseAttrs {
    millisecond: number;
    /**
     * 选择器的粒度，表示最大可选的时间单位。默认为 year。
     */
    'max-granularity'?: 'year' | 'month';
    /**
     * 选择器的粒度，表示最小可选的时间单位。默认为 month。
     */
    'min-granularity'?: 'year' | 'month';
    /**
     * 是否显示年份控制按钮（快速增减年份）
     * @default false
     */
    'show-ctrl-btn-year-add'?: boolean;
    'show-ctrl-btn-year-sub'?: boolean;
    /**
     * 是否显示月份控制按钮（快速增减月份）
     * @default false
     */
    'show-ctrl-btn-month-add'?: boolean;
    'show-ctrl-btn-month-sub'?: boolean;
}

export interface Emits extends BaseEmits {
    change: {
        oldTime: Date;
        newTime: Date;
    };
    'popover-open-change': boolean;
}
export type EventMap = Emit2EventMap<Emits>;

/**
 * 日期导航组件
 *
 * 存在一个 titleFormatter 方法，可以重写该方法以自定义年月标题的回显格式。
 */
export class Ele extends UiBase<Attrs, Emits> {
    public static readonly tagName = 'dt-yyyymm-nav' as const;
    protected static _style = styleStr;
    protected static _template = html;

    static get observedAttributes(): string[] {
        return [
            ...(super.observedAttributes as (keyof BaseAttrs)[]),
            'millisecond',
            'max-granularity',
            'min-granularity',
            'show-ctrl-btn-month-add',
            'show-ctrl-btn-year-sub',
            'show-ctrl-btn-month-add',
            'show-ctrl-btn-month-sub'
        ] satisfies (keyof Attrs)[];
    }

    public get millisecond() {
        return Math.floor(+this._getAttr('millisecond', '0'));
    }
    public set millisecond(v: number) {
        if (!Number.isSafeInteger(v)) return;
        this.setAttribute('millisecond', '' + Math.floor(v));
    }

    public get showCtrlBtnYearAdd() {
        return this.hasAttribute('show-ctrl-btn-year-add');
    }
    public set showCtrlBtnYearAdd(val: boolean) {
        this.toggleAttribute('show-ctrl-btn-year-add', val);
    }
    public get showCtrlBtnYearSub() {
        return this.hasAttribute('show-ctrl-btn-year-sub');
    }
    public set showCtrlBtnYearSub(val: boolean) {
        this.toggleAttribute('show-ctrl-btn-year-sub', val);
    }
    public get showCtrlBtnMonthAdd() {
        return this.hasAttribute('show-ctrl-btn-month-add');
    }
    public set showCtrlBtnMonthAdd(val: boolean) {
        this.toggleAttribute('show-ctrl-btn-month-add', val);
    }
    public get showCtrlBtnMonthSub() {
        return this.hasAttribute('show-ctrl-btn-month-sub');
    }
    public set showCtrlBtnMonthSub(val: boolean) {
        this.toggleAttribute('show-ctrl-btn-month-sub', val);
    }

    public connectedCallback() {
        if (!super.connectedCallback()) return;
        this._render();
        this._bindEvt<PopoverEle>`.echo`('open-change', this._onTitleToggle);
        this._bindEvt<YyyyMmDdListGrpEle>`dt-yyyymmdd-list-grp`(
            'change',
            this._onItemSelect
        );
        this._bindEvt<HTMLElement>`.btn`('click', this._onBtnClick);
    }

    protected _onAttrChanged(
        name: string,
        oldValue: string | null,
        newValue: string | null
    ) {
        super._onAttrChanged(name, oldValue, newValue);
        this._render();
        if (name === 'millisecond') {
            this.dispatchEvent(
                'change',
                {
                    oldTime: new Date(Math.floor(+oldValue!)),
                    newTime: new Date(Math.floor(+newValue!))
                },
                true
            );
        }
    }

    private _render = super._genRenderFn(() => {
        const ms = this.millisecond;
        this.$0<YyyyMmDdListGrpEle>`dt-yyyymmdd-list-grp`!.millisecond = ms;
        this.$0`.title`!.textContent = this.titleFormatter(ms);
    });

    private _onTitleToggle = (e: PopoverEvent['open-change']) => {
        const isOpen = e.detail;
        e.stopPropagation();
        this.$0`.wrapper`!.classList.toggle('show-list', isOpen);
        this
            .$0<YyyyMmDdListGrpEle>`dt-yyyymmdd-list-grp`!.scrollToCurrentItem();
        this.dispatchEvent('popover-open-change', isOpen, true);
    };
    private _onItemSelect = (e: YyyyMmDdListGrpEvent['change']) => {
        if (!(e.target instanceof YyyyMmDdListGrpEle)) return;
        e.stopPropagation();
        this.millisecond = e.target.millisecond;
    };
    private _onBtnClick = (e: MouseEvent) => {
        if (!(e.target instanceof HTMLElement)) return;
        const date = new Date(this.millisecond);
        date.setDate(1);
        if (e.target.matches('.add.year')) {
            date.setFullYear(date.getFullYear() + 1);
        } else if (e.target.matches('.sub.year')) {
            date.setFullYear(date.getFullYear() - 1);
        } else if (e.target.matches('.add.month')) {
            date.setMonth(date.getMonth() + 1);
        } else if (e.target.matches('.sub.month')) {
            date.setMonth(date.getMonth() - 1);
        }
        this.millisecond = +date;
    };

    public titleFormatter = (ms: number) => {
        const date = new Date(ms);
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        return `${(month < 10 ? '0' : '') + month}/${year}`;
    };
}

Ele.define();
