/**
 * CircleTimeline Component
 * Круговая временная шкала с периодами
 *
 * @module CircleTimeline
 * @description Компонент отображает временные периоды на круговой диаграмме.
 * Активный период автоматически поворачивается в заданную позицию с помощью GSAP анимации.
 * Поддерживает клик по точкам для переключения периодов.
 */

import { useGSAP } from '@gsap/react'
import classNames from 'classnames'
import { gsap } from 'gsap'
import { memo, useCallback, useMemo, useRef } from 'react'

import styles from './CircleTimeline.module.scss'
import { calculateCoordinates } from '../../lib/utils/calculateCoordinates/calculateCoordinates'
import { ANIMATION_DURATION, ANIMATION_EASE } from '../../model'

import type { TimePeriod } from '@/entities/TimePeriod'

export interface CircleTimelineProps {
  /**
   * Массив временных периодов для отображения
   */
  readonly periods: readonly TimePeriod[]

  /**
   * Индекс активного периода (0-based)
   */
  readonly activeIndex: number

  /**
   * Callback для изменения активного периода
   * @param index - Индекс выбранного периода
   */
  readonly onPeriodChange: (index: number) => void

  /**
   * Угол поворота круга в градусах
   */
  readonly rotation: number
}

/**
 * CircleTimeline - компонент круговой временной шкалы
 *
 * @component
 * @example
 * ```tsx
 * <CircleTimeline
 *   periods={HISTORICAL_PERIODS}
 *   activeIndex={0}
 *   onPeriodChange={(index) => setActiveIndex(index)}
 *   rotation={-60}
 * />
 * ```
 */
export const CircleTimeline = memo(function CircleTimeline({
  periods,
  activeIndex,
  onPeriodChange,
  rotation,
}: CircleTimelineProps) {
  // Реф для контейнера круга
  const circleRef = useRef<HTMLDivElement>(null)

  // Реф для массива точек периодов
  const pointsRef = useRef<(HTMLDivElement | null)[]>([])

  // Реф для заголовков периодов
  const titlesRef = useRef<(HTMLSpanElement | null)[]>([])

  /**
   * Анимация поворота круга и контр-поворота точек
   * Использует useGSAP hook для автоматической очистки анимаций
   */
  useGSAP(
    () => {
      // Анимация поворота контейнера круга
      if (circleRef.current) {
        gsap.to(circleRef.current, {
          rotation,
          duration: ANIMATION_DURATION,
          ease: ANIMATION_EASE,
        })
      }

      // Контр-поворот точек, чтобы текст оставался читаемым
      pointsRef.current.forEach((point, index) => {
        if (point) {
          gsap.to(point, {
            rotation: -rotation,
            duration: 0,
            ease: ANIMATION_EASE,
          })

          // Анимация заголовка
          const title = titlesRef.current[index]
          if (title) {
            // Останавливаем предыдущие анимации для предотвращения конфликтов
            gsap.killTweensOf(title)

            if (index === activeIndex) {
              gsap.to(title, {
                opacity: 1,
                visibility: 'visible',
                duration: 0.5,
                delay: ANIMATION_DURATION, // Ждем окончания вращения
              })
            } else {
              gsap.to(title, {
                opacity: 0,
                visibility: 'hidden',
                duration: 0.2,
              })
            }
          }
        }
      })
    },
    { dependencies: [rotation, activeIndex] }
  )

  /**
   * Мемоизированный расчет позиций точек на круге
   * Пересчитывается только при изменении количества периодов
   */
  const pointPositions = useMemo(() => {
    return periods.map((_, index, array) =>
      calculateCoordinates(array.length, index)
    )
  }, [periods])

  /**
   * Мемоизированный обработчик клика по точке
   * Предотвращает создание новой функции при каждом рендере
   */
  const handlePointClick = useCallback(
    (index: number) => {
      onPeriodChange(index)
    },
    [onPeriodChange]
  )

  return (
    <div className={styles.circleContainer} ref={circleRef}>
      {periods.map((period, index) => {
        const { x, y } = pointPositions[index]

        return (
          <div
            key={period.id}
            ref={(el) => {
              pointsRef.current[index] = el
            }}
            className={classNames(styles.point, {
              [styles.active]: index === activeIndex,
            })}
            style={{
              left: `calc(50% + ${x}px)`,
              top: `calc(50% + ${y}px)`,
            }}
            onClick={() => handlePointClick(index)}
            role='button'
            tabIndex={0}
            aria-label={`Period ${index + 1}: ${period.label}`}
            aria-current={index === activeIndex ? 'true' : 'false'}
          >
            <span className={styles.number}>{index + 1}</span>
            <span
              className={styles.title}
              ref={(el) => {
                titlesRef.current[index] = el
              }}
            >
              {period.label}
            </span>
          </div>
        )
      })}
    </div>
  )
})
