import { useEffect, useState } from 'react';
import { useRoute, useNavigation } from '@react-navigation/native';

import { View } from '@/components/shared/Themed';
import styled from '@emotion/native';
import TimerContent from '@/components/useCases/timer/view/TimerContent';
import FinishContent from '@/components/useCases/timer/view/FinishContent';
import { TimerBgColor } from '@/components/useCases/timer/business/type';
import { Audio } from 'expo-av';
import { Sound } from 'expo-av/build/Audio';
import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake';

interface TimerProps {
  reps: number;
  restTime: number;
  workTime: number;
}

export default function Timer() {
  const navigation = useNavigation();
  const route = useRoute();

  const { reps, restTime, workTime } = route.params as TimerProps;
  const [currentRep, setCurrentRep] = useState<number>(0);
  const [timeLeft, setTimeLeft] = useState<number>(0);
  const [isWorkPhase, setIsWorkPhase] = useState<boolean>(true);
  const [isRunning, setIsRunning] = useState<boolean>(false);
  const [isFinish, setIsFinish] = useState<boolean>(false);
  const [sound, setSound] = useState<Sound>();

  useEffect(() => {
    configureAudio();
    handleStart();
    activateKeepAwakeAsync();
  }, []);

  // when the user exits the screen, desactivate the keepAwake
  useEffect(() => {
    const unsubscribe = navigation.addListener('beforeRemove', (_) => {
      deactivateKeepAwake();
    });

    return unsubscribe;
  }, [navigation]);

  useEffect(() => {
    let timer: NodeJS.Timeout;

    if (isRunning && timeLeft > 0) {
      timer = setTimeout(() => {
        setTimeLeft(timeLeft - 1);
      }, 1000);
    } else if (isRunning && timeLeft === 0) {
      if (currentRep < reps) {
        if (isWorkPhase) {
          // If the work phase is over, move on to the rest phase
          playSound()
          setIsWorkPhase(false);
          setTimeLeft(restTime);
        } else {
          // If the rest phase is complete, move on to the next work phase
          playSound()
          setIsWorkPhase(true);
          setTimeLeft(workTime);
          setCurrentRep(currentRep + 1);
        }
      } else {
        // Done
        playSound();
        setIsRunning(false);
        setIsFinish(true);
      }
    }

    return () => clearTimeout(timer);
  }, [isRunning, timeLeft, currentRep, isWorkPhase, reps, workTime, restTime]);

  const handleStart = () => {
    setCurrentRep(1);
    setIsWorkPhase(true);
    setTimeLeft(workTime);
    setIsRunning(true);
    setIsFinish(false);
  };

  async function configureAudio() {
    await Audio.setAudioModeAsync({
      allowsRecordingIOS: false,
      staysActiveInBackground: false,
      playsInSilentModeIOS: true,
      shouldDuckAndroid: true,
      playThroughEarpieceAndroid: false,
    });
  }

  async function playSound() {
    const { sound } = await Audio.Sound.createAsync(require('../assets/audios/boxingBell.mp3'));
    setSound(sound);

    await sound.playAsync();
  }

  useEffect(() => {
    return sound
      ? () => {
          sound.unloadAsync();
        }
      : undefined;
  }, [sound]);

  const handleContine = () => {
    setIsRunning(true);
  };

  const handleStop = () => {
    setIsRunning(false);
  };

  const renderBgColor: () => TimerBgColor = () => {
    if (isFinish) return 'black';
    if (isWorkPhase) return 'red';

    return 'green';
  }

  return (
    <Container bgColor={renderBgColor()}>
      {isFinish && (
        <FinishContent handleStart={handleStart} />
      )}

      {!isFinish && (
        <TimerContent
          isWorkPhase={isWorkPhase}
          timeLeft={timeLeft}
          reps={reps}
          bgColor={renderBgColor()}
          currentRep={currentRep}
          isRunning={isRunning}
          handleStop={handleStop}
          handleContine={handleContine}
        />
      )}
    </Container>
  );
}

const Container = styled(View)<{ bgColor: TimerBgColor }>(({ theme, bgColor }) => ({
  flex: 1,
  alignItems: 'center',
  justifyContent: 'center',
  backgroundColor: theme.colors[bgColor]
}));
