import type {
  SyntheticEvent,
  Dispatch,
  SetStateAction,
} from 'react'
import {
  useCallback,
  useRef,
  useState,
  useEffect,
  useLayoutEffect,
  useMemo,
} from 'react'

import size from 'lodash/size'
import isNil from 'lodash/isNil'
import reduce from 'lodash/reduce'
import forEach from 'lodash/forEach'
import values from 'lodash/values'
import map from 'lodash/map'

import { isMobileDevice } from 'config'

import type { PlayerParam, PlayersStats } from 'requests'
import { getStatsEvents } from 'requests'

import { usePageParams, useToggle } from 'hooks'

import { useMatchPageStore } from 'features/MatchPage/store'
import { useLexicsConfig } from 'features/LexicsStore'
import { getHalfTime } from 'features/MatchPage/helpers/getHalfTime'

import type { SortCondition } from '../types'
import {
  PARAM_COLUMN_WIDTH_DEFAULT,
  FIRST_COLUMN_WIDTH_DEFAULT,
  DISPLAYED_PARAMS_COLUMNS,
  SCROLLBAR_WIDTH,
} from '../config'
import { StatsType } from '../../TabStats/config'

type UseTableArgs = {
  setSortCondition: Dispatch<SetStateAction<SortCondition>>,
  teamId: number,
}

type HeaderParam = Pick<PlayerParam, 'id' | 'lexica_short' | 'lexic'>

export const useTable = ({
  setSortCondition,
  teamId,
}: UseTableArgs) => {
  const containerRef = useRef<HTMLDivElement>(null)
  const tableWrapperRef = useRef<HTMLDivElement>(null)

  const [showLeftArrow, setShowLeftArrow] = useState(false)
  const [showRightArrow, setShowRightArrow] = useState(true)
  const [paramColumnWidth, setParamColumnWidth] = useState(PARAM_COLUMN_WIDTH_DEFAULT)

  const {
    close: reduceTable,
    isOpen: isExpanded,
    toggle: toggleIsExpanded,
  } = useToggle()
  const {
    playersStats,
    playingProgress,
    playStatsEpisodes,
    profile,
    setIsPlayingFiltersEpisodes,
    setPlayingData,
    setWatchAllEpisodesTimer,
    statsType,
  } = useMatchPageStore()
  const { profileId, sportType } = usePageParams()

  const params = useMemo(() => (
    reduce<PlayersStats, Record<string, HeaderParam>>(
      playersStats[teamId],
      (acc, curr) => {
        forEach(values(curr), ({
          id,
          lexic,
          lexica_short,
        }) => {
          acc[id] = acc[id] || {
            id,
            lexic,
            lexica_short,
          }
        })

        return acc
      },
      {},
    )
  ), [playersStats, teamId])

  const lexics = useMemo(() => (
    reduce<HeaderParam, Array<number>>(
      values(params),
      (acc, { lexic, lexica_short }) => {
        if (lexic) acc.push(lexic)
        if (lexica_short) acc.push(lexica_short)

        return acc
      },
      [],
    )
  // eslint-disable-next-line react-hooks/exhaustive-deps
  ), [map(params, 'id').sort().join('')])

  useLexicsConfig(lexics)

  const paramsCount = size(params)

  const getParamColumnWidth = useCallback(() => {
    const paramsTableWidth = (
      (containerRef.current?.clientWidth || 0)
      - FIRST_COLUMN_WIDTH_DEFAULT
      - SCROLLBAR_WIDTH - 8
    )
    return isExpanded
      ? PARAM_COLUMN_WIDTH_DEFAULT
      : paramsTableWidth / DISPLAYED_PARAMS_COLUMNS
  }, [isExpanded])

  const slideLeft = () => {
    const {
      clientHeight = 0,
      clientWidth = 0,
      scrollHeight = 0,
      scrollLeft = 0,
      scrollWidth = 0,
    } = tableWrapperRef.current || {}

    const hasVerticalScroll = scrollHeight > clientHeight
    const scrollRight = scrollWidth - (scrollLeft + clientWidth)

    const scrollBy = scrollRight === 0
      ? paramColumnWidth - (hasVerticalScroll ? SCROLLBAR_WIDTH : SCROLLBAR_WIDTH * 2)
      : paramColumnWidth

    tableWrapperRef.current?.scrollBy(-scrollBy, 0)
  }
  const slideRight = () => {
    tableWrapperRef.current?.scrollBy(paramColumnWidth, 0)
  }

  const getDisplayedValue = ({ val }: PlayerParam) => (isNil(val) ? '-' : String(val))

  const handleScroll = (e: SyntheticEvent<HTMLDivElement>) => {
    const {
      clientWidth,
      scrollLeft,
      scrollWidth,
    } = e.currentTarget

    const scrollRight = scrollWidth - (scrollLeft + clientWidth)

    setShowLeftArrow(scrollLeft > 0)
    setShowRightArrow(scrollRight > 0)
  }

  const handleSortClick = (paramId: number) => () => {
    setSortCondition((curr) => {
      const clicksCount = curr.paramId === paramId || isNil(curr.paramId)
        ? curr.clicksCount + 1
        : 1

      // При третьем клике сбрасываем счетчик клика и убираем сортировку по параметру
      return {
        clicksCount: clicksCount === 3 ? 0 : clicksCount,
        dir: curr.dir === 'asc' || curr.paramId !== paramId ? 'desc' : 'asc',
        paramId: clicksCount === 3 ? null : paramId,
      }
    })
  }

  const handleParamClick = async (paramId: number, playerId: number) => {
    setWatchAllEpisodesTimer(false)
    setIsPlayingFiltersEpisodes(false)

    setPlayingData({
      player: {
        id: playerId,
        paramId,
      },
      team: {
        id: null,
        paramId: null,
      },
    })

    try {
      const events = await getStatsEvents({
        matchId: profileId,
        paramId,
        playerId,
        sportType,
        teamId,
        ...(statsType === StatsType.CURRENT_STATS && profile?.video_bounds && (
          getHalfTime(profile.video_bounds, playingProgress)
        )),
      })

      playStatsEpisodes(events)
    // eslint-disable-next-line no-empty
    } catch (e) {}
  }

  useLayoutEffect(() => {
    setParamColumnWidth(getParamColumnWidth())
  }, [getParamColumnWidth, containerRef.current?.clientWidth])

  useLayoutEffect(() => {
    const {
      clientWidth = 0,
      scrollLeft = 0,
      scrollWidth = 0,
    } = tableWrapperRef.current || {}

    const scrollRight = scrollWidth - (scrollLeft + clientWidth)

    setShowRightArrow(scrollRight > 0)
  }, [isExpanded])

  useEffect(() => {
    if (isExpanded && paramsCount <= DISPLAYED_PARAMS_COLUMNS) {
      reduceTable()
    }
  }, [isExpanded, paramsCount, reduceTable])

  return {
    containerRef,
    getDisplayedValue,
    handleParamClick,
    handleScroll,
    handleSortClick,
    isExpanded,
    paramColumnWidth,
    params,
    showExpandButton: !isMobileDevice && paramsCount > DISPLAYED_PARAMS_COLUMNS,
    showLeftArrow,
    showRightArrow,
    slideLeft,
    slideRight,
    tableWrapperRef,
    toggleIsExpanded,
  }
}
