import { useEffect, useRef, useState } from 'react';

import { Box, Flex, IconButton, SliderTrack, Text } from '@chakra-ui/react';
import {
  MdFastForward,
  MdFastRewind,
  MdLooksOne,
  MdNavigateBefore,
  MdNavigateNext,
  MdPause,
  MdPlayArrow,
  MdRepeat,
  MdRepeatOne,
  MdStop,
  MdTrendingFlat,
} from 'react-icons/md';

import { useColorModeValue } from '@/components/ui/color-mode';
import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { useSpecificMedia } from '@/service/Media';
import { useSpecificSeason } from '@/service/Season';
import { useSpecificSeries } from '@/service/Series';
import { useSpecificType } from '@/service/Type';
import { DataUrlAccess } from '@/utils/data-url-access';
import { isNullOrUndefined } from '@/utils/validator';

import { Slider } from './ui/slider';

export enum PlayMode {
  PLAY_ONE,
  PLAY_ALL,
  PLAY_ONE_LOOP,
  PLAY_ALL_LOOP,
}

const playModeIcon = {
  [PlayMode.PLAY_ONE]: <MdLooksOne style={{ width: '100%', height: '100%' }} />,
  [PlayMode.PLAY_ALL]: (
    <MdTrendingFlat style={{ width: '100%', height: '100%' }} />
  ),
  [PlayMode.PLAY_ONE_LOOP]: (
    <MdRepeatOne style={{ width: '100%', height: '100%' }} />
  ),
  [PlayMode.PLAY_ALL_LOOP]: (
    <MdRepeat style={{ width: '100%', height: '100%' }} />
  ),
};

export type AudioPlayerProps = {};

const formatTime = (time) => {
  if (time && !isNaN(time)) {
    const minutes = Math.floor(time / 60);
    const formatMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
    const seconds = Math.floor(time % 60);
    const formatSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
    return `${formatMinutes}:${formatSeconds}`;
  }
  return '00:00';
};

