import {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useState,
} from 'react';
import {ListRenderItem, ScrollView, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {KeyboardController} from 'react-native-keyboard-controller';
import {IconInbox} from '@tabler/icons-react-native';
import {useQuery} from 'react-query';
import {SafeAreaView} from 'react-native-safe-area-context';
import {BadgeIconButton, Chip, Coachmark, InputSearch, List} from '@components';
import {useDebounce} from '@hooks/useDebounce';
import {Navigation} from '@interfaces/navigation';
import {TIME_TRACKING_QUERY_KEYS} from '@modules/timeTracking/constants';
import {
  EmployeeStatus,
  Incidence,
  UserDaySummaries,
} from '@modules/timeTracking/interfaces';
import {getOvertimeRequests} from '@modules/timeTracking/services';
import {
  useApprovalsCoachmark,
  useControlModuleNotifications,
  useGetControlModule,
  useTimeTrackingGrants,
} from '@modules/timeTracking/hooks';
import {useUserId} from '@redux/selectors';
import {useTheme} from '@shared/theme';
import {AMPLITUDE_EVENTS, Screens} from '@shared/constants';
import {
  isBefore,
  isSameDay,
  logAmplitudeEvent,
  simpleDateStringToLocalDate,
} from '@shared/utils';

import DaySelector from './components/DaySelector';
import EmployeeTable from './components/EmployeeTable';
import EmptyComponent from './components/EmptyComponent';
import {
  ALL_OVERTIME_REQUESTS_PARAMS,
  ChipFilter,
  ChipKey,
  CustomChipKey,
  getChipFilters,
  INCIDENCE_TO_CHIP_MAPPER,
} from './constants';
import {styles} from './styles';

const keyExtractor = (item: UserDaySummaries) => `${item.userId}`;

function ControlModule({
  navigation,
  route: {params},
}: Navigation<Screens.CONTROL_MODULE>) {
  const {dateString, fromPush, incidenceType, userId} = params ?? {};
  const parsedDateString = useMemo(
    () => (dateString ? simpleDateStringToLocalDate(dateString) : new Date()),
    [dateString],
  );
  const {t} = useTranslation();
  const {theme} = useTheme();
  const managerId = useUserId();
  const {manageTimeTracking: isAdmin} = useTimeTrackingGrants();
  const [chipFilters, setChipFilters] = useState<ChipFilter[]>(
    getChipFilters(parsedDateString),
  );
  const [selectedDay, setSelectedDay] = useState(parsedDateString);
  const debouncedSelectedDay = useDebounce(selectedDay);
  const [selectedChips, setSelectedChips] = useState<ChipKey[]>([
    incidenceType
      ? INCIDENCE_TO_CHIP_MAPPER[incidenceType] || CustomChipKey.ALL
      : CustomChipKey.ALL,
  ]);
  const debouncedSelectedChips = useDebounce(selectedChips);
  const [searchText, setSearchText] = useState('');
  const debouncedSearch = useDebounce(searchText);
  const [openedEmployeeId, setOpenedEmployeeId] = useState<Nullable<number>>(
    userId || null,
  );
  const {
    data,
    isLoading,
    isFetchingNextPage,
    hasNextPage,
    isRefreshing,
    getNextPage,
  } = useGetControlModule(
    debouncedSelectedDay,
    debouncedSearch,
    debouncedSelectedChips,
  );

  useEffect(() => {
    if (incidenceType) {
      logAmplitudeEvent(
        AMPLITUDE_EVENTS.TIME_TRACKING_INCIDENCE_NOTIFICATION_OPENED,
        {
          incidenceType,
          managerId,
          source: fromPush ? 'push' : 'notification_center',
        },
      );
    }
  }, [fromPush, incidenceType, managerId]);

  const {pendingOvertimeRequests} = useControlModuleNotifications();

  const {data: allOvertimeRequests, isLoading: isLoadingAllOvertimeRequests} =
    useQuery(TIME_TRACKING_QUERY_KEYS.allOvertimeRequestsAmount, () =>
      getOvertimeRequests(ALL_OVERTIME_REQUESTS_PARAMS),
    );

  const showOvertimeRequests = isAdmin || (allOvertimeRequests?.count ?? 0) > 0;

  const {coachmarkSteps, isCoachmarkVisible, onCloseCoachmark} =
    useApprovalsCoachmark({
      showOvertimeRequests,
      isLoadingAllOvertimeRequests,
    });

  useLayoutEffect(() => {
    const onIconPress = () => navigation.navigate(Screens.OVERTIME_REQUESTS);
    const headerRight = () => (
      <BadgeIconButton
        containerStyle={styles.headerRight}
        Icon={IconInbox}
        onIconPress={onIconPress}
        value={pendingOvertimeRequests}
        variant="secondary"
      />
    );
    navigation.setOptions({
      headerRight: showOvertimeRequests ? headerRight : undefined,
    });
  }, [navigation, pendingOvertimeRequests, showOvertimeRequests]);

  const onItemPress = useCallback(
    (cUserId: number) => () => {
      KeyboardController.dismiss();
      setOpenedEmployeeId(prev => (prev === cUserId ? null : cUserId));
    },
    [],
  );

  const renderItem: ListRenderItem<UserDaySummaries> = useCallback(
    ({item}) => (
      <EmployeeTable
        user={item}
        selectedDay={debouncedSelectedDay}
        isOpened={item.userId === openedEmployeeId}
        onPress={onItemPress(item.userId)}
      />
    ),
    [debouncedSelectedDay, onItemPress, openedEmployeeId],
  );

  const onDayChange = useCallback((day: Date) => {
    setSelectedDay(day);

    const newChipFilters = getChipFilters(day);
    setChipFilters(newChipFilters);

    setSelectedChips(prevSelectedChips => {
      const currentDay = new Date();
      const isPast = isBefore(day, currentDay);
      const isPresent = isSameDay(day, currentDay);
      const newSelectedChips = prevSelectedChips.reduce<ChipKey[]>(
        (acc, chip) => {
          if (newChipFilters.some(filter => filter.key === chip)) {
            acc.push(chip);
            return acc;
          }
          if (chip === EmployeeStatus.NOT_CLOCKED_IN && isPast) {
            acc.push(Incidence.ABSENT);
          } else if (chip === Incidence.ABSENT && isPresent) {
            acc.push(EmployeeStatus.NOT_CLOCKED_IN);
          }
          return acc;
        },
        [],
      );
      return newSelectedChips.length ? newSelectedChips : [CustomChipKey.ALL];
    });
  }, []);

  const onChipPress = useCallback(
    (chip: ChipKey) => () => {
      if (chip === CustomChipKey.ALL) {
        setSelectedChips([chip]);
        return;
      }
      setSelectedChips(prevChips => {
        if (prevChips.includes(chip)) {
          const next = prevChips.filter(current => current !== chip);
          return next.length ? next : [CustomChipKey.ALL];
        }
        return [...prevChips, chip].filter(
          current => current !== CustomChipKey.ALL,
        );
      });
    },
    [],
  );

  return (
    <SafeAreaView
      edges={['bottom']}
      style={[
        styles.container,
        {
          backgroundColor: theme.background.layout.default,
          borderTopColor: theme.border.neutral.default,
        },
      ]}>
      <View style={styles.headerContainer}>
        <DaySelector initialDay={parsedDateString} onDayChange={onDayChange} />
        <InputSearch
          placeholder={t('general.search')}
          value={searchText}
          onChangeText={setSearchText}
        />
        <ScrollView
          horizontal
          contentContainerStyle={styles.chipsContainer}
          showsHorizontalScrollIndicator={false}>
          {chipFilters.map(chip => (
            <Chip
              active={selectedChips.includes(chip.key)}
              key={chip.key}
              onPress={onChipPress(chip.key)}
              size="sm"
              text={t(chip.label)}
            />
          ))}
        </ScrollView>
      </View>
      <List
        data={data}
        keyboardShouldPersistTaps="handled"
        keyExtractor={keyExtractor}
        isRefreshing={isRefreshing}
        style={styles.listContainer}
        isLoading={isLoading || !data}
        isFetchingNextPage={isFetchingNextPage}
        onNextPage={getNextPage}
        hasNextPage={hasNextPage}
        renderItem={renderItem}
        ListEmptyComponent={
          <EmptyComponent
            hasFilters={
              !!debouncedSearch.length ||
              debouncedSelectedChips.some(c => c !== CustomChipKey.ALL)
            }
            isLoading={isLoading}
          />
        }
        showsVerticalScrollIndicator={false}
        withRefresh={false}
      />
      {showOvertimeRequests && (
        <Coachmark
          steps={coachmarkSteps}
          isVisible={isCoachmarkVisible}
          onClose={onCloseCoachmark}
          title={t('time_tracker.approval_coachmark.step1_title')}
        />
      )}
    </SafeAreaView>
  );
}

export default ControlModule;
