import * as React from 'react';
import classNames from 'classnames';
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import SwapRightOutlined from '@ant-design/icons/SwapRightOutlined';
import { RangePicker as RCRangePicker } from 'rc-picker';
import { GenerateConfig } from 'rc-picker/lib/generate/index';
import enUS from '../locale/en_US';
import { ConfigContext, ConfigConsumerProps } from '../../config-provider';
import SizeContext from '../../config-provider/SizeContext';
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
import { getRangePlaceholder } from '../util';
import { RangePickerProps, PickerLocale, getTimeProps, Components } from '.';
import { EventValue } from 'rc-picker/lib/interface';

export default function generateRangePicker<DateType>(
  generateConfig: GenerateConfig<DateType>,
): React.ComponentClass<RangePickerProps<DateType>> {
  class RangePicker extends React.Component<RangePickerProps<DateType>> {
    static contextType = ConfigContext;

    context: ConfigConsumerProps;

    pickerRef = React.createRef<RCRangePicker<DateType>>();

    focus = () => {
      if (this.pickerRef.current) {
        this.pickerRef.current.focus();
      }
    };

    blur = () => {
      if (this.pickerRef.current) {
        this.pickerRef.current.blur();
      }
    };

    renderPicker = (contextLocale: PickerLocale) => {
      const locale = { ...contextLocale, ...this.props.locale };
      const { getPrefixCls, direction, getPopupContainer } = this.context;
      const {
        prefixCls: customizePrefixCls,
        getPopupContainer: customGetPopupContainer,
        className,
        size: customizeSize,
        bordered = true,
        placeholder,
        ...restProps
      } = this.props;
      const { format, showTime, picker } = this.props as any;
      const prefixCls = getPrefixCls('picker', customizePrefixCls);

      let additionalOverrideProps: any = {};

      additionalOverrideProps = {
        ...additionalOverrideProps,
        ...(showTime ? getTimeProps({ format, picker, ...showTime }) : {}),
        ...(picker === 'time' ? getTimeProps({ format, ...this.props, picker }) : {}),
      };
      const rootPrefixCls = getPrefixCls();

      return (
        <SizeContext.Consumer>
          {size => {
            const mergedSize = customizeSize || size;

            return (
              <RCRangePicker<DateType>
                separator={
                  <span aria-label="to" className={`${prefixCls}-separator`}>
                    <SwapRightOutlined />
                  </span>
                }
                ref={this.pickerRef}
                placeholder={getRangePlaceholder(picker, locale, placeholder)}
                suffixIcon={picker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
                clearIcon={<CloseCircleFilled />}
                allowClear
                transitionName={`${rootPrefixCls}-slide-up`}
                {...restProps}
                {...additionalOverrideProps}
                // 转换 onChange，与 antd 的行为不同
                onChange={(dates, dateStrings) => {
                  if (restProps.onChange) {
                    if ((!picker || picker === 'date') && !showTime) {
                      const resultDates = dates
                        ? dates.map((item: any, index) =>
                            index === 0 ? item.startOf('day') : item.endOf('day'),
                          )
                        : null;
                      restProps.onChange(
                        resultDates as [EventValue<DateType>, EventValue<DateType>] | null,
                        dateStrings,
                      );
                    } else if (picker === 'week') {
                      const resultDates = dates
                        ? dates.map((item: any, index) =>
                            index === 0 ? item.startOf('week') : item.endOf('week'),
                          )
                        : null;
                      restProps.onChange(
                        resultDates as [EventValue<DateType>, EventValue<DateType>] | null,
                        dateStrings,
                      );
                    } else if (picker === 'month') {
                      const resultDates = dates
                        ? dates.map((item: any, index) =>
                            index === 0 ? item.startOf('month') : item.endOf('month'),
                          )
                        : null;
                      restProps.onChange(
                        resultDates as [EventValue<DateType>, EventValue<DateType>] | null,
                        dateStrings,
                      );
                    } else if (picker === 'quarter') {
                      const resultDates = dates
                        ? dates.map((item: any, index) =>
                            index === 0 ? item.startOf('quarter') : item.endOf('quarter'),
                          )
                        : null;
                      restProps.onChange(
                        resultDates as [EventValue<DateType>, EventValue<DateType>] | null,
                        dateStrings,
                      );
                    } else if (picker === 'year') {
                      const resultDates = dates
                        ? dates.map((item: any, index) =>
                            index === 0 ? item.startOf('year') : item.endOf('year'),
                          )
                        : null;
                      restProps.onChange(
                        resultDates as [EventValue<DateType>, EventValue<DateType>] | null,
                        dateStrings,
                      );
                    } else {
                      restProps.onChange(dates, dateStrings);
                    }
                  }
                }}
                className={classNames(
                  {
                    [`${prefixCls}-${mergedSize}`]: mergedSize,
                    [`${prefixCls}-borderless`]: !bordered,
                  },
                  className,
                )}
                locale={locale!.lang}
                prefixCls={prefixCls}
                getPopupContainer={customGetPopupContainer || getPopupContainer}
                generateConfig={generateConfig}
                prevIcon={<span className={`${prefixCls}-prev-icon`} />}
                nextIcon={<span className={`${prefixCls}-next-icon`} />}
                superPrevIcon={<span className={`${prefixCls}-super-prev-icon`} />}
                superNextIcon={<span className={`${prefixCls}-super-next-icon`} />}
                components={Components}
                direction={direction}
              />
            );
          }}
        </SizeContext.Consumer>
      );
    };

    render() {
      return (
        <LocaleReceiver componentName="DatePicker" defaultLocale={enUS}>
          {this.renderPicker}
        </LocaleReceiver>
      );
    }
  }

  return RangePicker;
}
