import { TriangleAlert } from 'lucide-react'
import { motion, useReducedMotion } from 'motion/react'
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import animalBorderImage from '@/assets/game/animal-border.webp'
import diamondIcon from '@/assets/system/diamond.webp'
import { SmartImage } from '@/components/smart-image'
import { DesktopAnimalOverlay } from '@/features/game/components/desktop/desktop-animal-overlay.tsx'
import { AnimalSpriteImage } from '@/features/game/components/shared/animal-sprite-image'
import { RoundBettingStartAlert } from '@/features/game/components/shared/round-betting-start-alert.tsx'
import { FLOWER_IMAGE_LIST } from '@/features/game/shared'
import { useAnimalVm } from '@/hooks/use-animal-vm'
import { cn } from '@/lib/utils'
import { useAuthStore } from '@/store/auth'
import { useGameRoundStore } from '@/store/game'

const SETTLEMENT_REVEAL_RANDOM_DURATION_MS = 3_200
const SETTLEMENT_REVEAL_SETTLE_DURATION_MS = 800
const SETTLEMENT_REVEAL_RESULT_HOLD_MS = 1_000
const SETTLEMENT_REVEAL_MIN_STEP_MS = 180
const SETTLEMENT_REVEAL_MAX_STEP_MS = 960

function getRandomAnimalId(ids: number[], currentId: number | null) {
  if (ids.length === 0) {
    return null
  }

  if (ids.length === 1) {
    return ids[0] ?? null
  }

  let nextId = currentId

  while (nextId === currentId) {
    nextId = ids[Math.floor(Math.random() * ids.length)] ?? currentId
  }

  return nextId
}

function getSettlementRevealStepDelay(progress: number) {
  const clampedProgress = Math.min(Math.max(progress, 0), 1)
  const easedProgress = clampedProgress ** 1.65

  return (
    SETTLEMENT_REVEAL_MIN_STEP_MS +
    (SETTLEMENT_REVEAL_MAX_STEP_MS - SETTLEMENT_REVEAL_MIN_STEP_MS) *
      easedProgress
  )
}

interface DesktopAnimalProps {
  className?: string
  itemClassName?: string
  imageClassName?: string
  onSelect?: (animalId: number) => void
}

