import { useCallback, useEffect, useState, useRef } from 'react'
import { MonitorDot, ChevronDown } from 'lucide-react'
import { createPortal } from 'react-dom'
import {
  activeInterconnectNodeId,
  api,
  setActiveInterconnectNodeId,
} from '@/api'
import { getNodes, type InterconnectNode } from '@/api/interconnect'
import { useEventBus } from '@/hooks/useEventBus'
import { SYSTEM_EVENTS } from '@/constants'
import { cn } from '@/lib/utils'

export function NodeSwitcher() {
  const [nodes, setNodes] = useState<InterconnectNode[]>([])
  const [selected, setSelected] = useState('local')
  const [isMaster, setIsMaster] = useState(false)
  const [open, setOpen] = useState(false)
  const [menuStyle, setMenuStyle] = useState<React.CSSProperties>({})
  const [mounted, setMounted] = useState(false)
  const buttonRef = useRef<HTMLButtonElement>(null)

  const fetchNodes = useCallback(async () => {
    try {
      const res = await getNodes()
      setNodes(Array.isArray(res) ? res : [])
    } catch {
      setNodes([])
    }
  }, [])

  const updateRoleState = useCallback(
    (role: string) => {
      const master = role === 'master'
      setIsMaster(master)
      if (master) {
        setSelected(activeInterconnectNodeId || 'local')
        fetchNodes()
      } else {
        setNodes([])
        setSelected('local')
        if (typeof document !== 'undefined') {
          const traveling = !!document.cookie.match(/(?:^| )active_interconnect_node_id=([^;]*)/)
          if (activeInterconnectNodeId && !traveling) {
            setActiveInterconnectNodeId('')
          }
        }
      }
    },
    [fetchNodes],
  )

  useEffect(() => {
    setMounted(true)
    // 在客户端初始化时从 localStorage 读取选中的节点
    setSelected(activeInterconnectNodeId || 'local')
  }, [])

  useEffect(() => {
    ;(async () => {
      try {
        const role = await api.settings.get('interconnect', 'interconnect_role')
        updateRoleState(role || 'none')
      } catch {
        updateRoleState('none')
      }
    })()
  }, [updateRoleState])

  useEventBus(SYSTEM_EVENTS.INTERCONNECT_ROLE_CHANGED, (role) => {
    updateRoleState(String(role || 'none'))
  })

  useEffect(() => {
    if (!isMaster) return
    const t = window.setInterval(fetchNodes, 120000)
    const onVis = () => {
      if (document.visibilityState === 'visible') fetchNodes()
    }
    document.addEventListener('visibilitychange', onVis)
    return () => {
      clearInterval(t)
      document.removeEventListener('visibilitychange', onVis)
    }
  }, [isMaster, fetchNodes])

  useEffect(() => {
    if (!open) return
    const updateMenuPosition = () => {
      const el = buttonRef.current
      if (!el) return
      const rect = el.getBoundingClientRect()
      const viewportH = window.innerHeight
      const spaceBelow = viewportH - rect.bottom
      const openUp = spaceBelow < 220 && rect.top > spaceBelow
      setMenuStyle({
        position: 'fixed',
        left: rect.left,
        width: Math.max(rect.width, 140),
        zIndex: 80,
        ...(openUp
          ? { bottom: viewportH - rect.top + 6, top: 'auto' }
          : { top: rect.bottom + 6, bottom: 'auto' }),
      })
    }
    updateMenuPosition()
    const onDoc = (e: MouseEvent) => {
      const t = e.target as Node
      if (buttonRef.current?.contains(t)) return
      setOpen(false)
    }
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') setOpen(false)
    }
    const onReposition = () => updateMenuPosition()
    document.addEventListener('mousedown', onDoc)
    document.addEventListener('keydown', onKey)
    window.addEventListener('resize', onReposition)
    window.addEventListener('scroll', onReposition, true)
    return () => {
      document.removeEventListener('mousedown', onDoc)
      document.removeEventListener('keydown', onKey)
      window.removeEventListener('resize', onReposition)
      window.removeEventListener('scroll', onReposition, true)
    }
  }, [open])

  // SSR 时或非 master 节点时返回 null
  if (!mounted || !isMaster) return null

  const handleSelect = (val: string) => {
    setSelected(val)
    setOpen(false)
    if (val === 'local') {
      setActiveInterconnectNodeId('')
    } else {
      const name = nodes.find((n) => n.id === val)?.name || ''
      setActiveInterconnectNodeId(val, name)
    }
    window.location.reload()
  }

  const allOptions = [
    { value: 'local', label: '本机节点' },
    ...nodes.map((n) => ({ value: n.id, label: n.name })),
  ]

  const currentLabel = allOptions.find((o) => o.value === selected)?.label || '本机节点'

  return (
    <div className="relative">
      <button
        ref={buttonRef}
        type="button"
        onClick={() => setOpen(!open)}
        className={cn(
          'inline-flex h-8 max-w-[150px] shrink-0 items-center gap-1.5 rounded-md border px-2 text-[11px] leading-none transition-colors',
          selected !== 'local'
            ? 'border-amber-500/30 bg-amber-500/10 text-amber-600 hover:bg-amber-500/15 dark:text-amber-400'
            : 'border-[var(--border)] bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]',
        )}
      >
        <MonitorDot size={12} className="shrink-0" />
        <span className="max-w-[100px] truncate">{currentLabel}</span>
        <ChevronDown size={12} className="shrink-0 opacity-60" />
      </button>

      {open &&
        mounted &&
        createPortal(
          <div className="ui-select-menu" style={menuStyle}>
            {allOptions.map((opt) => (
              <button
                key={opt.value}
                type="button"
                onClick={() => handleSelect(opt.value)}
                className={cn('ui-select-item', opt.value === selected && 'is-active')}
              >
                <span className="min-w-0 flex-1 truncate">{opt.label}</span>
              </button>
            ))}
          </div>,
          document.body,
        )}
    </div>
  )
}
