import { useEffect } from 'react'
import { useSyncPlay } from '../stores/syncplay-store'
import { startSyncPlaySocket, stopSyncPlaySocket, subscribeSyncPlay } from '../lib/syncplay-socket'

/**
 * Open the SyncPlay WebSocket only while the user is in a group. Idle
 * players don't need a connection - so we gate the socket on the active
 * group state and tear it down on leave.
 *
 * Two message families flow through:
 *   - SyncPlayCommand: Pause / Unpause / Seek - dispatched as remote
 *     commands so PlayerPage can mirror them onto the local video.
 *   - SyncPlayGroupUpdate: state changes, participant joins/leaves,
 *     queue updates. PlayQueue + GroupJoined carry the current item +
 *     position so a late joiner can catch up; UserJoined / UserLeft
 *     update the member count badge.
 */
export function useSyncPlaySocketBridge() {
  const applyRemote = useSyncPlay(s => s.applyRemote)
  const setRemoteQueueItem = useSyncPlay(s => s.setRemoteQueueItem)
  const setMemberCount = useSyncPlay(s => s.setMemberCount)
  const setActive = useSyncPlay(s => s.setActive)
  const active = useSyncPlay(s => s.active)

  useEffect(() => {
    if (!active) return
    startSyncPlaySocket()
    const unsub = subscribeSyncPlay(msg => {
      if (msg.MessageType === 'SyncPlayCommand' && msg.Data) {
        const data = msg.Data as { Command?: string; PositionTicks?: number }
        switch (data.Command) {
          case 'Pause':
            applyRemote({ type: 'pause' })
            break
          case 'Unpause':
            applyRemote({ type: 'play' })
            break
          case 'Seek':
            if (typeof data.PositionTicks === 'number') {
              applyRemote({ type: 'seek', positionTicks: data.PositionTicks })
            }
            break
        }
        return
      }
      if (msg.MessageType === 'SyncPlayGroupUpdate' && msg.Data) {
        const data = msg.Data as {
          Type?: string
          Data?: any
        }
        switch (data.Type) {
          case 'PlayQueue':
          case 'GroupJoined': {
            // The GroupJoined payload is a GroupInfoDto - it doesn't
            // include the queue, so position sync comes from a
            // PlayQueue update that follows. PlayQueue carries
            // Playlist + PlayingItemIndex + StartPositionTicks.
            const queue = data.Data as {
              Playlist?: Array<{ ItemId?: string }>
              PlayingItemIndex?: number
              StartPositionTicks?: number
              IsPlaying?: boolean
            } | undefined
            if (!queue?.Playlist) return
            const idx = typeof queue.PlayingItemIndex === 'number' ? queue.PlayingItemIndex : 0
            const item = queue.Playlist[idx]
            if (!item?.ItemId) return
            setRemoteQueueItem({
              itemId: item.ItemId,
              positionTicks: queue.StartPositionTicks || 0,
              isPlaying: queue.IsPlaying !== false,
            })
            break
          }
          case 'UserJoined':
          case 'UserLeft': {
            // The participant list comes in the payload as the group
            // info; bump the count from its length if present.
            const info = data.Data as { Participants?: string[] } | undefined
            if (info?.Participants) setMemberCount(info.Participants.length)
            break
          }
          case 'GroupLeft':
          case 'NotInGroup':
          case 'GroupDoesNotExist':
            // Server says we're no longer in a group - clear local
            // state so the player stops mirroring commands.
            setActive(null)
            break
        }
      }
    })
    return () => {
      unsub()
      stopSyncPlaySocket()
    }
  }, [active, applyRemote, setRemoteQueueItem, setMemberCount, setActive])
}
