/**
 * Torch Handler
 * Handles multi-browser MCP control synchronization for the sync server.
 * Only one browser can have the "torch" and connect to MCP at a time.
 */

// Client metadata
interface TorchClient {
  ws: any
  id: string
  name: string
  autoRequest: boolean
  userAgent: string
  hostname: string
  connectedAt: Date
}

// Connected torch clients (separate tracking from main clients set)
const torchClients = new Map<any, TorchClient>()
let clientIdCounter = 1

// Torch state - who has control
let torchHolderId: string | null = null

function generateClientId(): string {
  return `client_${clientIdCounter++}_${Date.now().toString(36)}`
}

function broadcastTorchState(broadcast: (message: string, filter?: (ws: any) => boolean) => void) {
  const clientList = Array.from(torchClients.values()).map(c => ({
    id: c.id,
    name: c.name,
    autoRequest: c.autoRequest,
    userAgent: c.userAgent,
    hostname: c.hostname,
    connectedAt: c.connectedAt.toISOString(),
    hasTorch: c.id === torchHolderId
  }))

  const message = JSON.stringify({
    type: 'torch-update',
    holderId: torchHolderId,
    clients: clientList
  })

  broadcast(message)
}

/**
 * Handle torch client connection
 */
export function handleTorchConnect(ws: any, broadcast: (message: string, filter?: (ws: any) => boolean) => void) {
  const id = generateClientId()
  torchClients.set(ws, {
    ws,
    id,
    name: 'Anonymous',
    autoRequest: false,
    userAgent: 'Unknown',
    hostname: 'Unknown',
    connectedAt: new Date()
  })
  console.log(`[Torch] Client connected: ${id} (${torchClients.size} total)`)
}

/**
 * Handle torch messages
 */
export function handleTorchMessage(ws: any, data: any, broadcast: (message: string, filter?: (ws: any) => boolean) => void) {
  const client = torchClients.get(ws)
  if (!client) return

  switch (data.type) {
    case 'register': {
      client.userAgent = data.userAgent || 'Unknown'
      client.hostname = data.hostname || 'Unknown'
      client.name = data.name || 'Anonymous'

      // Claim autoRequest exclusively (only one client at a time)
      if (data.autoRequest) {
        for (const [, c] of torchClients) {
          if (c.id !== client.id) c.autoRequest = false
        }
        client.autoRequest = true
      }

      // Auto-grant torch if requested and no one holds it
      if (client.autoRequest && torchHolderId === null) {
        torchHolderId = client.id
        console.log(`[Torch] Auto-granted torch to ${client.name} (${client.id})`)
      }

      const hasTorch = torchHolderId === client.id

      ws.send(JSON.stringify({
        type: 'registered',
        id: client.id,
        hasTorch
      }))

      console.log(`[Torch] Registered: ${client.name} (${client.id}) (torch: ${hasTorch}, autoRequest: ${client.autoRequest})`)
      broadcastTorchState(broadcast)
      break
    }

    case 'set-auto-request': {
      const value = !!data.value
      if (value) {
        // Exclusive: clear autoRequest from all other clients
        for (const [, c] of torchClients) {
          if (c.id !== client.id) c.autoRequest = false
        }
      }
      client.autoRequest = value
      console.log(`[Torch] Auto-request ${value ? 'claimed by' : 'released by'}: ${client.name} (${client.id})`)
      broadcastTorchState(broadcast)
      break
    }

    case 'update-name': {
      const newName = (data.name || '').substring(0, 20) || 'Anonymous'
      client.name = newName
      console.log(`[Torch] Name updated: ${client.id} → ${newName}`)
      broadcastTorchState(broadcast)
      break
    }

    case 'request': {
      const previousHolder = torchHolderId
      torchHolderId = client.id

      ws.send(JSON.stringify({ type: 'granted' }))
      console.log(`[Torch] Transferred: ${previousHolder} → ${client.name} (${client.id})`)
      broadcastTorchState(broadcast)
      break
    }

    case 'release': {
      if (torchHolderId === client.id) {
        torchHolderId = null
        ws.send(JSON.stringify({ type: 'released' }))
        console.log(`[Torch] Released by: ${client.name} (${client.id})`)
        broadcastTorchState(broadcast)
      }
      break
    }

    case 'transfer': {
      // Transfer torch to a specific client (only if sender has torch or no one has it)
      const targetId = data.targetId
      if (!targetId) {
        ws.send(JSON.stringify({ type: 'error', message: 'targetId required' }))
        break
      }

      // Check if target exists
      let targetExists = false
      for (const [, c] of torchClients) {
        if (c.id === targetId) {
          targetExists = true
          break
        }
      }

      if (!targetExists) {
        ws.send(JSON.stringify({ type: 'error', message: 'Target client not found' }))
        break
      }

      // Only allow transfer if sender has torch or no one has it
      if (torchHolderId !== null && torchHolderId !== client.id) {
        ws.send(JSON.stringify({ type: 'error', message: 'Cannot transfer - you do not have the torch' }))
        break
      }

      const previousHolder = torchHolderId
      torchHolderId = targetId

      ws.send(JSON.stringify({ type: 'transferred', targetId }))
      console.log(`[Torch] Transferred by ${client.name} (${client.id}): ${previousHolder} → ${targetId}`)
      broadcastTorchState(broadcast)
      break
    }
  }
}

/**
 * Handle torch client disconnect
 */
export function handleTorchDisconnect(ws: any, broadcast: (message: string, filter?: (ws: any) => boolean) => void) {
  const client = torchClients.get(ws)
  if (client) {
    console.log(`[Torch] Client disconnected: ${client.name} (${client.id})`)

    // If this client had the torch, release it (no auto-assign)
    if (torchHolderId === client.id) {
      torchHolderId = null
      console.log(`[Torch] Torch released (holder disconnected)`)
    }

    torchClients.delete(ws)
    broadcastTorchState(broadcast)
  }
}

/**
 * Get torch status for health check
 */
export function getTorchStatus() {
  return {
    clients: torchClients.size,
    torchHolder: torchHolderId
  }
}

/**
 * Cleanup torch handler
 */
export function cleanupTorchHandler() {
  torchClients.clear()
  torchHolderId = null
}
