import {
  cancelPvpQueue,
  checkPvpQueue,
  joinPvpQueue,
  randomCpuDifficulty,
  type CpuDifficulty,
  type PvpContentType,
  type PvpMatchSnapshot,
  type PvpMatchSide,
} from './pvpRoguelike'
import type { GameMode } from './gameRepository'

export function startPvpQueueWithCpuFallback<TSideState>({
  contentType,
  startStage,
  gameMode,
  liveMatchActive,
  onSearching,
  onCpuMatch,
  onLiveMatch,
  messages,
}: {
  contentType: PvpContentType
  startStage: number
  gameMode: GameMode
  liveMatchActive: () => boolean
  onSearching: (message: string) => void
  onCpuMatch: (difficulty: CpuDifficulty, message: string) => void
  onLiveMatch: (match: PvpMatchSnapshot<TSideState>, side: PvpMatchSide, message: string) => void
  messages: {
    offline: (difficulty: CpuDifficulty) => string
    searching: string
    notFound: (difficulty: CpuDifficulty) => string
    unavailable: (difficulty: CpuDifficulty) => string
    liveFound: (match: PvpMatchSnapshot<TSideState>, side: PvpMatchSide) => string
  }
}) {
  if (gameMode === 'offline') {
    const difficulty = randomCpuDifficulty()
    const timer = window.setTimeout(() => {
      onCpuMatch(difficulty, messages.offline(difficulty))
    }, 500)
    return () => window.clearTimeout(timer)
  }

  let cancelled = false
  let ticketId = ''
  let pollTimer: number | undefined
  onSearching(messages.searching)

  const beginLiveMatch = (match: PvpMatchSnapshot<TSideState>, side: PvpMatchSide) => {
    if (cancelled) return
    onLiveMatch(match, side, messages.liveFound(match, side))
  }

  const fallbackTimer = window.setTimeout(() => {
    if (cancelled || liveMatchActive()) return
    cancelled = true
    if (ticketId) cancelPvpQueue(ticketId).catch(() => undefined)
    const difficulty = randomCpuDifficulty()
    onCpuMatch(difficulty, messages.notFound(difficulty))
  }, 5000)

  const pollQueue = () => {
    if (!ticketId || cancelled) return
    checkPvpQueue<TSideState>(ticketId)
      .then((result) => {
        if (cancelled) return
        if (result.status === 'matched' && result.match && result.side) {
          window.clearTimeout(fallbackTimer)
          if (pollTimer) window.clearTimeout(pollTimer)
          beginLiveMatch(result.match, result.side)
          return
        }
        pollTimer = window.setTimeout(pollQueue, 500)
      })
      .catch(() => {
        if (!cancelled) pollTimer = window.setTimeout(pollQueue, 700)
      })
  }

  joinPvpQueue<TSideState>(contentType, startStage)
    .then((result) => {
      if (cancelled) return
      ticketId = result.ticketId
      if (result.status === 'matched' && result.match && result.side) {
        window.clearTimeout(fallbackTimer)
        beginLiveMatch(result.match, result.side)
        return
      }
      pollTimer = window.setTimeout(pollQueue, 500)
    })
    .catch(() => {
      if (cancelled) return
      window.clearTimeout(fallbackTimer)
      cancelled = true
      const difficulty = randomCpuDifficulty()
      onCpuMatch(difficulty, messages.unavailable(difficulty))
    })

  return () => {
    cancelled = true
    window.clearTimeout(fallbackTimer)
    if (pollTimer) window.clearTimeout(pollTimer)
    if (ticketId && !liveMatchActive()) cancelPvpQueue(ticketId).catch(() => undefined)
  }
}
