/*
 * Copyright 2018 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as React from "react";

import { Menu, MenuItem } from "@blueprintjs/core";

import { Classes, type DateRange, type TimePrecision } from "../../common";
import { clone, isDayRangeInRange } from "../../common/dateUtils";

export interface DateShortcutBase {
    /** Shortcut label that appears in the list. */
    label: string;

    /**
     * Set this prop to `true` to allow this shortcut to change the selected
     * times as well as the dates. By default, time components of a shortcut are
     * ignored; clicking a shortcut takes the date components of the `dateRange`
     * and combines them with the currently selected time.
     *
     * @default false
     */
    includeTime?: boolean;
}

export interface DateRangeShortcut extends DateShortcutBase {
    /**
     * Date range represented by this shortcut. Note that time components of a
     * shortcut are ignored by default; set `includeTime: true` to respect them.
     */
    dateRange: DateRange;
}

export interface DatePickerShortcut extends DateShortcutBase {
    /**
     * Date represented by this shortcut. Note that time components of a
     * shortcut are ignored by default; set `includeTime: true` to respect them.
     */
    date: Date;
}

export interface DatePickerShortcutMenuProps {
    allowSingleDayRange: boolean;
    minDate: Date;
    maxDate: Date;
    shortcuts: DateRangeShortcut[] | true;
    timePrecision: TimePrecision;
    selectedShortcutIndex?: number;
    onShortcutClick: (shortcut: DateRangeShortcut, index: number) => void;
    /**
     * The DatePicker component reuses this component for a single date.
     * This changes the default shortcut labels and affects which shortcuts are used.
     *
     * @default false
     */
    useSingleDateShortcuts?: boolean;
}

/**
 * Menu of {@link DateRangeShortcut} items, typically displayed in the UI to the left of a day picker calendar.
 *
 * This component may be used for single date pickers as well as range pickers by toggling the
 * `useSingleDateShortcuts` option.
 */
export class DatePickerShortcutMenu extends React.PureComponent<DatePickerShortcutMenuProps> {
    public static defaultProps: Partial<DatePickerShortcutMenuProps> = {
        selectedShortcutIndex: -1,
    };

    public render() {
        const shortcuts =
            this.props.shortcuts === true
                ? createDefaultShortcuts(
                      this.props.allowSingleDayRange,
                      this.props.timePrecision !== undefined,
                      this.props.useSingleDateShortcuts === true,
                  )
                : this.props.shortcuts;

        const shortcutElements = shortcuts.map((shortcut, index) => (
            <MenuItem
                active={this.props.selectedShortcutIndex === index}
                disabled={!this.isShortcutInRange(shortcut.dateRange)}
                key={index}
                onClick={this.getShorcutClickHandler(shortcut, index)}
                shouldDismissPopover={false}
                text={shortcut.label}
            />
        ));

        return (
            <Menu aria-label="Date picker shortcuts" className={Classes.DATERANGEPICKER_SHORTCUTS} tabIndex={0}>
                {shortcutElements}
            </Menu>
        );
    }

    private getShorcutClickHandler = (shortcut: DateRangeShortcut, index: number) => () => {
        const { onShortcutClick } = this.props;

        onShortcutClick(shortcut, index);
    };

    private isShortcutInRange = (shortcutDateRange: DateRange) => {
        const { minDate, maxDate } = this.props;

        return isDayRangeInRange(shortcutDateRange, [minDate, maxDate]);
    };
}

function createShortcut(label: string, dateRange: DateRange): DateRangeShortcut {
    return { dateRange, label };
}

function createDefaultShortcuts(
    allowSingleDayRange: boolean,
    hasTimePrecision: boolean,
    useSingleDateShortcuts: boolean,
) {
    const today = new Date();
    const makeDate = (action: (d: Date) => void) => {
        const returnVal = clone(today);
        action(returnVal);
        returnVal.setDate(returnVal.getDate() + 1);
        return returnVal;
    };

    const tomorrow = makeDate(() => null);
    const yesterday = makeDate(d => d.setDate(d.getDate() - 2));
    const oneWeekAgo = makeDate(d => d.setDate(d.getDate() - 7));
    const oneMonthAgo = makeDate(d => d.setMonth(d.getMonth() - 1));
    const threeMonthsAgo = makeDate(d => d.setMonth(d.getMonth() - 3));
    const sixMonthsAgo = makeDate(d => d.setMonth(d.getMonth() - 6));
    const oneYearAgo = makeDate(d => d.setFullYear(d.getFullYear() - 1));
    const twoYearsAgo = makeDate(d => d.setFullYear(d.getFullYear() - 2));

    const singleDayShortcuts =
        allowSingleDayRange || useSingleDateShortcuts
            ? [
                  createShortcut("Today", [today, hasTimePrecision ? tomorrow : today]),
                  createShortcut("Yesterday", [yesterday, hasTimePrecision ? today : yesterday]),
              ]
            : [];

    return [
        ...singleDayShortcuts,
        createShortcut(useSingleDateShortcuts ? "1 week ago" : "Past week", [oneWeekAgo, today]),
        createShortcut(useSingleDateShortcuts ? "1 month ago" : "Past month", [oneMonthAgo, today]),
        createShortcut(useSingleDateShortcuts ? "3 months ago" : "Past 3 months", [threeMonthsAgo, today]),
        // Don't include a couple of these for the single date shortcut
        ...(useSingleDateShortcuts ? [] : [createShortcut("Past 6 months", [sixMonthsAgo, today])]),
        createShortcut(useSingleDateShortcuts ? "1 year ago" : "Past year", [oneYearAgo, today]),
        ...(useSingleDateShortcuts ? [] : [createShortcut("Past 2 years", [twoYearsAgo, today])]),
    ];
}
