import type { Dispatch, SetStateAction } from 'react'
import {
  useMemo,
  useEffect,
  useState,
} from 'react'

import throttle from 'lodash/throttle'
import isEmpty from 'lodash/isEmpty'
import every from 'lodash/every'
import find from 'lodash/find'
import isUndefined from 'lodash/isUndefined'

import type {
  MatchInfo,
  PlayersStats,
  Player,
} from 'requests'
import { getPlayersStats, getMatchParticipants } from 'requests'

import { useObjectState, usePageParams } from 'hooks'

import type{ PlaylistOption } from 'features/MatchPage/types'
import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config'
import { FULL_GAME_KEY } from 'features/MatchPage/helpers/buildPlaylists'
import { getHalfTime } from 'features/MatchPage/helpers/getHalfTime'

const REQUEST_DELAY = 3000
const STATS_POLL_INTERVAL = 30000

type UsePlayersStatsArgs = {
  matchProfile: MatchInfo,
  playingProgress: number,
  selectedPlaylist?: PlaylistOption,
  setIsPlayersStatsFetching: Dispatch<SetStateAction<boolean>>,
  statsType: StatsType,
}

type PlayersData = {
  team1: Array<Player>,
  team2: Array<Player>,
}

export const usePlayersStats = ({
  matchProfile,
  playingProgress,
  selectedPlaylist,
  setIsPlayersStatsFetching,
  statsType,
}: UsePlayersStatsArgs) => {
  const [playersStats, setPlayersStats] = useObjectState<Record<string, PlayersStats>>({})
  const [playersData, setPlayersData] = useState<PlayersData>({ team1: [], team2: [] })

  const {
    profileId: matchId,
    sportName,
    sportType,
  } = usePageParams()

  const isCurrentStats = statsType === StatsType.CURRENT_STATS

  const isEmptyPlayersStats = (teamId: number) => (
    isEmpty(playersStats[teamId])
      || every(playersStats[teamId], isEmpty)
      || isEmpty(playersData[matchProfile?.team1.id === teamId ? 'team1' : 'team2'])
  )

  const fetchPlayers = useMemo(() => throttle(async (second?: number) => {
    if (
      !matchProfile?.team1.id
        || !matchProfile?.team2.id
        || !matchProfile?.video_bounds
    ) return null

    try {
      return getMatchParticipants({
        matchId,
        sportType,
        ...(!isUndefined(second) && getHalfTime(matchProfile.video_bounds, second)),
      })
    } catch (e) {
      return Promise.reject(e)
    }
  }, REQUEST_DELAY), [
    matchId,
    matchProfile?.team1.id,
    matchProfile?.team2.id,
    matchProfile?.video_bounds,
    sportType,
  ])

  const fetchPlayersStats = useMemo(() => (async (team: 'team1' | 'team2', second?: number) => {
    if (!sportName || !matchProfile?.[team].id || !matchProfile?.video_bounds) return null

    try {
      return getPlayersStats({
        matchId,
        sportName,
        teamId: matchProfile[team].id,
        ...(!isUndefined(second) && getHalfTime(matchProfile.video_bounds, second)),
      })
    } catch (e) {
      return Promise.reject(e)
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }), [
    matchId,
    sportName,
    matchProfile?.team1.id,
    matchProfile?.team2.id,
  ])

  const fetchData = useMemo(() => throttle(async (second?: number) => {
    if (selectedPlaylist?.id !== FULL_GAME_KEY || !matchProfile?.video_bounds) return

    const [res1, res2, res3] = await Promise.all([
      fetchPlayers(second),
      fetchPlayersStats('team1', second),
      fetchPlayersStats('team2', second),
    ])

    const team1Players = find(res1, { team_id: matchProfile?.team1.id })?.players || []
    const team2Players = find(res1, { team_id: matchProfile?.team2.id })?.players || []

    setPlayersData({
      team1: team1Players,
      team2: team2Players,
    })

    setPlayersStats({
      ...(matchProfile?.team1.id && res2 && { [matchProfile.team1.id]: res2 }),
      ...(matchProfile?.team2.id && res3 && { [matchProfile.team2.id]: res3 }),
    })

    setIsPlayersStatsFetching(false)
  }, REQUEST_DELAY), [
    selectedPlaylist?.id,
    fetchPlayers,
    fetchPlayersStats,
    setPlayersStats,
    matchProfile?.team1.id,
    matchProfile?.team2.id,
    matchProfile?.video_bounds,
    setIsPlayersStatsFetching,
  ])

  useEffect(() => {
    let interval: NodeJS.Timeout

    if (!isCurrentStats) {
      fetchData()
    }

    if (matchProfile?.live && !isCurrentStats) {
      interval = setInterval(() => {
        fetchData()
      }, STATS_POLL_INTERVAL)
    }

    return () => clearInterval(interval)
  }, [
    fetchData,
    isCurrentStats,
    matchProfile?.live,
  ])

  useEffect(() => {
    if (isCurrentStats) {
      fetchData(playingProgress)
    }
  }, [
    fetchData,
    playingProgress,
    isCurrentStats,
    matchProfile?.live,
  ])

  return {
    isEmptyPlayersStats,
    playersData,
    playersStats,
  }
}
