import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {
  NativeScrollEvent,
  NativeSyntheticEvent,
  ScrollView,
  View,
} from 'react-native';
import {useTranslation} from 'react-i18next';
import {useWatch} from 'react-hook-form';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {
  BackButton,
  Button,
  HeaderSection,
  InputSearch,
  Spinner,
  Typography,
} from '@components';
import {useDebounce} from '@hooks/useDebounce';
import {useSafeAreaBottomPadding} from '@hooks/useSafeAreaBottomPadding';
import {Navigation} from '@interfaces/navigation';
import {SEARCH_DEBOUNCE_MS, prodeKeys} from '@modules/prodev2/constants';
import {useProdeSnackbar} from '@modules/prodev2/hooks/useProdeSnackbar';
import {useSaveTournamentPrediction} from '@modules/prodev2/hooks/useSaveTournamentPrediction';
import {useTeams} from '@modules/prodev2/hooks/useTeams';
import {getTournamentPrediction} from '@modules/prodev2/services';
import {TeamWithGroup} from '@modules/prodev2/interfaces';
import {
  PodiumPosition,
  PodiumSlot,
} from '@modules/prodev2/components/PodiumSlot';
import {predictionTeamToTeamWithGroup} from '@modules/prodev2/utils';
import {useQuery} from '@shared/hooks/queries-v5/useQuery';
import {useTheme} from '@shared/theme';
import {Screens} from '@shared/constants';

import {TeamRow} from './components/TeamRow';
import {styles} from './styles';
import {usePodiumForm} from './usePodiumForm';

const PODIUM_ICONS: Record<PodiumPosition, string> = {
  champion: '🏆',
  runnerUp: '🥈',
  thirdPlace: '🥉',
};

const PODIUM_NUMBERS: Record<PodiumPosition, number> = {
  champion: 1,
  runnerUp: 2,
  thirdPlace: 3,
};

const PODIUM_LABEL_KEYS: Record<PodiumPosition, string> = {
  champion: 'sportsPool.podium.champion',
  runnerUp: 'sportsPool.podium.runner_up',
  thirdPlace: 'sportsPool.podium.third_place',
};