export function DesktopAnimal({
  className,
  itemClassName,
  imageClassName,
  onSelect,
}: DesktopAnimalProps) {
  const { t } = useTranslation()
  const prefersReducedMotion = useReducedMotion()
  const animalIds = useMemo(() => FLOWER_IMAGE_LIST.map((item) => item.id), [])
  const containerRef = useRef<HTMLElement | null>(null)
  const cellRefs = useRef(new Map<number, HTMLButtonElement>())
  const [revealCellId, setRevealCellId] = useState<number | null>(null)
  const [revealFrame, setRevealFrame] = useState<{
    height: number
    left: number
    top: number
    width: number
  } | null>(null)
  const [isRevealHoldingResult, setIsRevealHoldingResult] = useState(false)
  const [isRevealSettlingResult, setIsRevealSettlingResult] = useState(false)
  const revealPhase = useGameRoundStore((state) => state.revealAnimation.phase)
  const revealWinningCellId = useGameRoundStore(
    (state) => state.revealAnimation.winningCellId,
  )
  const revealRewardType = useGameRoundStore(
    (state) => state.revealAnimation.rewardType,
  )
  const roundPhase = useGameRoundStore((state) => state.round.phase)
  const roundId = useGameRoundStore((state) => state.round.id)
  const lastBetPeriodNo = useAuthStore(
    (state) => state.currentUser?.lastBetPeriodNo,
  )
  const finishRevealAnimation = useGameRoundStore(
    (state) => state.finishRevealAnimation,
  )
  const {
    cellWarning,
    handleSelect,
    handleStart,
    isRealtimeConnecting,
    lockInteraction,
    marqueeId,
    selectionByCell,
    showStandbyState,
  } = useAnimalVm(animalIds, onSelect)

  const isRevealRunning =
    revealPhase === 'spinning' ||
    (revealPhase === 'stopping' && !isRevealHoldingResult)
  const isRevealResult = revealPhase === 'result'
  const [hasRewardOverlayStarted, setHasRewardOverlayStarted] = useState(false)
  const shouldHideRevealHighlight =
    revealPhase === 'result' &&
    (revealRewardType !== 'none' || hasRewardOverlayStarted)
  const hasSubmittedCurrentRound =
    roundPhase === 'betting' && Boolean(roundId) && lastBetPeriodNo === roundId
  const showStopOverlay =
    hasSubmittedCurrentRound ||
    roundPhase === 'locked' ||
    roundPhase === 'revealing'

  useEffect(() => {
    if (revealPhase === 'idle') {
      setHasRewardOverlayStarted(false)
      return
    }

    if (revealPhase === 'result' && revealRewardType !== 'none') {
      setHasRewardOverlayStarted(true)
    }
  }, [revealPhase, revealRewardType])

  useEffect(() => {
    if (revealPhase === 'idle') {
      setRevealCellId(null)
      setIsRevealHoldingResult(false)
      setIsRevealSettlingResult(false)
      return
    }

    if (revealPhase === 'result') {
      setRevealCellId(shouldHideRevealHighlight ? null : revealWinningCellId)
      setIsRevealHoldingResult(false)
      setIsRevealSettlingResult(false)
      return
    }

    if (revealPhase === 'spinning') {
      setIsRevealHoldingResult(false)
      setIsRevealSettlingResult(false)
      setRevealCellId((currentId) => getRandomAnimalId(animalIds, currentId))

      const intervalId = window.setInterval(() => {
        setRevealCellId((currentId) => getRandomAnimalId(animalIds, currentId))
      }, 70)

      return () => {
        window.clearInterval(intervalId)
      }
    }

    if (revealWinningCellId === null) {
      setIsRevealHoldingResult(false)
      setIsRevealSettlingResult(false)
      return
    }

    const startedAt = performance.now()
    let timeoutId = 0
    setIsRevealHoldingResult(false)
    setIsRevealSettlingResult(false)

    const step = () => {
      const elapsedMs = performance.now() - startedAt

      if (elapsedMs >= SETTLEMENT_REVEAL_RANDOM_DURATION_MS) {
        setIsRevealSettlingResult(true)
        setRevealCellId(revealWinningCellId)
        timeoutId = window.setTimeout(() => {
          setIsRevealSettlingResult(false)
          setIsRevealHoldingResult(true)
          timeoutId = window.setTimeout(() => {
            finishRevealAnimation()
          }, SETTLEMENT_REVEAL_RESULT_HOLD_MS)
        }, SETTLEMENT_REVEAL_SETTLE_DURATION_MS)
        return
      }

      setRevealCellId((currentId) => getRandomAnimalId(animalIds, currentId))

      const progress = elapsedMs / SETTLEMENT_REVEAL_RANDOM_DURATION_MS
      const nextDelayMs = getSettlementRevealStepDelay(progress)
      const remainingMs = SETTLEMENT_REVEAL_RANDOM_DURATION_MS - elapsedMs

      timeoutId = window.setTimeout(step, Math.min(nextDelayMs, remainingMs))
    }

    setRevealCellId((currentId) => getRandomAnimalId(animalIds, currentId))
    timeoutId = window.setTimeout(step, SETTLEMENT_REVEAL_MIN_STEP_MS)

    return () => {
      window.clearTimeout(timeoutId)
    }
  }, [
    animalIds,
    finishRevealAnimation,
    revealPhase,
    revealWinningCellId,
    shouldHideRevealHighlight,
  ])

  useLayoutEffect(() => {
    if (revealCellId === null) {
      setRevealFrame(null)
      return
    }

    const syncRevealFrame = () => {
      const container = containerRef.current
      const cell = cellRefs.current.get(revealCellId)

      if (!container || !cell) {
        setRevealFrame(null)
        return
      }

      const containerRect = container.getBoundingClientRect()
      const cellRect = cell.getBoundingClientRect()

      setRevealFrame({
        height: cellRect.height,
        left: cellRect.left - containerRect.left,
        top: cellRect.top - containerRect.top,
        width: cellRect.width,
      })
    }

    syncRevealFrame()
    window.addEventListener('resize', syncRevealFrame)

    return () => {
      window.removeEventListener('resize', syncRevealFrame)
    }
  }, [revealCellId])

  return (
    <section
      ref={containerRef}
      className={cn(
        'relative grid w-full grid-cols-6 gap-design-5 overflow-hidden common-neon-inset',
        className,
      )}
    >
      {FLOWER_IMAGE_LIST.map((item) => {
        const selectionMeta = selectionByCell[item.id]
        const hasPlacedSelection = Boolean(selectionMeta)
        const isMarqueeActive = showStandbyState && item.id === marqueeId
        const isRevealWinner =
          !shouldHideRevealHighlight &&
          (isRevealResult || isRevealHoldingResult) &&
          revealWinningCellId === item.id
        const warningType =
          cellWarning?.cellId === item.id ? cellWarning.type : null
        const showCellWarning = warningType !== null
        const warningLabel =
          warningType === 'balance'
            ? t('gameDesktop.animal.insufficientBalanceRecharge')
            : warningType === 'betLimit'
              ? t('gameDesktop.animal.betLimitExceeded')
              : t('gameDesktop.animal.selectionLimitReached')

        return (
          <motion.button
            key={item.id}
            ref={(node) => {
              if (node) {
                cellRefs.current.set(item.id, node)
              } else {
                cellRefs.current.delete(item.id)
              }
            }}
            type="button"
            disabled={lockInteraction || showStopOverlay}
            onClick={() => handleSelect(item.id)}
            animate={
              showCellWarning
                ? {
                    rotate: [0, -1.8, 1.4, -1, 0.6, 0],
                    scale: [1, 1.015, 0.992, 1.01, 1],
                    x: [0, -2, 2, -1, 1, 0],
                  }
                : {
                    rotate: 0,
                    scale: 1,
                    x: 0,
                  }
            }
            transition={
              showCellWarning
                ? {
                    duration: 0.46,
                    ease: 'easeInOut',
                  }
                : { duration: 0.16, ease: 'easeOut' }
            }
            className={cn(
              'relative flex h-design-112 flex-col items-center justify-center overflow-hidden rounded-[calc(var(--design-unit)*18)] border border-transparent transition-[transform,border-color,box-shadow,opacity] duration-150',
              lockInteraction
                ? 'cursor-not-allowed opacity-90'
                : 'cursor-pointer hover:-translate-y-[1px]',
              isMarqueeActive &&
                'border-[rgba(121,255,250,1)] shadow-[0_0_calc(var(--design-unit)*18)_rgba(85,255,247,0.98),0_0_calc(var(--design-unit)*34)_rgba(39,245,255,0.88),inset_0_0_calc(var(--design-unit)*26)_rgba(112,255,248,0.34)]',
              isRevealRunning &&
                'border-[rgba(104,255,249,0.76)] shadow-[0_0_calc(var(--design-unit)*10)_rgba(68,244,255,0.46),0_0_calc(var(--design-unit)*22)_rgba(37,214,255,0.28),inset_0_0_calc(var(--design-unit)*16)_rgba(115,255,247,0.18)] brightness-115 saturate-125',
              isRevealWinner &&
                'border-[rgba(121,255,250,0.72)] shadow-[0_0_calc(var(--design-unit)*12)_rgba(81,248,255,0.54),0_0_calc(var(--design-unit)*22)_rgba(30,199,255,0.32),inset_0_0_calc(var(--design-unit)*18)_rgba(125,255,249,0.24)] brightness-110 saturate-120',
              showCellWarning &&
                'border-[rgba(255,92,92,1)] shadow-[0_0_calc(var(--design-unit)*18)_rgba(255,88,88,0.56),0_0_calc(var(--design-unit)*28)_rgba(255,44,44,0.32),inset_0_0_calc(var(--design-unit)*18)_rgba(255,126,126,0.3)]',
              !showStandbyState &&
                !hasPlacedSelection &&
                !isRevealWinner &&
                'opacity-95',
              itemClassName,
            )}
          >
            <SmartImage
              src={animalBorderImage}
              alt=""
              aria-hidden="true"
              priority
              showSkeleton={false}
              className="pointer-events-none absolute inset-0 z-20 h-full w-full"
              imgClassName="object-fill"
            />
            <span className="pointer-events-none absolute left-design-24 top-design-16 z-30 text-design-32 font-bold leading-none text-[#4BFFFE]">
              {String(item.id).padStart(2, '0')}
            </span>
            <motion.span
              aria-hidden="true"
              animate={
                showCellWarning
                  ? {
                      opacity: [0.45, 1, 0.6, 1, 0.82],
                    }
                  : undefined
              }
              transition={
                showCellWarning
                  ? {
                      duration: 0.52,
                      ease: 'easeInOut',
                    }
                  : undefined
              }
              className={cn(
                'pointer-events-none absolute inset-[calc(var(--design-unit)*2)] rounded-[calc(var(--design-unit)*15)] opacity-0 transition-opacity duration-150',
                isMarqueeActive &&
                  'bg-[radial-gradient(circle_at_center,rgba(129,255,250,0.48)_0%,rgba(94,255,247,0.18)_38%,rgba(43,236,255,0.08)_56%,transparent_76%)] opacity-100 shadow-[0_0_calc(var(--design-unit)*12)_rgba(119,255,249,0.98),0_0_calc(var(--design-unit)*28)_rgba(53,246,255,0.9),0_0_calc(var(--design-unit)*44)_rgba(37,241,255,0.58),inset_0_0_calc(var(--design-unit)*20)_rgba(163,255,250,0.52)]',
                isRevealRunning &&
                  'bg-[radial-gradient(circle_at_center,rgba(128,255,250,0.36)_0%,rgba(77,244,255,0.16)_40%,rgba(27,183,255,0.07)_68%,transparent_88%)] opacity-100 shadow-[0_0_calc(var(--design-unit)*12)_rgba(95,249,255,0.46),inset_0_0_calc(var(--design-unit)*18)_rgba(151,255,250,0.24)]',
                isRevealWinner &&
                  'bg-[radial-gradient(circle_at_center,rgba(128,255,250,0.34)_0%,rgba(67,226,255,0.16)_38%,rgba(25,131,255,0.07)_58%,transparent_76%)] opacity-100 shadow-[0_0_calc(var(--design-unit)*12)_rgba(92,248,255,0.42),inset_0_0_calc(var(--design-unit)*18)_rgba(126,255,250,0.24)]',
                showCellWarning &&
                  'bg-[radial-gradient(circle_at_center,rgba(255,106,106,0.34)_0%,rgba(255,58,58,0.18)_42%,rgba(108,0,0,0.2)_78%,transparent_100%)] opacity-100',
              )}
            />
            {!showStandbyState && !hasPlacedSelection && !isRevealWinner ? (
              <span
                aria-hidden="true"
                className="pointer-events-none absolute inset-[calc(var(--design-unit)*2)] z-20 rounded-[calc(var(--design-unit)*15)] bg-[rgba(4,16,24,0.52)] shadow-[inset_0_0_calc(var(--design-unit)*20)_rgba(3,9,14,0.56)]"
              />
            ) : null}
            <AnimalSpriteImage
              animalId={item.id}
              alt={`animal-${item.id}`}
              className={cn(
                'absolute left-[1.5%] right-[1.5%] top-[2.9%] bottom-[2.9%] z-10 overflow-hidden rounded-[calc(var(--design-unit)*14)]',
                isRevealRunning &&
                  'brightness-115 saturate-125 drop-shadow-[0_0_calc(var(--design-unit)*8)_rgba(101,250,255,0.42)]',
                isRevealWinner &&
                  'brightness-110 saturate-120 drop-shadow-[0_0_calc(var(--design-unit)*9)_rgba(106,250,255,0.44)]',
                imageClassName,
              )}
            />
            {showCellWarning ? (
              <motion.span
                initial={{ opacity: 0, scale: 0.94 }}
                animate={{
                  opacity: [0.2, 1, 0.92],
                  scale: [0.96, 1.02, 1],
                  boxShadow: [
                    'inset 0 0 calc(var(--design-unit)*10) rgba(255,108,108,0.16), 0 0 calc(var(--design-unit)*8) rgba(255,60,60,0.12)',
                    'inset 0 0 calc(var(--design-unit)*20) rgba(255,108,108,0.28), 0 0 calc(var(--design-unit)*20) rgba(255,60,60,0.28)',
                    'inset 0 0 calc(var(--design-unit)*16) rgba(255,108,108,0.22), 0 0 calc(var(--design-unit)*18) rgba(255,60,60,0.2)',
                  ],
                }}
                transition={{ duration: 0.5, ease: 'easeOut' }}
                className="pointer-events-none absolute inset-[calc(var(--design-unit)*3)] z-30 flex flex-col items-center justify-center gap-design-8 rounded-[calc(var(--design-unit)*15)] border border-[rgba(255,126,126,0.9)] bg-[rgba(61,0,0,0.58)] px-design-10 py-design-10 text-center"
              >
                <motion.span
                  animate={{
                    opacity: [0.72, 1, 0.92],
                    scale: [0.94, 1.08, 1],
                  }}
                  transition={{ duration: 0.38, ease: 'easeOut' }}
                  className="flex h-design-28 w-design-28 items-center justify-center"
                >
                  <TriangleAlert className="h-design-28 w-design-28 text-[#FFD0D0] drop-shadow-[0_0_calc(var(--design-unit)*8)_rgba(255,92,92,0.45)]" />
                </motion.span>
                <motion.span
                  animate={{
                    opacity: [0.7, 1, 0.96],
                    scale: [0.98, 1.03, 1],
                  }}
                  transition={{ duration: 0.42, ease: 'easeOut' }}
                  className="text-design-16 font-bold leading-tight tracking-[0.04em] text-[#FFE0E0] [text-shadow:0_0_calc(var(--design-unit)*10)_rgba(255,132,132,0.42)]"
                >
                  {warningLabel}
                </motion.span>
              </motion.span>
            ) : null}
            {hasPlacedSelection ? (
              <span className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center">
                <span className="flex min-w-design-96 items-center justify-center gap-design-4 rounded-full border border-[rgba(162,242,255,0.48)] bg-[linear-gradient(180deg,rgba(7,23,34,0.88),rgba(5,14,22,0.96))] px-design-10 py-design-6 shadow-[0_0_calc(var(--design-unit)*18)_rgba(70,245,255,0.18)]">
                  <SmartImage
                    src={diamondIcon}
                    alt="diamond"
                    className="h-design-24 w-design-24 shrink-0 object-contain"
                  />
                  <span className="text-design-18 font-semibold leading-none tracking-[0.06em] text-[#D8FBFF]">
                    {selectionMeta.amount}
                  </span>
                </span>
              </span>
            ) : null}
          </motion.button>
        )
      })}

      {revealFrame ? (
        <div
          aria-hidden="true"
          className={cn(
            'pointer-events-none absolute z-40 transform-gpu transition-[height,transform,width]',
            prefersReducedMotion
              ? 'duration-0'
              : isRevealSettlingResult
                ? 'duration-[800ms] ease-[cubic-bezier(0.16,1,0.3,1)]'
                : 'duration-[160ms] ease-[cubic-bezier(0.22,1,0.36,1)]',
          )}
          style={{
            height: revealFrame.height,
            transform: `translate(${revealFrame.left}px, ${revealFrame.top}px)`,
            width: revealFrame.width,
          }}
        >
          <div
            className="gold-reveal-glow rounded-[calc(var(--design-unit)*16)]"
            style={
              prefersReducedMotion
                ? {
                    animation: 'none',
                    opacity: 0.36,
                    transform: 'scale(1)',
                  }
                : undefined
            }
          />
          <div className="gold-reveal-static-border rounded-[calc(var(--design-unit)*16)]" />
          <div
            className="gold-reveal-shell rounded-[calc(var(--design-unit)*16)]"
            style={prefersReducedMotion ? { animation: 'none' } : undefined}
          />
        </div>
      ) : null}

      <DesktopAnimalOverlay showStopOverlay={showStopOverlay} />
      <RoundBettingStartAlert className="z-50" />

      {showStandbyState ? (
        <button
          type="button"
          onClick={handleStart}
          aria-busy={isRealtimeConnecting}
          className="group absolute inset-0 z-10 flex cursor-pointer items-center justify-center overflow-hidden bg-[rgba(3,13,20,0.66)]"
        >
          <div className="relative flex min-w-design-260 flex-col items-center gap-design-10 rounded-[calc(var(--design-unit)*22)] border border-[rgba(111,255,247,0.56)] bg-[linear-gradient(180deg,rgba(8,30,42,0.94),rgba(4,14,20,0.96))] px-design-32 py-design-18 text-center shadow-[0_0_calc(var(--design-unit)*18)_rgba(70,245,255,0.38),0_0_calc(var(--design-unit)*42)_rgba(19,210,232,0.22),inset_0_0_calc(var(--design-unit)*18)_rgba(120,255,249,0.12)] transition-[transform,box-shadow,border-color] duration-200 group-hover:-translate-y-[1px] group-hover:border-[rgba(141,255,250,0.82)] group-hover:shadow-[0_0_calc(var(--design-unit)*24)_rgba(88,247,255,0.5),0_0_calc(var(--design-unit)*52)_rgba(32,228,255,0.32),inset_0_0_calc(var(--design-unit)*18)_rgba(145,255,251,0.16)]">
            <span className="pointer-events-none absolute inset-[1px] rounded-[calc(var(--design-unit)*22)] border border-[rgba(226,255,255,0.1)]" />
            <span className="pointer-events-none absolute inset-x-design-14 top-design-10 h-design-18 rounded-full bg-[linear-gradient(180deg,rgba(255,255,255,0.16),rgba(255,255,255,0))] opacity-70" />
            <span className="text-design-14 uppercase tracking-[0.44em] text-[rgba(132,255,248,0.72)]">
              {isRealtimeConnecting
                ? t('gameDesktop.animal.loading')
                : t('gameDesktop.animal.tapToEnter')}
            </span>
            <div className="flex items-center gap-design-10">
              {isRealtimeConnecting ? (
                <span className="relative flex h-design-24 w-design-24 items-center justify-center">
                  <motion.span
                    animate={{ rotate: 360 }}
                    transition={{
                      duration: 1.2,
                      repeat: Number.POSITIVE_INFINITY,
                      ease: 'linear',
                    }}
                    className="absolute inset-0 rounded-full border-2 border-[rgba(119,255,250,0.22)] border-t-[rgba(119,255,250,0.98)] border-r-[rgba(119,255,250,0.56)]"
                  />
                  <motion.span
                    animate={{ scale: [0.85, 1, 0.85], opacity: [0.6, 1, 0.6] }}
                    transition={{
                      duration: 1.2,
                      repeat: Number.POSITIVE_INFINITY,
                      ease: 'easeInOut',
                    }}
                    className="h-design-8 w-design-8 rounded-full bg-[#BFFFFD] shadow-[0_0_calc(var(--design-unit)*10)_rgba(114,255,249,0.72)]"
                  />
                </span>
              ) : (
                <span className="h-design-10 w-design-10 rounded-full bg-[rgba(126,255,248,0.92)] shadow-[0_0_calc(var(--design-unit)*10)_rgba(114,255,249,0.62)]" />
              )}
              <span className="text-design-28 font-semibold tracking-[0.18em] text-[#E0FFFF]">
                {isRealtimeConnecting
                  ? t('gameDesktop.animal.loading')
                  : t('gameDesktop.animal.getStart')}
              </span>
            </div>
            <div className="flex items-center gap-design-4">
              {[0, 1, 2].map((index) => (
                <motion.span
                  key={`loading-dot-${index}`}
                  animate={
                    isRealtimeConnecting
                      ? { opacity: [0.28, 1, 0.28], y: [0, -2, 0] }
                      : { opacity: 0.7 }
                  }
                  transition={
                    isRealtimeConnecting
                      ? {
                          duration: 0.9,
                          repeat: Number.POSITIVE_INFINITY,
                          ease: 'easeInOut',
                          delay: index * 0.15,
                        }
                      : undefined
                  }
                  className="h-design-4 w-design-4 rounded-full bg-[rgba(145,255,249,0.86)] shadow-[0_0_calc(var(--design-unit)*8)_rgba(114,255,249,0.48)]"
                />
              ))}
            </div>
          </div>
        </button>
      ) : null}
    </section>
  )
}
