import type { CalendarOptions, DatesSetArg } from '@fullcalendar/core';
import allLocales from '@fullcalendar/core/locales-all';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import FullCalendar from '@fullcalendar/react';

import { ActionButton } from '@lib/components/ActionButton';
import { Boundary } from '@lib/components/Boundary';
import { SearchInput } from '@lib/components/SearchInput';
import { StylishText } from '@lib/components/StylishText';
import type { TableFilter } from '@lib/types/Filters';
import { t } from '@lingui/core/macro';
import {
  ActionIcon,
  Box,
  Button,
  Group,
  Indicator,
  LoadingOverlay,
  Popover,
  Stack,
  Tooltip
} from '@mantine/core';
import { type DateValue, MonthPicker } from '@mantine/dates';
import {
  IconCalendarMonth,
  IconChevronLeft,
  IconChevronRight,
  IconDownload,
  IconFilter
} from '@tabler/icons-react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useShallow } from 'zustand/react/shallow';
import {
  defaultLocale,
  getPriorityLocale
} from '../../contexts/LanguageContext';
import type { CalendarState } from '../../hooks/UseCalendar';
import { useLocalState } from '../../states/LocalState';
import { FilterSelectDrawer } from '../../tables/FilterSelectDrawer';

export interface InvenTreeCalendarProps extends CalendarOptions {
  enableDownload?: boolean;
  enableFilters?: boolean;
  enableSearch?: boolean;
  filters?: TableFilter[];
  isLoading?: boolean;
  state: CalendarState;
}

export default function Calendar({
  enableDownload,
  enableFilters = false,
  enableSearch,
  isLoading,
  filters,
  state,
  ...calendarProps
}: Readonly<InvenTreeCalendarProps>) {
  const [monthSelectOpened, setMonthSelectOpened] = useState<boolean>(false);

  const [filtersVisible, setFiltersVisible] = useState<boolean>(false);

  const [locale] = useLocalState(useShallow((s) => [s.language]));

  // Ensure underscore is replaced with dash
  const calendarLocale = useMemo(() => {
    let _locale: string | null = locale;

    if (!_locale) {
      _locale = getPriorityLocale();
    }

    _locale = _locale || defaultLocale;

    _locale = _locale.replace('_', '-');

    return _locale;
  }, [locale]);

  const selectMonth = useCallback(
    (date: DateValue) => {
      state.selectMonth(date);
      setMonthSelectOpened(false);
    },
    [state.selectMonth]
  );

  useEffect(() => {
    // Select initial month on first calendar render
    state.ref?.current?.getApi()?.gotoDate(new Date());
  }, []);

  // Callback when the calendar date range is adjusted
  const datesSet = useCallback(
    (dateInfo: DatesSetArg) => {
      if (state.ref?.current) {
        const api = state.ref.current.getApi();

        // Update calendar state
        state.setMonthName(api.view.title);
        state.setStartDate(dateInfo.start);
        state.setEndDate(dateInfo.end);
      }

      // Pass the dates set to the parent component
      calendarProps.datesSet?.(dateInfo);
    },
    [calendarProps.datesSet, state.ref, state.setMonthName]
  );

  return (
    <>
      {state.exportModal.modal}
      {enableFilters && filters && (filters?.length ?? 0) > 0 && (
        <Boundary label={`InvenTreeCalendarFilterDrawer-${state.name}`}>
          <FilterSelectDrawer
            title={t`Calendar Filters`}
            availableFilters={filters}
            filterSet={state.filterSet}
            opened={filtersVisible}
            onClose={() => setFiltersVisible(false)}
          />
        </Boundary>
      )}
      <Stack gap='xs'>
        <Group justify='space-between' gap='xs'>
          <Group gap={0} justify='left'>
            <ActionButton
              icon={<IconChevronLeft />}
              onClick={state.prevMonth}
              tooltipAlignment='top'
              tooltip={t`Previous month`}
            />
            <Popover
              opened={monthSelectOpened}
              onClose={() => setMonthSelectOpened(false)}
              position='bottom-start'
              shadow='md'
            >
              <Popover.Target>
                <Tooltip label={t`Select month`} position='top'>
                  <Button
                    m={0}
                    variant='transparent'
                    aria-label='calendar-select-month'
                    onClick={() => {
                      setMonthSelectOpened(!monthSelectOpened);
                    }}
                  >
                    <IconCalendarMonth />
                  </Button>
                </Tooltip>
              </Popover.Target>
              <Popover.Dropdown>
                <MonthPicker onChange={selectMonth} />
              </Popover.Dropdown>
            </Popover>
            <ActionButton
              icon={<IconChevronRight />}
              onClick={state.nextMonth}
              tooltipAlignment='top'
              tooltip={t`Next month`}
            />
            <StylishText size='lg'>{state.monthName}</StylishText>
          </Group>
          <Group justify='right' gap='xs' wrap='nowrap'>
            {enableSearch && (
              <SearchInput searchCallback={state.setSearchTerm} />
            )}
            {enableFilters && filters && filters.length > 0 && (
              <Indicator
                size='xs'
                label={state.filterSet.activeFilters?.length ?? 0}
                disabled={state.filterSet.activeFilters?.length == 0}
              >
                <ActionIcon
                  variant='transparent'
                  aria-label='calendar-select-filters'
                >
                  <Tooltip label={t`Calendar Filters`} position='top-end'>
                    <IconFilter
                      onClick={() => setFiltersVisible(!filtersVisible)}
                    />
                  </Tooltip>
                </ActionIcon>
              </Indicator>
            )}
            {enableDownload && (
              <ActionIcon
                variant='transparent'
                aria-label='calendar-export-data'
              >
                <Tooltip label={t`Export data`} position='top-end'>
                  <IconDownload onClick={state.exportModal.open} />
                </Tooltip>
              </ActionIcon>
            )}
          </Group>
        </Group>
        <Box pos='relative'>
          <LoadingOverlay visible={state.query.isFetching} />
          <FullCalendar
            ref={state.ref}
            plugins={[dayGridPlugin, interactionPlugin]}
            initialView='dayGridMonth'
            locales={allLocales}
            locale={calendarLocale}
            headerToolbar={false}
            footerToolbar={false}
            {...calendarProps}
            datesSet={datesSet}
          />
        </Box>
      </Stack>
    </>
  );
}