export default function Podium({
  navigation,
  route: {
    params: {competitionId},
  },
}: Navigation<Screens.PRODEV2_PODIUM>) {
  const {t} = useTranslation();
  const {theme, iconSizes} = useTheme();
  const {top} = useSafeAreaInsets();
  const bottomSafePadding = useSafeAreaBottomPadding();
  const {enqueueSnackbar} = useProdeSnackbar();

  const [searchQuery, setSearchQuery] = useState('');
  const debouncedSearch = useDebounce(searchQuery, SEARCH_DEBOUNCE_MS);
  const trimmedSearch = debouncedSearch.trim();

  const [activeSlot, setActiveSlot] = useState<PodiumPosition>('champion');
  const [selectedTeams, setSelectedTeams] = useState<
    Record<PodiumPosition, Nullable<TeamWithGroup>>
  >({
    champion: null,
    runnerUp: null,
    thirdPlace: null,
  });

  const {data: tournamentPrediction} = useQuery(
    prodeKeys.tournamentPrediction(competitionId),
    () => getTournamentPrediction(competitionId),
    {enabled: !!competitionId},
  );
  const existingPrediction = tournamentPrediction?.prediction ?? null;

  const formMethods = usePodiumForm({existingPrediction});
  const {control, handleSubmit, setValue, formState} = formMethods;

  const formValues = useWatch({control});
  const championTeamId = formValues.championTeamId ?? null;
  const runnerUpTeamId = formValues.runnerUpTeamId ?? null;
  const thirdPlaceTeamId = formValues.thirdPlaceTeamId ?? null;

  useEffect(() => {
    if (!existingPrediction) {
      setSelectedTeams({champion: null, runnerUp: null, thirdPlace: null});
      setActiveSlot('champion');
      return;
    }

    setSelectedTeams({
      champion: predictionTeamToTeamWithGroup(existingPrediction.championTeam),
      runnerUp: predictionTeamToTeamWithGroup(existingPrediction.runnerUpTeam),
      thirdPlace: predictionTeamToTeamWithGroup(
        existingPrediction.thirdPlaceTeam,
      ),
    });

    if (!existingPrediction.championTeam) setActiveSlot('champion');
    else if (!existingPrediction.runnerUpTeam) setActiveSlot('runnerUp');
    else if (!existingPrediction.thirdPlaceTeam) setActiveSlot('thirdPlace');
    else setActiveSlot('champion');
  }, [existingPrediction]);

  const {
    data: teams,
    isLoading: isTeamsLoading,
    getNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useTeams(competitionId, trimmedSearch || undefined);

  const slotIdByPosition: Record<PodiumPosition, Nullable<number>> = useMemo(
    () => ({
      champion: championTeamId,
      runnerUp: runnerUpTeamId,
      thirdPlace: thirdPlaceTeamId,
    }),
    [championTeamId, runnerUpTeamId, thirdPlaceTeamId],
  );

  const isTeamSelected = useCallback(
    (teamId: number) =>
      championTeamId === teamId ||
      runnerUpTeamId === teamId ||
      thirdPlaceTeamId === teamId,
    [championTeamId, runnerUpTeamId, thirdPlaceTeamId],
  );

  const allSlotsFilled =
    !!championTeamId && !!runnerUpTeamId && !!thirdPlaceTeamId;

  const setSlot = useCallback(
    (position: PodiumPosition, team: Nullable<TeamWithGroup>) => {
      const fieldName =
        position === 'champion'
          ? 'championTeamId'
          : position === 'runnerUp'
          ? 'runnerUpTeamId'
          : 'thirdPlaceTeamId';
      setValue(fieldName, team ? team.id : null, {shouldValidate: true});
      setSelectedTeams(prev => ({...prev, [position]: team}));
    },
    [setValue],
  );

  const removeTeam = useCallback(
    (position: PodiumPosition) => {
      setSlot(position, null);
      setActiveSlot(position);
    },
    [setSlot],
  );

  const onSelectTeam = useCallback(
    (team: TeamWithGroup) => {
      if (championTeamId === team.id) {
        removeTeam('champion');
        return;
      }
      if (runnerUpTeamId === team.id) {
        removeTeam('runnerUp');
        return;
      }
      if (thirdPlaceTeamId === team.id) {
        removeTeam('thirdPlace');
        return;
      }

      const targetPosition: PodiumPosition = !slotIdByPosition[activeSlot]
        ? activeSlot
        : !championTeamId
        ? 'champion'
        : !runnerUpTeamId
        ? 'runnerUp'
        : !thirdPlaceTeamId
        ? 'thirdPlace'
        : activeSlot;

      setSlot(targetPosition, team);

      if (targetPosition === 'champion' && !runnerUpTeamId) {
        setActiveSlot('runnerUp');
      } else if (targetPosition === 'runnerUp' && !thirdPlaceTeamId) {
        setActiveSlot('thirdPlace');
      } else if (targetPosition === 'thirdPlace' && !championTeamId) {
        setActiveSlot('champion');
      }
    },
    [
      activeSlot,
      championTeamId,
      removeTeam,
      runnerUpTeamId,
      setSlot,
      slotIdByPosition,
      thirdPlaceTeamId,
    ],
  );

  const onBack = useCallback(() => {
    if (navigation.canGoBack()) {
      navigation.goBack();
    }
  }, [navigation]);

  const {mutate: savePrediction, isPending: isSaving} =
    useSaveTournamentPrediction(competitionId);

  const onSubmit = handleSubmit(values => {
    if (
      !values.championTeamId ||
      !values.runnerUpTeamId ||
      !values.thirdPlaceTeamId
    ) {
      return;
    }
    savePrediction(
      {
        championTeamId: values.championTeamId,
        runnerUpTeamId: values.runnerUpTeamId,
        thirdPlaceTeamId: values.thirdPlaceTeamId,
      },
      {
        onSuccess: () => {
          enqueueSnackbar({
            title: t('sportsPool.podium.saved_title'),
            description: t('sportsPool.podium.saved_description'),
            variant: 'success',
          });
          onBack();
        },
        onError: () => {
          enqueueSnackbar({
            title: t('sportsPool.podium.error_title'),
            description: t('sportsPool.podium.error_description'),
            variant: 'error',
          });
        },
      },
    );
  });

  const onScroll = useCallback(
    (event: NativeSyntheticEvent<NativeScrollEvent>) => {
      if (!hasNextPage || isFetchingNextPage) return;
      const {layoutMeasurement, contentOffset, contentSize} = event.nativeEvent;
      const distanceFromBottom =
        contentSize.height - (contentOffset.y + layoutMeasurement.height);
      if (distanceFromBottom < 200) {
        getNextPage();
      }
    },
    [getNextPage, hasNextPage, isFetchingNextPage],
  );

  const renderPodiumSlot = useCallback(
    (position: PodiumPosition) => (
      <PodiumSlot
        position={position}
        team={selectedTeams[position]}
        label={t(PODIUM_LABEL_KEYS[position])}
        icon={
          <Typography style={{fontSize: iconSizes.x4}}>
            {PODIUM_ICONS[position]}
          </Typography>
        }
        number={PODIUM_NUMBERS[position]}
        isSelected={activeSlot === position}
        onSelect={() => setActiveSlot(position)}
        onRemove={() => removeTeam(position)}
      />
    ),
    [activeSlot, iconSizes.x4, removeTeam, selectedTeams, t],
  );

  const hasResults = (teams?.length ?? 0) > 0;

  return (
    <View
      style={[
        styles.container,
        !!top && {paddingTop: top},
        {backgroundColor: theme.background.layout.tertiary},
      ]}>
      <HeaderSection
        leftComponent={<BackButton onPress={onBack} />}
        title={t('sportsPool.podium.modal_title')}
      />
      <ScrollView
        style={[
          styles.content,
          {backgroundColor: theme.background.layout.default},
        ]}
        contentContainerStyle={styles.scrollContent}
        onScroll={onScroll}
        scrollEventThrottle={16}
        keyboardShouldPersistTaps="handled"
        showsVerticalScrollIndicator={false}>
        <View style={styles.podiumSection}>
          <View style={styles.slotsRow}>
            {renderPodiumSlot('champion')}
            {renderPodiumSlot('runnerUp')}
            {renderPodiumSlot('thirdPlace')}
          </View>
          {!!formState.errors.root?.message && (
            <Typography variant="xs" color={theme.text.feedback.error}>
              {formState.errors.root.message}
            </Typography>
          )}
        </View>

        <View style={styles.countriesSection}>
          <Typography variant="m" weight="semiBold">
            {t('sportsPool.podium.countries')}
          </Typography>
          <InputSearch
            value={searchQuery}
            onChangeText={setSearchQuery}
            placeholder={t('sportsPool.podium.search_placeholder')}
          />
          <View
            style={[
              styles.listCard,
              {
                backgroundColor: theme.background.elements.default,
                borderColor: theme.border.neutral.default,
              },
            ]}>
            {isTeamsLoading && !hasResults ? (
              <View style={styles.listFooter}>
                <Spinner />
              </View>
            ) : hasResults ? (
              teams.map(team => (
                <TeamRow
                  key={team.id}
                  team={team}
                  isSelected={isTeamSelected(team.id)}
                  isDisabled={allSlotsFilled && !isTeamSelected(team.id)}
                  onPress={onSelectTeam}
                />
              ))
            ) : (
              <View style={styles.listEmpty}>
                <Typography variant="s" color={theme.text.neutral.lighter}>
                  {t('sportsPool.podium.no_results')}
                </Typography>
              </View>
            )}
            {isFetchingNextPage && (
              <View style={styles.listFooter}>
                <Spinner />
              </View>
            )}
          </View>
        </View>
      </ScrollView>
      <View
        style={[
          styles.footer,
          {
            paddingBottom: bottomSafePadding,
            backgroundColor: theme.background.layout.default,
            borderColor: theme.border.neutral.default,
          },
        ]}>
        <Button
          text={t('sportsPool.podium.save')}
          onPress={onSubmit}
          disabled={!allSlotsFilled || isSaving}
          isLoading={isSaving}
        />
        <Button
          text={t('sportsPool.podium.close')}
          onPress={onBack}
          variant="tertiary"
        />
      </View>
    </View>
  );
}
