import React, {useState, useEffect, useMemo, useCallback} from 'react';
import {View, TouchableOpacity, StyleSheet, Platform} from 'react-native';
import {Calendar} from 'react-native-calendars';
import DateTimePicker, {
  DateTimePickerEvent,
} from '@react-native-community/datetimepicker';
import moment from 'moment';
import PlayyText from '../PlayyText/PlayyText';
import {useTheme, ColorsScheme} from '../../theme/ThemeContext';
import {SPACING_8, SPACING_16} from '../Spacing/Spacing';
import {GLYPHS} from '../Glyphs';
import CardView from '../Card/CardView';

interface DateSelectorProps {
  selectedDate: Date;
  onDateChange: (date: Date) => void;
  minimumDate?: Date;
  maximumDate?: Date;
  showHeader?: boolean;
  headerTitle?: string;
  locale?: string;
  cardViewStyle?: object;
  dateFormat?: string;
}

const DateSelector: React.FC<DateSelectorProps> = ({
  selectedDate,
  onDateChange,
  minimumDate = moment().subtract(100, 'years').toDate(),
  maximumDate = new Date(),
  showHeader = true,
  headerTitle,
  locale = 'en_US',
  cardViewStyle,
  dateFormat = 'MMMM YYYY',
}) => {
  const {colors} = useTheme();
  const styles = useMemo(() => themedStyle(colors || {}), [colors]);

  const [currentMonth, setCurrentMonth] = useState<Date>(selectedDate);
  const [showMonthPicker, setShowMonthPicker] = useState(false);

  // Update currentMonth when selectedDate changes externally
  useEffect(() => {
    setCurrentMonth(selectedDate);
  }, [selectedDate]);

  // Memoize formatted dates to avoid recalculations
  const formattedDates = useMemo(
    () => ({
      current: moment(currentMonth).format('YYYY-MM-DD'),
      currentMonth: moment(currentMonth).format('YYYY-MM'),
      selected: moment(selectedDate).format('YYYY-MM-DD'),
      max: moment(maximumDate).format('YYYY-MM-DD'),
      min: moment(minimumDate).format('YYYY-MM-DD'),
      headerTitle: moment(currentMonth).format(dateFormat),
    }),
    [currentMonth, selectedDate, maximumDate, minimumDate, dateFormat],
  );

  // Memoize calendar theme to prevent recreation
  const calendarTheme = useMemo(
    () => ({
      calendarBackground: colors.background_grouped_secondary,
      textSectionTitleColor: colors.labels_tertiary,
      selectedDayTextColor: colors.blue,
      todayTextColor: colors.labels_primary,
      dayTextColor: colors.labels_primary,
      textDisabledColor: colors.labels_secondary,
      dotColor: colors.labels_primary,
      selectedDotColor: colors.red,
      arrowColor: colors.labels_primary,
      monthTextColor: colors.labels_primary,
      indicatorColor: colors.red,
      textDayFontFamily: 'Playy',
      textMonthFontFamily: 'Playy',
      textDayHeaderFontFamily: 'Playy',
      textDayFontWeight: '400' as const,
      textMonthFontWeight: '500' as const,
      textDayHeaderFontWeight: '400' as const,
      textDayFontSize: 16,
      textMonthFontSize: 16,
      textDayHeaderFontSize: 13,
    }),
    [colors],
  );

  // Memoize marked dates
  const markedDates = useMemo(
    () => ({
      [formattedDates.selected]: {
        selected: true,
        selectedColor: colors.blue_50,
      },
    }),
    [formattedDates.selected, colors.blue_50],
  );

  const onCalendarDateSelect = useCallback(
    (date: string) => {
      const selectedCalendarDate = new Date(date);
      onDateChange(selectedCalendarDate);
    },
    [onDateChange],
  );

  const handleMonthChange = useCallback(
    (event: DateTimePickerEvent, date?: Date) => {
      if (date) {
        setCurrentMonth(date);
      }
    },
    [],
  );

  const toggleMonthPicker = useCallback(() => {
    setShowMonthPicker(prev => !prev);
  }, []);

  const navigateToPreviousMonth = useCallback(() => {
    const prevMonth = moment(currentMonth).subtract(1, 'month');
    const minDate = moment(minimumDate);
    if (prevMonth.isAfter(minDate) || prevMonth.isSame(minDate, 'month')) {
      setCurrentMonth(prevMonth.toDate());
    }
  }, [currentMonth, minimumDate]);

  const navigateToNextMonth = useCallback(() => {
    const nextMonth = moment(currentMonth).add(1, 'month');
    const maxDate = moment(maximumDate);
    if (nextMonth.isBefore(maxDate) || nextMonth.isSame(maxDate, 'month')) {
      setCurrentMonth(nextMonth.toDate());
    }
  }, [currentMonth, maximumDate]);

  return (
    <CardView cardViewStyle={cardViewStyle || styles.card}>
      {showHeader && (
        <View style={styles.customHeader}>
          <TouchableOpacity
            style={styles.headerLeft}
            onPress={toggleMonthPicker}
            accessibilityLabel="Toggle month picker"
            accessibilityRole="button">
            <PlayyText BodyEmphasized color={colors.text_primary}>
              {headerTitle || formattedDates.headerTitle}
            </PlayyText>
            <PlayyText FootnoteEmphasized color={colors.blue}>
              {showMonthPicker
                ? GLYPHS['chevron-down-strong'].char
                : GLYPHS['chevron-right-strong'].char}
            </PlayyText>
          </TouchableOpacity>
          <View style={styles.headerRight}>
            <TouchableOpacity
              style={[styles.arrowButton, {opacity: showMonthPicker ? 0 : 1}]}
              disabled={showMonthPicker}
              onPress={navigateToPreviousMonth}
              accessibilityLabel="Previous month"
              accessibilityRole="button">
              <PlayyText BodyEmphasized color={colors.blue}>
                {GLYPHS['chevron-left-strong'].char}
              </PlayyText>
            </TouchableOpacity>
            <TouchableOpacity
              style={[styles.arrowButton, {opacity: showMonthPicker ? 0 : 1}]}
              disabled={showMonthPicker}
              onPress={navigateToNextMonth}
              accessibilityLabel="Next month"
              accessibilityRole="button">
              <PlayyText BodyEmphasized color={colors.blue}>
                {GLYPHS['chevron-right-strong'].char}
              </PlayyText>
            </TouchableOpacity>
          </View>
        </View>
      )}

      {!showMonthPicker ? (
        <Calendar
          key={formattedDates.currentMonth}
          current={formattedDates.current}
          onDayPress={(day: {dateString: string}) =>
            onCalendarDateSelect(day.dateString)
          }
          maxDate={formattedDates.max}
          minDate={formattedDates.min}
          markedDates={markedDates}
          hideArrows={true}
          hideExtraDays={true}
          renderHeader={() => null}
          theme={calendarTheme}
        />
      ) : (
        <View style={styles.dateTimePickerContainer}>
          <DateTimePicker
            value={currentMonth || new Date()}
            mode="date"
            onChange={handleMonthChange}
            display={Platform.OS === 'ios' ? 'spinner' : 'default'}
            minimumDate={minimumDate}
            maximumDate={maximumDate}
            locale={locale}
            themeVariant={
              colors.background_primary === 'rgba(0, 0, 0, 1)'
                ? 'dark'
                : 'light'
            }
          />
        </View>
      )}
    </CardView>
  );
};

const themedStyle = (colors: ColorsScheme) =>
  StyleSheet.create({
    customHeader: {
      flexDirection: 'row',
      justifyContent: 'space-between',
      alignItems: 'center',
      paddingVertical: 12,
    },
    headerLeft: {
      flex: 1,
      flexDirection: 'row',
      gap: 4,
      alignItems: 'center',
    },
    headerRight: {
      flexDirection: 'row',
      alignItems: 'center',
      gap: 28,
    },
    arrowButton: {
      alignItems: 'center',
      justifyContent: 'center',
      minWidth: 44,
      minHeight: 44,
    },
    dateTimePickerContainer: {
      paddingVertical: SPACING_16,
      alignItems: 'center',
    },
    card: {
      paddingVertical: SPACING_8,
      paddingHorizontal: SPACING_16,
    },
  });

export default DateSelector;
