import React, { useContext, useRef } from "react";
import moment, { Moment } from "moment";
import { DateTable, DateTableProps } from "./tables/DateTable";
import { ControlledProps } from "../form/controlled";
import { CellStatus } from "./tables/BaseTable";
import { MonthTable } from "./tables/MonthTable";
import { FadeTransition } from "../transition/FadeTransition";
import { YearTable } from "./tables/YearTable";
import { QuarterTable } from "./tables/QuarterTable";
import { TimeDisabledProps } from "../timepicker/TimeProps";
import { TimeTable } from "../timepicker/TimeTable";
import { useTranslation } from "../i18n";
import {
  RangeDateType,
  showTimeType,
  CalendarTableType,
  DateChangeContext,
} from "./DateProps";
import { RangePickerContext } from "../datepicker/RangePickerContext";
import { isAfter, isBefore, isSame } from "../datepicker/util";

export interface CalendarTableProps
  extends ControlledProps<
    Moment | RangeDateType,
    React.SyntheticEvent,
    DateChangeContext
  > {
  /**
   * 允许选择的时间范围限制
   */
  range?: RangeDateType;

  /**
   * 不可选的日期
   */
  disabledDate?: (date: Moment, startDate?: Moment) => boolean;

  /**
   * 不可选的月份
   * @since 2.5.0
   */
  disabledMonth?: (date: Moment, startDate?: Moment) => boolean;

  /**
   * 不可选的季度
   */
  disabledQuarter?: (date: Moment, startDate?: Moment) => boolean;

  /**
   * 不可选的时间
   */
  disabledTime?: (
    date: Moment | RangeDateType,
    partial?: "start" | "end"
  ) => TimeDisabledProps;

  /**
   * 是否开启时间选择
   */
  showTime?: showTimeType<Moment>;

  /**
   * 当前展示日期
   */
  curViewMoment?: Moment;

  /**
   * 当前展示日期改变回调
   */
  onCurViewMomentChange?: DateTableProps["onCurrentChange"];

  /**
   * 当前展示的日历类型
   */
  type: CalendarTableType;

  /**
   * 日历类型改变回调
   */
  onTypeChange?: (types: CalendarTableType) => void;

  /**
   * 作为范围选择部分时的位置
   */
  rangeType?: "start" | "end";

  /**
   * 是否只选择到月份
   */
  monthOnly?: boolean;

  /**
   * 当前 Hover 的日期
   */
  hovered?: Moment;

  /**
   * 当前 Hover 的日期
   */
  onHoveredChange?: DateTableProps["onCurrentChange"];
}

/**
 * 获取当前时间选择范围
 */
export function getTimeRange(
  value: Moment,
  range: RangeDateType = [null, null]
): RangeDateType {
  if (!Array.isArray(range) || !value) {
    return undefined;
  }
  const [min, max] = range;
  const timeRange: RangeDateType = [
    moment().startOf("day"),
    moment().endOf("day"),
  ];
  if (moment.isMoment(min) && isSame(value, min, "day")) {
    timeRange[0] = min;
  }
  if (moment.isMoment(max) && isSame(value, max, "day")) {
    timeRange[1] = max;
  }
  return timeRange;
}

