import React, {useCallback, useEffect} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {FormProvider} from 'react-hook-form';
import {Dialog, Typography} from '@components';
import {useSavePrediction} from '@modules/prodev2/hooks/useSavePrediction';
import {useProdeSnackbar} from '@modules/prodev2/hooks/useProdeSnackbar';
import {
  Match,
  MatchInPrediction,
  Prediction,
  SavePredictionRequest,
} from '@modules/prodev2/interfaces';
import {useTheme} from '@shared/theme';

import {TeamFlag} from '../MatchCard/components/TeamFlag';
import {PenaltySelector} from './components/PenaltySelector';
import {ScoreColumn} from './components/ScoreColumn';
import {styles} from './styles';
import {usePredictionForm} from './usePredictionForm';
import {buildMatchTitle, decrementScore, incrementScore} from './utils';

export interface Props {
  isOpen: boolean;
  onClose: () => void;
  competitionId: number;
  match: Nullable<Match | MatchInPrediction>;
  existingPrediction?: Nullable<Prediction>;
}

export function PredictionModal({
  isOpen,
  onClose,
  competitionId,
  match,
  existingPrediction,
}: Props) {
  const {t} = useTranslation();
  const {theme} = useTheme();
  const {enqueueSnackbar} = useProdeSnackbar();
  const saveMutation = useSavePrediction(competitionId);

  const methods = usePredictionForm({isOpen, existingPrediction});
  const homeScore = methods.watch('predictedHomeScore');
  const awayScore = methods.watch('predictedAwayScore');
  const penaltyWinnerId = methods.watch('predictedQualifierId');

  const isKnockout = match?.stageType === 'KNOCKOUT';
  const isDraw =
    homeScore !== null && awayScore !== null && homeScore === awayScore;
  const requiresPenaltyWinner = isKnockout && isDraw;
  const hasScoresSet = homeScore !== null && awayScore !== null;

  useEffect(() => {
    if (!isDraw && penaltyWinnerId !== null) {
      methods.setValue('predictedQualifierId', null);
    }
  }, [isDraw, penaltyWinnerId, methods]);

  const onIncrement = useCallback(
    (team: 'home' | 'away') => () => {
      const field =
        team === 'home' ? 'predictedHomeScore' : 'predictedAwayScore';
      const current = methods.getValues(field);
      methods.setValue(field, incrementScore(current), {shouldDirty: true});
    },
    [methods],
  );

  const onDecrement = useCallback(
    (team: 'home' | 'away') => () => {
      const field =
        team === 'home' ? 'predictedHomeScore' : 'predictedAwayScore';
      const current = methods.getValues(field);
      methods.setValue(field, decrementScore(current), {shouldDirty: true});
    },
    [methods],
  );

  const onSelectPenaltyWinner = useCallback(
    (teamId: number) => {
      methods.setValue('predictedQualifierId', teamId, {shouldDirty: true});
    },
    [methods],
  );

  const onSubmit = methods.handleSubmit(values => {
    if (!match) return;
    if (
      values.predictedHomeScore === null ||
      values.predictedAwayScore === null
    ) {
      return;
    }

    const request: SavePredictionRequest = {
      matchId: match.id,
      predictedHomeScore: values.predictedHomeScore,
      predictedAwayScore: values.predictedAwayScore,
    };
    if (requiresPenaltyWinner && values.predictedQualifierId) {
      request.predictedQualifierId = values.predictedQualifierId;
    }

    saveMutation.mutate(request, {
      onSuccess: () => {
        enqueueSnackbar({
          title: t('sportsPool.prediction.saved'),
          variant: 'success',
        });
        onClose();
      },
      onError: () => {
        enqueueSnackbar({
          title: t('sportsPool.prediction.error'),
          variant: 'error',
        });
      },
    });
  });

  const hasChanges = existingPrediction
    ? homeScore !== existingPrediction.predictedHomeScore ||
      awayScore !== existingPrediction.predictedAwayScore ||
      penaltyWinnerId !== existingPrediction.predictedQualifierId
    : hasScoresSet;

  const canSave =
    hasScoresSet &&
    hasChanges &&
    (!requiresPenaltyWinner || penaltyWinnerId !== null);

  return match ? (
    <Dialog
      isVisible={isOpen}
      onClose={onClose}
      title={buildMatchTitle(match, t)}
      titleNumberOfLines={2}
      wrapperType="view"
      footer={{
        primaryButton: {
          text: t('sportsPool.prediction.save'),
          onPress: onSubmit,
          disabled: !canSave || saveMutation.isPending,
          isLoading: saveMutation.isPending,
        },
      }}>
      <FormProvider {...methods}>
        <View style={styles.body}>
          <View style={styles.scoreRow}>
            <View style={styles.teamColumn}>
              <TeamFlag team={match.homeTeam} />
            </View>
            <ScoreColumn
              field="predictedHomeScore"
              value={homeScore}
              onIncrement={onIncrement('home')}
              onDecrement={onDecrement('home')}
            />
            <Typography
              variant="xs"
              weight="semiBold"
              color={theme.text.neutral.lighter}>
              {t('sportsPool.matches.vs')}
            </Typography>
            <ScoreColumn
              field="predictedAwayScore"
              value={awayScore}
              onIncrement={onIncrement('away')}
              onDecrement={onDecrement('away')}
            />
            <View style={styles.teamColumn}>
              <TeamFlag team={match.awayTeam} />
            </View>
          </View>
          {requiresPenaltyWinner && match.homeTeam && match.awayTeam && (
            <PenaltySelector
              homeTeam={match.homeTeam}
              awayTeam={match.awayTeam}
              penaltyWinnerId={penaltyWinnerId}
              onSelect={onSelectPenaltyWinner}
            />
          )}
        </View>
      </FormProvider>
    </Dialog>
  ) : null;
}

export default PredictionModal;
