import BaseFoundation, { DefaultAdapter } from '../base/foundation';
import { strings } from './constants';
import type { ArrayElement } from '../utils/type';
import type { Type, DateInputFoundationProps, InsetInputValue } from './inputFoundation';
import type { MonthsGridFoundationProps } from './monthsGridFoundation';
import type { WeekStartNumber } from './_utils/getMonthTable';
export type ValidateStatus = ArrayElement<typeof strings.STATUS>;
export type InputSize = ArrayElement<typeof strings.SIZE_SET>;
export type Position = ArrayElement<typeof strings.POSITION_SET>;
export type PresetPosition = ArrayElement<typeof strings.PRESET_POSITION_SET>;
export type BaseValueType = string | number | Date;
export type DayStatusType = {
    isToday?: boolean;
    isSelected?: boolean;
    isDisabled?: boolean;
    isSelectedStart?: boolean;
    isSelectedEnd?: boolean;
    isInRange?: boolean;
    isHover?: boolean;
    isOffsetRangeStart?: boolean;
    isOffsetRangeEnd?: boolean;
    isHoverInOffsetRange?: boolean;
};
export type DisabledDateOptions = {
    rangeStart?: string;
    rangeEnd?: string;
    /**
     * current select of range type
     */
    rangeInputFocus?: 'rangeStart' | 'rangeEnd' | false;
};
export type PresetType = {
    start?: BaseValueType | (() => BaseValueType);
    end?: BaseValueType | (() => BaseValueType);
    text?: string;
};
export type TriggerRenderProps = {
    [x: string]: any;
    value?: ValueType;
    inputValue?: string;
    placeholder?: string | string[];
    autoFocus?: boolean;
    size?: InputSize;
    disabled?: boolean;
    inputReadOnly?: boolean;
    componentProps?: DatePickerFoundationProps;
};
export type DateOffsetType = (selectedDate?: Date) => Date;
export type DensityType = 'default' | 'compact';
export type DisabledDateType = (date?: Date, options?: DisabledDateOptions) => boolean;
export type DisabledTimeType = (date?: Date | Date[], panelType?: string) => ({
    disabledHours?: () => number[];
    disabledMinutes?: (hour: number) => number[];
    disabledSeconds?: (hour: number, minute: number) => number[];
});
export type OnCancelType = (date: Date | Date[], dateStr: string | string[]) => void;
export type OnPanelChangeType = (date: Date | Date[], dateStr: string | string[]) => void;
export type OnChangeType = (date?: Date | Date[] | string | string[], dateStr?: string | string[] | Date | Date[]) => void;
export type OnConfirmType = (date: Date | Date[], dateStr: string | string[]) => void;
export type OnPresetClickType = (item: PresetType, e: any) => void;
export type PresetsType = Array<PresetType | (() => PresetType)>;
export type RenderDateType = (dayNumber?: number, fullDate?: string) => any;
export type RenderFullDateType = (dayNumber?: number, fullDate?: string, dayStatus?: DayStatusType) => any;
export type TriggerRenderType = (props: TriggerRenderProps) => any;
export type ValueType = BaseValueType | BaseValueType[];
export interface ElementProps {
    bottomSlot?: any;
    insetLabel?: any;
    prefix?: any;
    topSlot?: any;
}
export interface RenderProps {
    renderDate?: RenderDateType;
    renderFullDate?: RenderFullDateType;
    triggerRender?: TriggerRenderType;
}
export type RangeType = 'rangeStart' | 'rangeEnd' | false;
export interface EventHandlerProps {
    onCancel?: OnCancelType;
    onChange?: OnChangeType;
    onOpenChange?: (status: boolean) => void;
    onPanelChange?: OnPanelChangeType;
    onConfirm?: OnConfirmType;
    onBlur?: (e: any) => void;
    onClear?: (e: any) => void;
    onFocus?: (e: any, rangType: RangeType) => void;
    onPresetClick?: OnPresetClickType;
    onClickOutSide?: () => void;
}
export interface DatePickerFoundationProps extends ElementProps, RenderProps, EventHandlerProps, Pick<MonthsGridFoundationProps, 'startYear' | 'endYear'> {
    autoAdjustOverflow?: boolean;
    autoFocus?: boolean;
    autoSwitchDate?: boolean;
    borderless?: boolean;
    className?: string;
    defaultOpen?: boolean;
    defaultPickerValue?: ValueType;
    defaultValue?: ValueType;
    density?: DensityType;
    disabled?: boolean;
    disabledDate?: DisabledDateType;
    disabledTime?: DisabledTimeType;
    dropdownClassName?: string;
    dropdownStyle?: Record<string, any>;
    endDateOffset?: DateOffsetType;
    format?: string;
    getPopupContainer?: () => HTMLElement;
    inputReadOnly?: boolean;
    inputStyle?: Record<string, any>;
    max?: number;
    motion?: boolean;
    multiple?: boolean;
    needConfirm?: boolean;
    onChangeWithDateFirst?: boolean;
    open?: boolean;
    placeholder?: string | string[];
    position?: Position;
    prefixCls?: string;
    presets?: PresetsType;
    presetPosition?: PresetPosition;
    showClear?: boolean;
    size?: InputSize;
    spacing?: number;
    startDateOffset?: DateOffsetType;
    stopPropagation?: boolean | string;
    style?: Record<string, any>;
    timePickerOpts?: any;
    timeZone?: string | number;
    type?: Type;
    validateStatus?: ValidateStatus;
    value?: ValueType;
    weekStartsOn?: WeekStartNumber;
    zIndex?: number;
    syncSwitchMonth?: boolean;
    hideDisabledOptions?: MonthsGridFoundationProps['hideDisabledOptions'];
    disabledTimePicker?: MonthsGridFoundationProps['disabledTimePicker'];
    locale?: any;
    dateFnsLocale?: any;
    localeCode?: string;
    rangeSeparator?: string;
    insetInput?: DateInputFoundationProps['insetInput'];
    preventScroll?: boolean;
}
export interface DatePickerFoundationState {
    panelShow: boolean;
    isRange: boolean;
    /** value of trigger input */
    inputValue: string;
    value: Date[];
    cachedSelectedValue: (Date | null)[];
    prevTimeZone: string | number;
    rangeInputFocus: RangeType;
    autofocus: boolean;
    /** value of inset input */
    insetInputValue: InsetInputValue;
    triggerDisabled: boolean;
}
export { Type, DateInputFoundationProps };
export interface DatePickerAdapter extends DefaultAdapter<DatePickerFoundationProps, DatePickerFoundationState> {
    togglePanel: (panelShow: boolean, cb?: () => void) => void;
    registerClickOutSide: () => void;
    unregisterClickOutSide: () => void;
    notifyBlur: DatePickerFoundationProps['onBlur'];
    notifyFocus: DatePickerFoundationProps['onFocus'];
    notifyClear: DatePickerFoundationProps['onClear'];
    notifyChange: DatePickerFoundationProps['onChange'];
    notifyCancel: DatePickerFoundationProps['onCancel'];
    notifyConfirm: DatePickerFoundationProps['onConfirm'];
    notifyOpenChange: DatePickerFoundationProps['onOpenChange'];
    notifyPresetsClick: DatePickerFoundationProps['onPresetClick'];
    updateValue: (value: Date[]) => void;
    updatePrevTimezone: (prevTimeZone: string | number) => void;
    updateCachedSelectedValue: (cachedSelectedValue: Date[]) => void;
    updateInputValue: (inputValue: string) => void;
    needConfirm: () => boolean;
    typeIsYearOrMonth: () => boolean;
    setRangeInputFocus: (rangeInputFocus: DatePickerFoundationState['rangeInputFocus']) => void;
    couldPanelClosed: () => boolean;
    isEventTarget: (e: any) => boolean;
    updateInsetInputValue: (insetInputValue: InsetInputValue) => void;
    setInsetInputFocus: () => void;
    setTriggerDisabled: (disabled: boolean) => void;
    setInputFocus: () => void;
    setInputBlur: () => void;
    setRangeInputBlur: () => void;
}
/**
 * The datePicker foundation.js is responsible for maintaining the date value and the input box value, as well as the callback of both
 *  task 1. Accept the selected date change, update the date value, and update the input box value according to the date = > Notify the change
 *  task 2. When the input box changes, update the date value = > Notify the change
 */