export function CalendarTable({
  value,
  onChange,
  type,
  onTypeChange,
  curViewMoment = moment(),
  onCurViewMomentChange,
  range,
  disabledDate = () => true,
  disabledMonth = () => true,
  disabledQuarter = () => true,
  disabledTime = () => ({}),
  showTime,
  rangeType,
  monthOnly,
  hovered,
  ...props
}: CalendarTableProps) {
  const t = useTranslation();
  const { range: rangePickerRange } = useContext(RangePickerContext);

  // 记录 Table 切换
  const prevTypeRef = useRef<CalendarTableType>(null);
  const prevType = prevTypeRef.current;
  if (type === "month" || type === "date" || type === "quarter") {
    prevTypeRef.current = type;
  }

  const tableProps = {
    ...props,
    range,
    onTypeChange,
    current: curViewMoment,
    onCurrentChange: onCurViewMomentChange,
  };

  const timeProps = typeof showTime === "object" ? showTime : {};

  function getValue(): Moment {
    if (!Array.isArray(value)) {
      return value;
    }
    if (rangeType === "start") {
      return value[0];
    }
    return value[1];
  }

  function getCellStatus(date: Moment, type: "date" | "month" | "quarter") {
    // 单日选择
    if (!Array.isArray(value)) {
      if (moment.isMoment(value) && isSame(date, value, type)) {
        return CellStatus.Selected;
      }
      return CellStatus.Common;
    }
    // 范围选择
    if (moment.isMoment(value[0]) && isSame(date, value[0], type)) {
      // 只选中了开始或开始结束在同一天返回 Selected
      if (!moment.isMoment(value[1])) {
        return CellStatus.Selected;
      }
      if (isSame(value[0], value[1], type)) {
        return CellStatus.Selected;
      }
      return CellStatus.RangeStart;
    }
    if (moment.isMoment(value[1]) && isSame(date, value[1], type)) {
      return CellStatus.RangeEnd;
    }
    if (moment.isMoment(value[0]) && moment.isMoment(value[1])) {
      if (isBefore(value[0], date) && isAfter(value[1], date)) {
        return CellStatus.InRange;
      }
    }
    if (
      moment.isMoment(value[0]) &&
      !moment.isMoment(value[1]) &&
      moment.isMoment(hovered)
    ) {
      if (isBefore(value[0], date) && isAfter(hovered, date)) {
        return CellStatus.InRangeHover;
      }
      if (isBefore(hovered, date) && isAfter(value[0], date)) {
        return CellStatus.InRangeHover;
      }
    }
    return CellStatus.Common;
  }

  return (
    <>
      {/* Year */}
      <FadeTransition in={type === "year"} exit={false}>
        <YearTable
          {...tableProps}
          onSelect={value => {
            onCurViewMomentChange(moment(curViewMoment).year(value.year()));
            onTypeChange(prevType || (monthOnly ? "date" : "month"));
          }}
          cellStatus={date => {
            if (!Array.isArray(value)) {
              if (moment.isMoment(value) && isSame(date, value, "year")) {
                return CellStatus.Selected;
              }
            }
            return CellStatus.Common;
          }}
        />
      </FadeTransition>

      {/* Quarter */}
      <FadeTransition in={type === "quarter"} exit={false}>
        <QuarterTable
          {...tableProps}
          onSelect={(newValue, context) => {
            onCurViewMomentChange(
              moment(curViewMoment).quarter(newValue.quarter())
            );

            context.type = "quarter";
            if (!Array.isArray(value)) {
              return onChange(newValue, context);
            }
            // 范围选择
            if (moment.isMoment(value[0]) && !moment.isMoment(value[1])) {
              if (isBefore(value[0], newValue)) {
                return onChange([value[0], newValue], context);
              }
              return onChange([newValue, value[0]], context);
            }
            return onChange([newValue, null], context);
          }}
          cellStatus={date => getCellStatus(date, "quarter")}
          disabledQuarter={disabledQuarter}
        />
      </FadeTransition>

      {/* Month */}
      <FadeTransition in={type === "month"} exit={false}>
        <MonthTable
          {...tableProps}
          onSelect={(newValue, context) => {
            onCurViewMomentChange(
              moment(curViewMoment).month(newValue.month())
            );
            if (monthOnly) {
              context.type = "quarter";
              if (!Array.isArray(value)) {
                return onChange(newValue, context);
              }
              // 范围选择
              if (moment.isMoment(value[0]) && !moment.isMoment(value[1])) {
                if (isBefore(value[0], newValue)) {
                  return onChange([value[0], newValue], context);
                }
                return onChange([newValue, value[0]], context);
              }
              return onChange([newValue, null], context);
            }
            return onTypeChange("date");
          }}
          cellStatus={date => getCellStatus(date, "month")}
          disabledMonth={disabledMonth}
        />
      </FadeTransition>

      {/* Date */}
      <FadeTransition in={type === "date"} exit={false}>
        <DateTable
          {...tableProps}
          value={getValue()}
          disabledDate={(date: Moment) => {
            // 范围选择已选择 start，未选择 end
            if (
              Array.isArray(value) &&
              moment.isMoment(value[0]) &&
              !moment.isMoment(value[1])
            ) {
              return disabledDate(date, value[0]);
            }
            return disabledDate(date);
          }}
          onSelect={(v, context) => {
            // 单日选择
            context.type = "date";
            if (!Array.isArray(value)) {
              return onChange(v, context);
            }
            // 范围选择
            if (moment.isMoment(value[0]) && !moment.isMoment(value[1])) {
              if (isBefore(value[0], v)) {
                return onChange([value[0], v], context);
              }
              return onChange([v, value[0]], context);
            }
            return onChange([v, null], context);
          }}
          cellStatus={date => getCellStatus(date, "date")}
        />
      </FadeTransition>

      {/* Time */}
      <FadeTransition in={type === "time"} exit={false}>
        <TimeTable
          caption={
            moment.isMoment(getValue()) ? getValue().format("L") : t.selectTime
          }
          value={getValue()}
          onChange={(v, context) => {
            context.type = "time";
            // 日期选择完才可选择时间，所以 value 必定合法
            if (!Array.isArray(value)) {
              return onChange(v, context);
            }
            if (rangeType === "start") {
              return onChange([v, value[1]], context);
            }
            return onChange([value[0], v], context);
          }}
          range={getTimeRange(getValue(), rangePickerRange || range)}
          {...(disabledTime(value, rangeType) || {})}
          {...timeProps}
        />
      </FadeTransition>
    </>
  );
}

CalendarTable.displayName = "CalendarTable";
