import Select from '../select';
import { Group, Button } from '../radio';
import type { CalendarMode, SelectInfo } from './generateCalendar';
import type { Ref } from 'vue';
import { defineComponent, ref } from 'vue';
import type { Locale } from '../vc-picker/interface';
import type { GenerateConfig } from '../vc-picker/generate';
import { FormItemInputContext } from '../form/FormItemContext';

const YearSelectOffset = 10;
const YearSelectTotal = 20;

interface SharedProps<DateType> {
  prefixCls: string;
  value: DateType;
  validRange?: [DateType, DateType];
  generateConfig: GenerateConfig<DateType>;
  locale: Locale;
  fullscreen: boolean;
  divRef: Ref<HTMLDivElement>;
  onChange: (year: DateType) => void;
}

function YearSelect<DateType>(props: SharedProps<DateType>) {
  const { fullscreen, validRange, generateConfig, locale, prefixCls, value, onChange, divRef } =
    props;

  const year = generateConfig.getYear(value || generateConfig.getNow());

  let start = year - YearSelectOffset;
  let end = start + YearSelectTotal;

  if (validRange) {
    start = generateConfig.getYear(validRange[0]);
    end = generateConfig.getYear(validRange[1]) + 1;
  }

  const suffix = locale && locale.year === '年' ? '年' : '';
  const options: { label: string; value: number }[] = [];
  for (let index = start; index < end; index++) {
    options.push({ label: `${index}${suffix}`, value: index });
  }
  return (
    <Select
      size={fullscreen ? undefined : 'small'}
      options={options}
      value={year}
      class={`${prefixCls}-year-select`}
      onChange={(numYear: number) => {
        let newDate = generateConfig.setYear(value, numYear);

        if (validRange) {
          const [startDate, endDate] = validRange;
          const newYear = generateConfig.getYear(newDate);
          const newMonth = generateConfig.getMonth(newDate);
          if (
            newYear === generateConfig.getYear(endDate) &&
            newMonth > generateConfig.getMonth(endDate)
          ) {
            newDate = generateConfig.setMonth(newDate, generateConfig.getMonth(endDate));
          }
          if (
            newYear === generateConfig.getYear(startDate) &&
            newMonth < generateConfig.getMonth(startDate)
          ) {
            newDate = generateConfig.setMonth(newDate, generateConfig.getMonth(startDate));
          }
        }

        onChange(newDate);
      }}
      getPopupContainer={() => divRef!.value!}
    />
  );
}
YearSelect.inheritAttrs = false;

function MonthSelect<DateType>(props: SharedProps<DateType>) {
  const { prefixCls, fullscreen, validRange, value, generateConfig, locale, onChange, divRef } =
    props;
  const month = generateConfig.getMonth(value || generateConfig.getNow());

  let start = 0;
  let end = 11;

  if (validRange) {
    const [rangeStart, rangeEnd] = validRange;
    const currentYear = generateConfig.getYear(value);
    if (generateConfig.getYear(rangeEnd) === currentYear) {
      end = generateConfig.getMonth(rangeEnd);
    }
    if (generateConfig.getYear(rangeStart) === currentYear) {
      start = generateConfig.getMonth(rangeStart);
    }
  }

  const months = locale.shortMonths || generateConfig.locale.getShortMonths!(locale.locale);
  const options: { label: string; value: number }[] = [];
  for (let index = start; index <= end; index += 1) {
    options.push({
      label: months[index],
      value: index,
    });
  }

  return (
    <Select
      size={fullscreen ? undefined : 'small'}
      class={`${prefixCls}-month-select`}
      value={month}
      options={options}
      onChange={(newMonth: number) => {
        onChange(generateConfig.setMonth(value, newMonth));
      }}
      getPopupContainer={() => divRef!.value!}
    />
  );
}

MonthSelect.inheritAttrs = false;

interface ModeSwitchProps<DateType> extends Omit<SharedProps<DateType>, 'onChange'> {
  mode: CalendarMode;
  onModeChange: (type: CalendarMode) => void;
}

function ModeSwitch<DateType>(props: ModeSwitchProps<DateType>) {
  const { prefixCls, locale, mode, fullscreen, onModeChange } = props;
  return (
    <Group
      onChange={({ target: { value } }) => {
        onModeChange(value);
      }}
      value={mode}
      size={fullscreen ? undefined : 'small'}
      class={`${prefixCls}-mode-switch`}
    >
      <Button value="month">{locale.month}</Button>
      <Button value="year">{locale.year}</Button>
    </Group>
  );
}
ModeSwitch.inheritAttrs = false;

export interface CalendarHeaderProps<DateType> {
  prefixCls: string;
  value: DateType;
  validRange?: [DateType, DateType];
  generateConfig: GenerateConfig<DateType>;
  locale: Locale;
  mode: CalendarMode;
  fullscreen: boolean;
  onChange: (date: DateType, source: SelectInfo['source']) => void;
  onModeChange: (mode: CalendarMode) => void;
}

export default defineComponent<CalendarHeaderProps<any>>({
  name: 'CalendarHeader',
  inheritAttrs: false,
  props: [
    'mode',
    'prefixCls',
    'value',
    'validRange',
    'generateConfig',
    'locale',
    'mode',
    'fullscreen',
  ] as any,
  setup(_props, { attrs }) {
    const divRef = ref<HTMLDivElement>(null);
    const formItemInputContext = FormItemInputContext.useInject();
    FormItemInputContext.useProvide(formItemInputContext, { isFormItemInput: false });

    return () => {
      const props = { ..._props, ...attrs };
      const { prefixCls, fullscreen, mode, onChange, onModeChange } = props;
      const sharedProps = {
        ...props,
        fullscreen,
        divRef,
      } as any;

      return (
        <div class={`${prefixCls}-header`} ref={divRef}>
          <YearSelect
            {...sharedProps}
            onChange={v => {
              onChange(v, 'year');
            }}
          />
          {mode === 'month' && (
            <MonthSelect
              {...sharedProps}
              onChange={v => {
                onChange(v, 'month');
              }}
            />
          )}
          <ModeSwitch {...sharedProps} onModeChange={onModeChange} />
        </div>
      );
    };
  },
});