'use client'

import { useCallback, useEffect, useMemo, useState } from 'react'
import { useAuth } from './useAuth'
import type { LobsterStatusMessage } from '@/lib/protocol'

export interface ApiKeyItem {
  id: string
  name: string | null
  prefix?: string
  createdAt?: string
}

export interface OnlineLobster {
  lobsterId?: string
  lobsterName?: string
}

export interface LobsterWithStatus {
  id: string
  name: string
  isOnline: boolean
}

/** Shared lobby state — singleton across all useLobsters() consumers. */
let sharedOnlineLobsters: OnlineLobster[] = []
const listeners = new Set<(lobsters: OnlineLobster[]) => void>()

function notifyListeners(lobsters: OnlineLobster[]) {
  sharedOnlineLobsters = lobsters
  for (const fn of listeners) fn(lobsters)
}

/**
 * Update the shared online lobsters state.
 * Called by RelayProvider when lobster_status messages arrive on the global WebSocket.
 */
export function updateOnlineLobsters(
  action: LobsterStatusMessage['action'],
  lobsters: LobsterStatusMessage['lobsters'],
): void {
  switch (action) {
    case 'list':
      notifyListeners(lobsters)
      break
    case 'online':
      notifyListeners([
        ...sharedOnlineLobsters.filter(
          (existing) => !lobsters.some((l) => l.lobsterId === existing.lobsterId),
        ),
        ...lobsters,
      ])
      break
    case 'offline':
      notifyListeners(
        sharedOnlineLobsters.filter(
          (existing) => !lobsters.some((l) => l.lobsterId === existing.lobsterId),
        ),
      )
      break
  }
}

export function useLobsters() {
  const { authClient } = useAuth()
  const [apiKeys, setApiKeys] = useState<ApiKeyItem[]>([])
  const [onlineLobsters, setOnlineLobsters] = useState<OnlineLobster[]>(sharedOnlineLobsters)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  // Subscribe to shared lobby state
  useEffect(() => {
    const handler = (lobsters: OnlineLobster[]) => setOnlineLobsters(lobsters)
    listeners.add(handler)
    // Sync initial state
    setOnlineLobsters(sharedOnlineLobsters)
    return () => { listeners.delete(handler) }
  }, [])

  const fetchApiKeys = useCallback(async () => {
    setLoading(true)
    setError(null)
    try {
      const { data, error: err } = await authClient.apiKey.list()
      if (err) {
        setError(err.message ?? 'Failed to fetch API keys')
        return
      }
      if (data?.apiKeys) {
        setApiKeys(
          data.apiKeys.map((k) => ({
            id: k.id,
            name: k.name,
            prefix: k.start ?? k.prefix ?? undefined,
            createdAt: k.createdAt ? new Date(k.createdAt).toLocaleDateString() : undefined,
          })),
        )
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err))
    } finally {
      setLoading(false)
    }
  }, [authClient])

  const createApiKey = useCallback(
    async (name: string): Promise<string | null> => {
      setError(null)
      try {
        const { data, error: err } = await authClient.apiKey.create({
          name,
          expiresIn: null,
        })
        if (err) {
          setError(err.message ?? 'Failed to create API key')
          return null
        }
        if (data?.key) {
          // Refresh the list
          await fetchApiKeys()
          return data.key
        }
        return null
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err))
        return null
      }
    },
    [authClient, fetchApiKeys],
  )

  const deleteApiKey = useCallback(
    async (keyId: string) => {
      setError(null)
      try {
        const { error: err } = await authClient.apiKey.delete({ keyId })
        if (err) {
          setError(err.message ?? 'Failed to delete API key')
          return
        }
        // Refresh the list
        await fetchApiKeys()
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err))
      }
    },
    [authClient, fetchApiKeys],
  )

  /** Merge apiKeys (all lobsters) with onlineLobsters → sorted: online first, then offline. */
  const lobstersWithStatus: LobsterWithStatus[] = useMemo(() => {
    const onlineIds = new Set(onlineLobsters.map((l) => l.lobsterId))
    const merged = apiKeys.map((k) => ({
      id: k.id,
      name: k.name ?? 'Unnamed',
      isOnline: onlineIds.has(k.id),
    }))
    // Online first, then offline
    return merged.sort((a, b) => (a.isOnline === b.isOnline ? 0 : a.isOnline ? -1 : 1))
  }, [apiKeys, onlineLobsters])

  return {
    apiKeys,
    onlineLobsters,
    lobstersWithStatus,
    loading,
    error,
    fetchApiKeys,
    createApiKey,
    deleteApiKey,
  }
}