export const AudioPlayer = ({}: AudioPlayerProps) => {
  const { playMediaList, MediaOffset, previous, next, first } =
    useActivePlaylistService();
  const audioRef = useRef<HTMLAudioElement>(null);
  const [isPlaying, setIsPlaying] = useState<boolean>(false);
  const [timeProgress, setTimeProgress] = useState<number>(0);
  const [playingMode, setPlayingMode] = useState<PlayMode>(PlayMode.PLAY_ALL);
  const [duration, setDuration] = useState<number>(0);
  const { dataMedia } = useSpecificMedia(
    MediaOffset !== undefined ? playMediaList[MediaOffset] : undefined
  );
  const { dataSeason } = useSpecificSeason(dataMedia?.seasonId);
  const { dataType } = useSpecificType(dataMedia?.typeId);
  const { dataSeries } = useSpecificSeries(dataMedia?.seriesId);

  const [mediaSource, setMediaSource] = useState<string>('');
  useEffect(() => {
    setMediaSource(
      dataMedia && dataMedia?.dataId
        ? DataUrlAccess.getUrl(dataMedia?.dataId)
        : ''
    );
  }, [dataMedia, setMediaSource]);
  const backColor = useColorModeValue('back.100', 'back.800');
  const configButton = {
    borderRadius: 'full',
    backgroundColor: 'transparent',
    _hover: {
      bgColor: 'brand.500',
    },
    width: '50px',
    height: '50px',
    padding: '5px',
  };

  useEffect(() => {
    if (!audioRef || !audioRef.current) {
      return;
    }
    if (isPlaying) {
      audioRef.current.play();
    } else {
      audioRef.current.pause();
    }
  }, [isPlaying, audioRef]);

  const onAudioEnded = () => {
    if (playMediaList.length === 0 || isNullOrUndefined(MediaOffset)) {
      return;
    }
    if (playingMode === PlayMode.PLAY_ALL_LOOP) {
      if (playMediaList.length == MediaOffset + 1) {
        first();
      } else {
        next();
      }
    } else if (playingMode === PlayMode.PLAY_ALL) {
      next();
    } else if (playingMode === PlayMode.PLAY_ONE_LOOP) {
      onSeek(0);
      onPlay();
    }
  };
  const onSeek = (newValue) => {
    console.log(`onSeek: ${newValue}`);
    if (!audioRef || !audioRef.current) {
      return;
    }
    audioRef.current.currentTime = newValue;
  };
  const onPlay = () => {
    if (!audioRef || !audioRef.current) {
      return;
    }
    if (isPlaying) {
      audioRef.current.pause();
    } else {
      audioRef.current.play();
    }
  };
  const onStop = () => {
    if (!audioRef || !audioRef.current) {
      return;
    }
    if (audioRef.current.currentTime == 0 && audioRef.current.paused) {
      // TODO remove current playing value
    } else {
      audioRef.current.pause();
      audioRef.current.currentTime = 0;
    }
  };
  const onNavigatePrevious = () => {
    previous();
  };
  const onFastRewind = () => {
    if (!audioRef || !audioRef.current) {
      return;
    }
    audioRef.current.currentTime -= 10;
  };
  const onFastForward = () => {
    if (!audioRef || !audioRef.current) {
      return;
    }
    audioRef.current.currentTime += 10;
  };
  const onNavigateNext = () => {
    next();
  };
  const onTypePlay = () => {
    setPlayingMode((value: PlayMode) => {
      if (value === PlayMode.PLAY_ONE) {
        return PlayMode.PLAY_ALL;
      } else if (value === PlayMode.PLAY_ALL) {
        return PlayMode.PLAY_ONE_LOOP;
      } else if (value === PlayMode.PLAY_ONE_LOOP) {
        return PlayMode.PLAY_ALL_LOOP;
      } else {
        return PlayMode.PLAY_ONE;
      }
    });
  };
  /**
   * Call when meta-data is updated
   */
  function onChangeMetadata(): void {
    const seconds = audioRef.current?.duration;
    if (seconds !== undefined) {
      setDuration(seconds);
    }
  }
  const onTimeUpdate = () => {
    if (!audioRef || !audioRef.current) {
      return;
    }
    console.log(`onTimeUpdate ${audioRef.current.currentTime}`);
    setTimeProgress(audioRef.current.currentTime);
  };
  const onDurationChange = (event) => {};
  const onChangeStateToPlay = () => {
    setIsPlaying(true);
  };
  const onChangeStateToPause = () => {
    setIsPlaying(false);
  };
  const marks = () => {
    const minutes = Math.floor(duration / 60);
    const result: number[] = [];
    for (let i = 1; i <= minutes; i++) {
      result.push(60 * i);
    }
    return result;
  };
  return (
    <>
      {!isNullOrUndefined(MediaOffset) && (
        <Flex
          position="absolute"
          height="150px"
          minHeight="150px"
          paddingY="5px"
          paddingX="10px"
          marginX="15px"
          bottom={0}
          left={0}
          right={0}
          zIndex={1000}
          borderWidth="1px"
          borderColor="brand.900"
          bgColor={backColor}
          borderTopRadius="10px"
          direction="column"
        >
          <Text
            alignContent="left"
            fontSize="20px"
            fontWeight="bold"
            userSelect="none"
            marginRight="auto"
            overflow="hidden"
            // noOfLines={1}
          >
            {dataMedia?.name ?? '???'}
          </Text>
          <Text
            alignContent="left"
            fontSize="16px"
            userSelect="none"
            marginRight="auto"
            overflow="hidden"
            // noOfLines={1}
          >
            {dataSeries && dataSeries.name}
            {dataSeason && dataSeason?.name}
            {dataType && ` / ${dataType.name}`}
          </Text>
          <Box width="full" paddingX="15px">
            <Slider
              defaultValue={[0]}
              value={[timeProgress]}
              min={0}
              max={duration}
              step={0.1}
              onValueChange={(e) => onSeek(e.value)}
              variant="outline"
              colorPalette="brand"
              marks={marks()}
              //focusCapture={false}
            >
              <SliderTrack
                bg="brand.200"
                height="10px"
                borderRadius="full"
              ></SliderTrack>
            </Slider>
          </Box>
          <Flex>
            <Text
              alignContent="left"
              fontSize="16px"
              userSelect="none"
              marginRight="auto"
              overflow="hidden"
              // noOfLines={1}
            >
              {formatTime(timeProgress)}
            </Text>
            <Text alignContent="left" fontSize="16px" userSelect="none">
              {formatTime(duration)}
            </Text>
          </Flex>
          <Flex gap="5px">
            <IconButton
              {...configButton}
              aria-label={'Play'}
              onClick={onPlay}
              variant="ghost"
            >
              {isPlaying ? (
                <MdPause style={{ width: '100%', height: '100%' }} />
              ) : (
                <MdPlayArrow style={{ width: '100%', height: '100%' }} />
              )}
            </IconButton>
            <IconButton
              {...configButton}
              aria-label={'Stop'}
              onClick={onStop}
              variant="ghost"
            >
              <MdStop style={{ width: '100%', height: '100%' }} />
            </IconButton>
            <IconButton
              {...configButton}
              aria-label={'Previous Media'}
              onClick={onNavigatePrevious}
              marginLeft="auto"
              variant="ghost"
            >
              <MdNavigateBefore style={{ width: '100%', height: '100%' }} />{' '}
            </IconButton>
            <IconButton
              {...configButton}
              aria-label={'jump 15sec in past'}
              onClick={onFastRewind}
              variant="ghost"
            >
              <MdFastRewind style={{ width: '100%', height: '100%' }} />
            </IconButton>
            <IconButton
              {...configButton}
              aria-label={'jump 15sec in future'}
              onClick={onFastForward}
              variant="ghost"
            >
              <MdFastForward style={{ width: '100%', height: '100%' }} />
            </IconButton>
            <IconButton
              {...configButton}
              aria-label={'Next Media'}
              marginRight="auto"
              onClick={onNavigateNext}
              variant="ghost"
            >
              <MdNavigateNext style={{ width: '100%', height: '100%' }} />
            </IconButton>
            <IconButton
              {...configButton}
              aria-label={'continue to the end'}
              onClick={onTypePlay}
              variant="ghost"
            >
              {playModeIcon[playingMode]}
            </IconButton>
          </Flex>
        </Flex>
      )}

      <audio
        src={mediaSource}
        ref={audioRef}
        //preload={true}
        onPlay={onChangeStateToPlay}
        onPause={onChangeStateToPause}
        onTimeUpdate={onTimeUpdate}
        onDurationChange={onDurationChange}
        onLoadedMetadata={onChangeMetadata}
        autoPlay={true}
        onEnded={onAudioEnded}
      />
    </>
  );
};
