import {
  MonthYearPickerDialogueAndroid,
  MonthYearPickerViewIOS,
} from '@hero-design/react-native-month-year-picker';
import format from 'date-fns/fp/format';
import React, { useState } from 'react';
import { Platform, TouchableOpacity } from 'react-native';
import { useTheme } from '../../theme';
import { noop } from '../../utils/functions';
import Box from '../Box';
import ContentNavigator from '../ContentNavigator';
import Icon from '../Icon';
import Typography from '../Typography';
import CalendarRowItem from './CalendarRowItem';
import {
  StyledCalendarDayNameCell,
  StyledCalendarHeader,
  StyledCalendarRow,
  StyledCalendarRowItem,
  StyledContainer,
  StyledDisabledCalendarRowItem,
} from './StyledCalendar';
import {
  getCalendarButtonState,
  getCalendarDate,
  isEqDate,
  shouldUseMonthPicker,
} from './helpers';
import CalendarRange from './CalendarRange';
import { DAYS_OF_WEEK } from './constants';
import type { CalendarProps } from './types';
import { useCalendarLayout } from './shared/hooks/useCalendarLayout';

const Calendar = ({
  value,
  visibleDate,
  onChange,
  onPreviousPress = noop,
  onNextPress = noop,
  onTitlePress = noop,
  minDate,
  maxDate,
  markedDates = [],
  testID,
  onMonthChange = noop,
  onToggleMonthPicker = noop,
  monthPickerConfirmLabel,
  monthPickerCancelLabel,
}: CalendarProps) => {
  const theme = useTheme();
  const { onLayout, contentHeight, contentWidth, calendarItemWidth } =
    useCalendarLayout();
  const {
    parsedMaskedDate,
    daysOfPreviousMonth,
    daysOfCurrentMonth,
    daysOfNextMonth,
  } = getCalendarDate({
    visibleDate,
    markedDates,
    minDate,
    maxDate,
    onMonthChange,
  });
  const { disablePrevButton, disableNextButton } = getCalendarButtonState({
    visibleDate,
    minDate,
    maxDate,
  });
  const shouldShowMonthPicker = shouldUseMonthPicker(onMonthChange);

  const [monthPickerVisible, setMonthPickerVisible] = useState(false);

  const now = new Date();

  return (
    <StyledContainer testID={testID}>
      <StyledCalendarHeader>
        <ContentNavigator
          value={
            !shouldShowMonthPicker ? (
              format('MMMM yyyy', visibleDate)
            ) : (
              <TouchableOpacity
                testID="calendar-month-picker"
                onPress={() => {
                  onToggleMonthPicker?.(!monthPickerVisible);
                  setMonthPickerVisible(!monthPickerVisible);
                }}
              >
                <Box
                  flexDirection="row"
                  justifyContent="center"
                  alignItems="center"
                >
                  <Typography.Title
                    level="h5"
                    style={{
                      textAlign: 'center',
                      marginRight:
                        theme.__hd__.calendar.space.headerMarginRight,
                    }}
                  >
                    {format('MMMM yyyy', visibleDate)}
                  </Typography.Title>

                  <Icon
                    icon={monthPickerVisible ? 'arrow-up' : 'arrow-down'}
                    size="small"
                  />
                </Box>
              </TouchableOpacity>
            )
          }
          onPreviousPress={onPreviousPress}
          onNextPress={onNextPress}
          onPress={shouldShowMonthPicker ? undefined : onTitlePress}
          previousDisabled={disablePrevButton}
          nextDisabled={disableNextButton}
          fontSize="large"
        />
      </StyledCalendarHeader>
      {Platform.OS === 'ios' && monthPickerVisible ? (
        <Box style={{ overflow: 'hidden' }}>
          <MonthYearPickerViewIOS
            value={value}
            minimumDate={minDate}
            maximumDate={maxDate}
            onChange={onMonthChange}
            textColor={theme.colors.onDefaultGlobalSurface}
            style={{
              height:
                contentHeight +
                theme.__hd__.calendar.space.iosPickerMarginVertical * 2,
              marginVertical:
                -theme.__hd__.calendar.space.iosPickerMarginVertical,
              width: contentWidth,
            }}
          />
        </Box>
      ) : (
        <Box onLayout={onLayout}>
          <StyledCalendarRow>
            {DAYS_OF_WEEK.map((day) => (
              <StyledCalendarRowItem key={day}>
                <StyledCalendarDayNameCell themeItemWidth={calendarItemWidth}>
                  <Typography.Body variant="small">{day}</Typography.Body>
                </StyledCalendarDayNameCell>
              </StyledCalendarRowItem>
            ))}
          </StyledCalendarRow>
          <StyledCalendarRow>
            {daysOfPreviousMonth.map((date) =>
              date ? (
                <CalendarRowItem
                  key={date.toDateString()}
                  date={date}
                  isCurrent={isEqDate(now, date)}
                  isSelected={isEqDate(value, date)}
                  onPress={() => onChange?.(date)}
                  textIntent="subdued"
                  marked={parsedMaskedDate[date.toDateString()]}
                  itemWidth={contentWidth > 0 ? contentWidth / 7 : undefined}
                />
              ) : (
                <StyledDisabledCalendarRowItem
                  themeItemWidth={calendarItemWidth}
                  testID="calendar-disabled-cell"
                />
              )
            )}
            {daysOfCurrentMonth.map((date) =>
              date ? (
                <CalendarRowItem
                  itemWidth={calendarItemWidth}
                  key={date.toDateString()}
                  date={date}
                  isCurrent={isEqDate(now, date)}
                  isSelected={isEqDate(value, date)}
                  onPress={() => onChange?.(date)}
                  marked={parsedMaskedDate[date.toDateString()]}
                />
              ) : (
                <StyledDisabledCalendarRowItem
                  themeItemWidth={calendarItemWidth}
                  testID="calendar-disabled-cell"
                />
              )
            )}
            {daysOfNextMonth.map((date) =>
              date ? (
                <CalendarRowItem
                  itemWidth={calendarItemWidth}
                  key={date.toDateString()}
                  date={date}
                  isCurrent={isEqDate(now, date)}
                  isSelected={isEqDate(value, date)}
                  onPress={() => onChange?.(date)}
                  textIntent="subdued"
                  marked={parsedMaskedDate[date.toDateString()]}
                />
              ) : (
                <StyledDisabledCalendarRowItem
                  themeItemWidth={calendarItemWidth}
                  testID="calendar-disabled-cell"
                />
              )
            )}
          </StyledCalendarRow>

          {Platform.OS === 'android' && monthPickerVisible && (
            <MonthYearPickerDialogueAndroid
              themeVariant={theme.themeMode === 'dark' ? 'dark' : 'light'}
              doneButtonLabel={monthPickerConfirmLabel}
              cancelButtonLabel={monthPickerCancelLabel}
              value={value}
              minimumDate={minDate}
              maximumDate={maxDate}
              onChange={(action, date) => {
                setMonthPickerVisible(false);
                onToggleMonthPicker?.(false);

                if (action === 'dateSetAction' && !!date) {
                  onMonthChange(date);
                }
              }}
            />
          )}
        </Box>
      )}
    </StyledContainer>
  );
};

export default Object.assign(Calendar, {
  Range: CalendarRange,
});