export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapter> {
    clickConfirmButton: boolean;
    constructor(adapter: DatePickerAdapter);
    init(): void;
    initFromProps({ value, timeZone, prevTimeZone }: Pick<DatePickerFoundationProps, 'value' | 'timeZone'> & {
        prevTimeZone?: string | number;
    }): void;
    /**
     * 如果用户传了一个空的 value，需要把 range input focus 设置为 rangeStart，这样用户可以清除完之后继续从开始选择
     *
     * If the user passes an empty value, you need to set the range input focus to rangeStart, so that the user can continue to select from the beginning after clearing
     */
    initRangeInputFocus(result: Date[]): void;
    /**
     * value 可能是 UTC value 也可能是 zoned value
     *
     * UTC value -> 受控传入的 value
     *
     * zoned value -> statue.value，保存的是当前计算机时区下选择的日期
     *
     * 如果是时区变化，则需要将旧 zoned value 转为新时区下的 zoned value
     *
     * 如果是 value 变化，则不需要传入之前的时区，将 UTC value 转为 zoned value 即可
     *
     */
    parseWithTimezone(value: ValueType, timeZone: string | number, prevTimeZone: string | number): Date[];
    _isMultiple(): boolean;
    /**
     *
     *  Verify and parse the following three format inputs
     *
        1. Date object
        2. ISO 9601-compliant string
        3. ts timestamp

        Unified here to format the incoming value and output it as a Date object
     *
     */
    _parseValue(value: BaseValueType): Date;
    destroy(): void;
    initPanelOpenStatus(defaultOpen?: boolean): void;
    openPanel(): void;
    /**
     * clear inset input value when close panel
     */
    clearInsetInputValue(): void;
    /**
     * call it when change state value or input value
     */
    resetCachedSelectedValue(willUpdateDates?: Date[]): void;
    /**
     * timing to call closePanel
     *  1. click confirm button
     *  2. click cancel button
     *  3. select date, time, year, month
     *    - date type and not multiple, close panel after select date
     *    - dateRange type, close panel after select rangeStart and rangeEnd
     *  4. click outside
     * @param {Event} e
     * @param {String} inputValue
     * @param {Date[]} dates
     */
    closePanel(e?: any, inputValue?: string, dates?: Date[]): void;
    open(): void;
    close(): void;
    focus(focusType?: Exclude<RangeType, false>): void;
    blur(): void;
    /**
     * reset cachedSelectedValue, inputValue when close panel
     */
    resetInnerSelectedStates(willUpdateDates?: Date[]): void;
    resetFocus(e?: any): void;
    /**
     * cachedSelectedValue can be `(Date|null)[]` or `null`
     */
    isCachedSelectedValueValid(dates: Date[]): boolean;
    /**
     * 将输入框内容置空
     */
    clearInputValue(): void;
    /**
     * clear range input focus when open is controlled
     * fixed github 1375
     */
    clearRangeInputFocus: () => void;
    /**
     * Callback when the content of the input box changes
     * Update the date panel if the changed value is a legal date, otherwise only update the input box
     * @param {String} input The value of the input box after the change
     * @param {Event} e
     */
    handleInputChange(input: string, e: any): void;
    /**
     * inset input 变化时需要更新以下 state 状态
     *  - insetInputValue（总是）
     *  - inputValue（可以解析为合法日期时）
     *  - value（可以解析为合法日期时）
     */
    handleInsetInputChange(options: {
        insetInputStr: string;
        format: string;
        insetInputValue: InsetInputValue;
    }): void;
    /**
     * when input change we reset cached selected value
     */
    _updateCachedSelectedValueFromInput(input: string): void;
    /**
     * Input box blur
     * @param {String} input
     * @param {Event} e
     */
    handleInputBlur(input?: string, e?: any): void;
    /**
     * called when range type rangeEnd input tab press
     * @param {Event} e
     */
    handleRangeEndTabPress(e: any): void;
    /**
     * called when the input box is focused
     * @param {Event} e input focus event
     * @param {String} range 'rangeStart' or 'rangeEnd', use when type is range
     */
    handleInputFocus(e: any, range: 'rangeStart' | 'rangeEnd'): void;
    handleSetRangeFocus(rangeInputFocus: RangeType): void;
    handleInputClear(e: any): void;
    /**
     * 范围选择清除按钮回调
     * 因为清除按钮没有集成在Input内，因此需要手动清除 value、inputValue、cachedValue
     *
     * callback of range input clear button
     * Since the clear button is not integrated in Input, you need to manually clear value, inputValue, cachedValue
     */
    handleRangeInputClear(e: any): void;
    handleRangeInputBlur(value: any, e: any): void;
    handleInputComplete(input?: any): void;
    /**
     * Parse the input, return the time object if it is valid,
     *  otherwise return "
     *
     * @param {string} input
     * @returns  {Date [] | '}
     */
    parseInput(input?: string, format?: string): Date[];
    /**
     * get date which may include null from input
     */
    getLooseDateFromInput(input: string): Array<Date | null>;
    /**
     * parse input into `Array<Date|null>`, loose means return value includes `null`
     *
     * @example
     * ```javascript
     * parseInputLoose('2022-03-15 ~ '); // [Date, null]
     * parseInputLoose(' ~ 2022-03-15 '); // [null, Date]
     * parseInputLoose(''); // []
     * parseInputLoose('2022-03- ~ 2022-0'); // [null, null]
     * ```
     */
    parseInputLoose(input?: string): Array<Date | null>;
    /**
     * parse multiple into `Array<Date|null>`, loose means return value includes `null`
     *
     * @example
     * ```javascript
     * parseMultipleInputLoose('2021-01-01,2021-10-15'); // [Date, Date];
     * parseMultipleInputLoose('2021-01-01,2021-10-'); // [Date, null];
     * parseMultipleInputLoose(''); // [];
     * ```
     */
    parseMultipleInputLoose(input?: string, separator?: string, needDedupe?: boolean): Date[];
    /**
     * Parses the input when multiple is true, if valid,
     *  returns a list of time objects, otherwise returns an array
     *
     * @param {string} [input='']
     * @param {string} [separator=',']
     * @param {boolean} [needDedupe=false]
     * @returns {Date[]}
     */
    parseMultipleInput(input?: string, separator?: string, needDedupe?: boolean): Date[];
    /**
     * dates[] => string
     *
     * @param {Date[]} dates
     * @returns {string}
     */
    formatDates(dates?: Date[], customFormat?: string): string;
    /**
     * dates[] => string
     *
     * @param {Date[]} dates
     * @returns {string}
     */
    formatMultipleDates(dates?: Date[], separator?: string, customFormat?: string): string;
    /**
     * Update date value and the value of the input box
     * 1. Select Update
     * 2. Input Update
     * @param {Date|''} value
     * @param {Boolean} forceUpdateValue
     * @param {String} input
     */
    _updateValueAndInput(value: Date | Array<Date>, forceUpdateValue?: boolean, input?: string): void;
    /**
     * when changing the selected value through the date panel
     * @param {*} value
     * @param {*} options
     */
    handleSelectedChange(value: Date[], options?: {
        fromPreset?: boolean;
        needCheckFocusRecord?: boolean;
    }): void;
    /**
     * when changing the year and month through the panel when the type is year or month or monthRange
     * @param {*} item
     */
    handleYMSelectedChange(item?: {
        currentMonth?: {
            left: number;
            right: number;
        };
        currentYear?: {
            left: number;
            right: number;
        };
    }): void;
    handleConfirm(): void;
    handleCancel(): void;
    handlePresetClick(item: PresetType, e: any): void;
    /**
     * 根据 type 处理 onChange 返回的参数
     *
     *  - 返回的日期需要把用户时间转换为设置的时区时间
     *      - 用户时间：用户计算机系统时间
     *      - 时区时间：通过 ConfigProvider 设置的 timeZone
     *  - 例子：用户设置时区为+9，计算机所在时区为+8区，然后用户选择了22:00
     *      - DatePicker 内部保存日期 state 为 +8 的 22:00 => a = new Date("2021-05-25 22:00:00")
     *      - 传出去时，需要把 +8 的 22:00 => +9 的 22:00 => b = zonedTimeToUtc(a, "+09:00");
     *
     * According to the type processing onChange returned parameters
     *
     *   - the returned date needs to convert the user time to the set time zone time
     *       - user time: user computer system time
     *       - time zone time: timeZone set by ConfigProvider
     *   - example: the user sets the time zone to + 9, the computer's time zone is + 8 zone, and then the user selects 22:00
     *       - DatePicker internal save date state is + 8 22:00 = > a = new Date ("2021-05-25 22:00:00")
     *       - when passed out, you need to + 8 22:00 = > + 9 22:00 = > b = zonedTimeToUtc (a, "+ 09:00");
     *
     *  e.g.
     *  let a = new Date ("2021-05-25 22:00:00");
     *       = > Tue May 25 2021 22:00:00 GMT + 0800 (China Standard Time)
     *  let b = zonedTimeToUtc (a, "+ 09:00");
     *       = > Tue May 25 2021 21:00:00 GMT + 0800 (China Standard Time)
     *
     * @param {Date|Date[]} value
     * @return {{ notifyDate: Date|Date[], notifyValue: string|string[]}}
     */
    disposeCallbackArgs(value: Date | Date[]): {
        notifyValue: any;
        notifyDate: any;
    };
    /**
     * Notice: Check whether the date is the same as the state value before calling
     * @param {Date[]} value
     */
    _notifyChange(value: Date[]): void;
    /**
     * Get the date changed through the date panel or enter
     */
    _getChangedDates(dates: Date[]): any[];
    /**
     * Whether a date is disabled
     * @param value The date that needs to be judged whether to disable
     * @param selectedValue Selected date, when selecting a range, pass this date to the second parameter of `disabledDate`
     */
    _someDateDisabled(value: Date[], selectedValue: Date[]): boolean;
    /**
     * Format locale date
     * locale get from LocaleProvider
     * @param {Date} date
     * @param {String} token
     */
    localeFormat(date: Date, token: string): string;
    _isRangeType: () => boolean;
    _isRangeValueComplete: (value: Date[] | Date) => boolean;
    /**
     * Convert computer date to UTC date
     * Before passing the date to the user, you need to convert the date to UTC time
     * dispose date from computer date to utc date
     * When given timeZone prop, you should convert computer date to utc date before passing to user
     * @param {(date: Date) => Boolean} fn
     * @param {Date|Date[]} date
     * @returns {Boolean}
     */
    disposeDateFn(fn: (date: Date, ...rest: any) => boolean, date: Date | Date[], ...rest: any[]): boolean;
    /**
     * Determine whether the date is disabled
     * Whether the date is disabled
     * @param {Date} date
     * @returns {Boolean}
     */
    disabledDisposeDate(date: Date, ...rest: any[]): boolean;
    /**
     * Determine whether the date is disabled
     * Whether the date time is disabled
     * @param {Date|Date[]} date
     * @returns {Object}
     */
    disabledDisposeTime(date: Date | Date[], ...rest: any[]): boolean;
    /**
     * Trigger wrapper needs to do two things:
     *  1. Open Panel when clicking trigger;
     *  2. When clicking on a child but the child does not listen to the focus event, manually trigger focus
     *
     * @param {Event} e
     * @returns
     */
    handleTriggerWrapperClick(e: any): void;
    handlePanelVisibleChange(visible: boolean): void;
}
