import React, { ReactElement, useMemo } from 'react';
import {
  getHours,
  getMinutes,
  getSeconds,
  setHours,
  setMinutes,
  setSeconds,
} from 'date-fns';

import PanelColumn, { Unit } from './PanelColumn';
import { PanelContainer } from './StyledTimePicker';
import assert from '../../utils/assert';

import { leftPad } from './utils';

const supportedMinuteSteps = [1, 5, 10, 15, 20, 30, 60] as const;

type MinuteStep = typeof supportedMinuteSteps[number];

export type PanelContentProps = {
  minuteStep: MinuteStep;
  onSelect: (val: Date) => void;
  resolvedValue: Date | undefined;
  with12Hours: boolean;
  withSeconds: boolean;
};

const PanelContent = (props: PanelContentProps): ReactElement => {
  const {
    resolvedValue,
    with12Hours,
    withSeconds,
    onSelect,
    minuteStep,
  } = props;
  assert(
    supportedMinuteSteps.includes(minuteStep),
    `minuteStep ${minuteStep} is not supported`
  );

  const setTime = (
    isNewPM: boolean,
    newHour: number,
    newMinute: number,
    newSecond: number
  ): Date => {
    let newDate = new Date();

    newDate = setHours(
      setMinutes(setSeconds(newDate, newSecond), newMinute),
      !with12Hours || !isNewPM ? newHour : newHour + 12
    );

    return newDate;
  };

  const currentTime = resolvedValue !== undefined ? resolvedValue : new Date();
  const rawHour = getHours(currentTime);
  const minute = getMinutes(currentTime);
  const second = getSeconds(currentTime);

  const isPM: boolean = with12Hours ? rawHour >= 12 : false;
  const hour = with12Hours ? rawHour % 12 : rawHour;

  const rawHours: Unit[] = useMemo(
    () =>
      Array.from(new Array(24), (_, i) => {
        return { label: leftPad(i, 2), value: i };
      }),
    []
  );

  const hours = useMemo(() => {
    if (!with12Hours) return rawHours;
    // Re-generate hours for AM/PM
    return rawHours
      .filter(
        isPM ? (h): boolean => h.value >= 12 : (h): boolean => h.value < 12
      )
      .map(h => {
        const hourValue = h.value % 12;
        const hourLabel = hourValue === 0 ? '12' : leftPad(hourValue, 2);
        return {
          ...h,
          label: hourLabel,
          value: hourValue,
        };
      });
  }, [with12Hours, isPM, rawHours]);

  const minutes: Unit[] = useMemo(
    () =>
      Array.from(new Array(60 / minuteStep), (_, i) => {
        return { label: leftPad(i * minuteStep, 2), value: i * minuteStep };
      }),
    [minuteStep]
  );
  const seconds: Unit[] = useMemo(
    () =>
      Array.from(new Array(60), (_, i) => {
        return { label: leftPad(i, 2), value: i };
      }),
    []
  );

  return (
    <PanelContainer>
      <PanelColumn
        key="hour"
        value={hour}
        units={hours}
        onSelect={(newValue): void =>
          onSelect(setTime(isPM, newValue, minute, second))
        }
      />
      <PanelColumn
        key="minute"
        value={minute}
        units={minutes}
        onSelect={(newValue): void =>
          onSelect(setTime(isPM, hour, newValue, second))
        }
      />
      {withSeconds === true && (
        <PanelColumn
          key="second"
          value={second}
          units={seconds}
          onSelect={(newValue): void =>
            onSelect(setTime(isPM, hour, minute, newValue))
          }
        />
      )}
      {with12Hours === true && (
        <PanelColumn
          key="12hours"
          value={isPM ? 1 : 0}
          units={[
            { label: 'AM', value: 0 },
            { label: 'PM', value: 1 },
          ]}
          onSelect={(newValue): void =>
            onSelect(setTime(newValue !== 0, hour, minute, second))
          }
        />
      )}
    </PanelContainer>
  );
};

export default PanelContent;
