import type { ReactFlowInstance } from 'reactflow'
import type {
  CollaborationState,
  CursorPosition,
  NodePanelPresenceMap,
  OnlineUser,
} from '../types/collaboration'
import { useSuspenseQuery } from '@tanstack/react-query'
import { useEffect, useRef, useState } from 'react'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { collaborationManager } from '../core/collaboration-manager'
import { CursorService } from '../services/cursor-service'

type CollaborationViewState = {
  isConnected: boolean
  onlineUsers: OnlineUser[]
  cursors: Record<string, CursorPosition>
  nodePanelPresence: NodePanelPresenceMap
  isLeader: boolean
}

type ReactFlowStore = NonNullable<Parameters<typeof collaborationManager.connect>[1]>

const initialState: CollaborationViewState = {
  isConnected: false,
  onlineUsers: [],
  cursors: {},
  nodePanelPresence: {},
  isLeader: false,
}

export function useCollaboration(appId: string, reactFlowStore?: ReactFlowStore) {
  const [state, setState] = useState<CollaborationViewState>(initialState)

  const cursorServiceRef = useRef<CursorService | null>(null)
  const lastDisconnectReasonRef = useRef<string | null>(null)
  const { data: isCollaborationEnabled } = useSuspenseQuery({
    ...systemFeaturesQueryOptions(),
    select: s => s.enable_collaboration_mode,
  })

  useEffect(() => {
    if (!appId || !isCollaborationEnabled) {
      Promise.resolve().then(() => {
        setState(initialState)
      })
      return
    }

    let connectionId: string | null = null
    let isUnmounted = false

    if (!cursorServiceRef.current)
      cursorServiceRef.current = new CursorService()

    const initCollaboration = async () => {
      try {
        const id = await collaborationManager.connect(appId, reactFlowStore)
        if (isUnmounted) {
          collaborationManager.disconnect(id)
          return
        }
        connectionId = id
        setState(prev => ({ ...prev, isConnected: collaborationManager.isConnected() }))
      }
      catch (error) {
        console.error('Failed to initialize collaboration:', error)
      }
    }

    initCollaboration()

    const unsubscribeStateChange = collaborationManager.onStateChange((newState: Partial<CollaborationState>) => {
      if (newState.isConnected === false)
        lastDisconnectReasonRef.current = newState.disconnectReason || newState.error || null
      if (newState.isConnected === true)
        lastDisconnectReasonRef.current = null

      if (newState.isConnected === undefined)
        return

      setState(prev => ({ ...prev, isConnected: newState.isConnected ?? prev.isConnected }))
    })

    const unsubscribeCursors = collaborationManager.onCursorUpdate((cursors: Record<string, CursorPosition>) => {
      setState(prev => ({ ...prev, cursors }))
    })

    const unsubscribeUsers = collaborationManager.onOnlineUsersUpdate((users: OnlineUser[]) => {
      setState(prev => ({ ...prev, onlineUsers: users }))
    })

    const unsubscribeNodePanelPresence = collaborationManager.onNodePanelPresenceUpdate((presence: NodePanelPresenceMap) => {
      setState(prev => ({ ...prev, nodePanelPresence: presence }))
    })

    const unsubscribeLeaderChange = collaborationManager.onLeaderChange((isLeader: boolean) => {
      setState(prev => ({ ...prev, isLeader }))
    })

    return () => {
      isUnmounted = true
      unsubscribeStateChange()
      unsubscribeCursors()
      unsubscribeUsers()
      unsubscribeNodePanelPresence()
      unsubscribeLeaderChange()
      cursorServiceRef.current?.stopTracking()
      if (connectionId)
        collaborationManager.disconnect(connectionId)
    }
  }, [appId, reactFlowStore, isCollaborationEnabled])

  const prevIsConnected = useRef(false)
  useEffect(() => {
    if (prevIsConnected.current && !state.isConnected) {
      const reason = lastDisconnectReasonRef.current
      if (reason)
        console.warn('WebSocket disconnected:', reason)
      else
        console.warn('WebSocket disconnected.')
    }
    prevIsConnected.current = state.isConnected || false
  }, [state.isConnected])

  const startCursorTracking = (containerRef: React.RefObject<HTMLElement>, reactFlowInstance?: ReactFlowInstance) => {
    if (!isCollaborationEnabled || !cursorServiceRef.current)
      return

    if (cursorServiceRef.current) {
      cursorServiceRef.current.startTracking(containerRef, (position) => {
        collaborationManager.emitCursorMove(position)
      }, reactFlowInstance)
    }
  }

  const stopCursorTracking = () => {
    cursorServiceRef.current?.stopTracking()
  }

  const result = {
    isConnected: state.isConnected || false,
    onlineUsers: state.onlineUsers || [],
    cursors: state.cursors || {},
    nodePanelPresence: state.nodePanelPresence || {},
    isLeader: state.isLeader || false,
    leaderId: collaborationManager.getLeaderId(),
    isEnabled: isCollaborationEnabled,
    startCursorTracking,
    stopCursorTracking,
  }

  return result
}
