import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { setHours, setMinutes } from 'date-fns';
import {
  Badge,
  Box,
  BulletText,
  Button,
  Card,
  Flex,
  Form,
  Grid,
  Heading,
  Inset,
  toast,
  Typo,
} from '../../atoms';
import { ArrowRightIcon, Cross1Icon } from '../../icon';
import { DatePickerButton, TimeSelect } from '../../molecules';
import { getTimeOption, parseTimeOption } from '../../utils';
import { OnOfflineRadioCard } from './on-offline-radio-card';

type Type = 'onlineCoaching' | 'offlineCoaching';

interface Values {
  date?: Date;
  type?: Type;
}

export interface ReservationCardProps {
  sessionNumber?: number;
  readonly?: boolean;
  defaultTime?: Date;
  defaultType?: Type;
  customerName?: string;
  error?: string;
  onClickCompleteSession?: () => void;
  onClickReserve?: () => void;
  onClickSave?: (values: Values) => void;
  onClickCancel?: () => void;
  minTime?: Date;
  maxTime?: Date;
}

export function ReservationCard(
  props: ReservationCardProps
): React.ReactElement {
  const {
    sessionNumber,
    customerName,
    readonly,
    defaultTime,
    defaultType,
    error,
    minTime,
    maxTime,
    onClickReserve,
    onClickCancel,
    onClickCompleteSession,
  } = props;

  const [editValues, setEditValues] = useState<Values>({
    date: props.defaultTime,
    type: props.defaultType,
  });

  const date = readonly ? defaultTime : editValues.date;
  const type = readonly ? defaultType : editValues.type;
  const time = date && getTimeOption(date);

  const onClickSave = useCallback(() => {
    props.onClickSave?.(editValues);
  }, [editValues, props]);

  const onClickReset = useCallback(() => {
    setEditValues({
      date: defaultTime,
      type: defaultType,
    });
  }, [defaultTime, defaultType]);

  const ActionButtons = useMemo(() => {
    if (readonly) {
      return (
        <Button onClick={onClickReserve} size="small" variant="surface">
          {defaultTime && defaultType ? '예약 수정하기' : '예약하기'}
        </Button>
      );
    }
    return (
      <Button color="gray" onClick={onClickCancel} variant="transparent">
        <Cross1Icon />
      </Button>
    );
  }, [defaultTime, defaultType, onClickCancel, onClickReserve, readonly]);

  const onChangeDate = useCallback(
    (newDate: Date | null) => {
      if (!newDate) return;
      const { hour = 0, minute = 0 } = time ? parseTimeOption(time) : {};
      setEditValues((prev) => {
        return {
          ...prev,
          date: setMinutes(setHours(newDate, hour), minute),
        };
      });
    },
    [time]
  );

  const onChangeType = useCallback((newType: string) => {
    setEditValues((prev) => {
      return {
        ...prev,
        type: newType as Type,
      };
    });
  }, []);

  const onChangeTime = useCallback(
    (v?: string) => {
      const { hour, minute } = parseTimeOption(v);
      if (typeof v === 'undefined') {
        setEditValues((prev) => {
          return {
            ...prev,
            date: v,
          };
        });
      }
      setEditValues((prev) => {
        return {
          ...prev,
          date: setMinutes(setHours(date || new Date(), hour), minute),
        };
      });
    },
    [date]
  );

  useEffect(() => {
    if (!minTime || !editValues.date || readonly) return;
    if (editValues.date < minTime) {
      toast.warn('선택 가능한 시간대로 변경되었습니다.');
      setEditValues((prev) => {
        return {
          ...prev,
          date: minTime,
        };
      });
    }
  }, [editValues, minTime, readonly]);

  useEffect(() => {
    if (!maxTime || !editValues.date || readonly) return;
    if (editValues.date > maxTime) {
      toast.warn('선택 가능한 시간대로 변경되었습니다.');
      setEditValues((prev) => {
        return {
          ...prev,
          date: maxTime,
        };
      });
    }
  }, [editValues, maxTime, readonly]);

  return (
    <Card
      error={Boolean(error)}
      size="3"
      style={{ overflow: 'visible', contain: 'initial' }}
    >
      <Flex gap="3" justify="between" mb="5">
        <Grid
          align="center"
          columns={{ initial: '1', xs: 'auto 1fr' }}
          gapY="2"
        >
          <Flex align="center">
            <Heading variant="heading4">
              {customerName || '-'}님 {sessionNumber || '-'}회차 세션
            </Heading>
            <Badge ml="2">다음 세션</Badge>
          </Flex>
          {error ? (
            <BulletText color="red" variant="caption">
              {error}
            </BulletText>
          ) : null}
        </Grid>
        <Flex>{ActionButtons}</Flex>
      </Flex>

      <Box>
        <Form.Root
          onSubmit={(e) => {
            e.preventDefault();
          }}
        >
          <Flex direction="column" gap="5">
            <Form.Field name="date">
              <Form.Label asChild>
                <Heading mb="2" variant="heading5" weight="regular">
                  세션 일자와 시각
                </Heading>
                <Grid columns="1fr auto" gap="4">
                  <DatePickerButton
                    disabled={readonly}
                    maxDate={maxTime}
                    minDate={minTime}
                    onChange={onChangeDate}
                    placeholder="일자를 선택해주세요"
                    selected={date}
                    size="large"
                  />
                  <TimeSelect
                    disabled={readonly}
                    maxTime={maxTime}
                    minTime={minTime}
                    onValueChange={onChangeTime}
                    size="3"
                    time={date}
                    value={time}
                  />
                </Grid>
              </Form.Label>
            </Form.Field>

            <Form.Field name="type">
              <Form.Label asChild>
                <Heading mb="2" variant="heading5" weight="regular">
                  온/오프라인 진행 여부
                </Heading>
              </Form.Label>
              <Form.Control asChild>
                <OnOfflineRadioCard
                  disabled={readonly}
                  onValueChange={onChangeType}
                  size="1"
                  value={type}
                />
              </Form.Control>
            </Form.Field>

            {readonly ? null : (
              <Flex align="center" gap="3" justify="end">
                <Button
                  color="gray"
                  onClick={onClickReset}
                  size="small"
                  variant="transparent"
                >
                  초기화하기
                </Button>
                <Button onClick={onClickSave} size="small">
                  저장하기
                </Button>
              </Flex>
            )}
          </Flex>
        </Form.Root>
      </Box>

      {readonly ? (
        <Inset clip="border-box" side="bottom">
          <Box
            mt="5"
            px="5"
            py="4"
            style={{ backgroundColor: 'var(--accent-a3)' }}
            width="100%"
          >
            <Flex align="center" gap="4" justify="center">
              <Typo>{sessionNumber || '-'}회차 세션을 완료하셨나요?</Typo>
              <Button onClick={onClickCompleteSession} size="small">
                세션 종료하기
                <ArrowRightIcon />
              </Button>
            </Flex>
          </Box>
        </Inset>
      ) : null}
    </Card>
  );
}
