'use client'

import { useState, useEffect, useCallback } from 'react'
import { Button } from '@/components/ui/button'

interface PresenceEntry {
  id: string
  clientId: string
  displayName: string
  platform: string
  version: string
  roles: string[]
  connectedAt: number
  lastActivity: number
  host?: string
  ip?: string
  status: 'online' | 'idle' | 'offline'
}

interface DeviceTokenSummary {
  role: string
  scopes?: string[]
  createdAtMs?: number
  rotatedAtMs?: number
  revokedAtMs?: number
  lastUsedAtMs?: number
}

interface PendingDevice {
  requestId: string
  deviceId: string
  displayName?: string
  role?: string
  remoteIp?: string
  isRepair?: boolean
  ts?: number
}

interface PairedDevice {
  id: string
  deviceId: string
  displayName: string
  publicKey?: string
  pairedAt?: number
  lastSeen?: number
  trusted?: boolean
  roles?: string[]
  scopes?: string[]
  tokens?: DeviceTokenSummary[]
  createdAtMs?: number
  approvedAtMs?: number
}

type Tab = 'instances' | 'devices'

function relativeTime(ts: number): string {
  if (!ts) return '--'
  const now = Date.now()
  const diffMs = now - (ts < 1e12 ? ts * 1000 : ts)
  if (diffMs < 0) return 'just now'
  const seconds = Math.floor(diffMs / 1000)
  if (seconds < 60) return `${seconds}s ago`
  const minutes = Math.floor(seconds / 60)
  if (minutes < 60) return `${minutes}m ago`
  const hours = Math.floor(minutes / 60)
  if (hours < 24) return `${hours}h ago`
  const days = Math.floor(hours / 24)
  return `${days}d ago`
}

function statusColor(status: PresenceEntry['status']): string {
  switch (status) {
    case 'online': return 'bg-green-500/20 text-green-400 border-green-500/30'
    case 'idle': return 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'
    case 'offline': return 'bg-zinc-500/20 text-zinc-400 border-zinc-500/30'
    default: return 'bg-zinc-500/20 text-zinc-400 border-zinc-500/30'
  }
}

async function deviceAction(
  action: string,
  params: Record<string, unknown>,
): Promise<{ ok: boolean; error?: string; data?: Record<string, unknown> }> {
  try {
    const res = await fetch('/api/nodes', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ action, ...params }),
    })
    const data = await res.json()
    if (!res.ok) return { ok: false, error: data.error || `Request failed (${res.status})` }
    return { ok: true, data }
  } catch {
    return { ok: false, error: 'Network error' }
  }
}

export function NodesPanel() {
  const [tab, setTab] = useState<Tab>('instances')
  const [nodes, setNodes] = useState<PresenceEntry[]>([])
  const [devices, setDevices] = useState<PairedDevice[]>([])
  const [pendingDevices, setPendingDevices] = useState<PendingDevice[]>([])
  const [connected, setConnected] = useState(true)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  const fetchNodes = useCallback(async () => {
    try {
      const res = await fetch('/api/nodes')
      if (!res.ok) { setError('Failed to fetch nodes'); return }
      const data = await res.json()
      setNodes(data.nodes || data.entries || [])
      setConnected(data.connected !== false)
      setError(null)
    } catch {
      setError('Failed to fetch nodes')
    } finally {
      setLoading(false)
    }
  }, [])

  const fetchDevices = useCallback(async () => {
    try {
      const res = await fetch('/api/nodes?action=devices')
      if (!res.ok) return
      const data = await res.json()
      setDevices(data.paired || data.devices || [])
      setPendingDevices(data.pending || [])
    } catch {
      // silent fallback
    }
  }, [])

  useEffect(() => {
    fetchNodes()
    fetchDevices()
    const interval = setInterval(() => {
      fetchNodes()
      fetchDevices()
    }, 30000)
    return () => clearInterval(interval)
  }, [fetchNodes, fetchDevices])

  const pendingCount = pendingDevices.length
  const totalDeviceCount = devices.length + pendingCount

  return (
    <div className="m-4">
      <div className="flex items-center gap-3 mb-4">
        <h2 className="text-lg font-semibold text-foreground">Nodes / Instances</h2>
        <span
          className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded text-xs font-medium border ${
            connected
              ? 'bg-green-500/10 text-green-400 border-green-500/30'
              : 'bg-red-500/10 text-red-400 border-red-500/30'
          }`}
        >
          {connected ? 'Gateway Connected' : 'Gateway Unreachable'}
        </span>
      </div>

      {/* Tab bar */}
      <div className="flex gap-1 mb-4">
        <Button
          variant={tab === 'instances' ? 'secondary' : 'ghost'}
          size="sm"
          onClick={() => setTab('instances')}
        >
          Instances ({nodes.length})
        </Button>
        <Button
          variant={tab === 'devices' ? 'secondary' : 'ghost'}
          size="sm"
          onClick={() => setTab('devices')}
        >
          Devices ({totalDeviceCount})
          {pendingCount > 0 && (
            <span className="ml-1.5 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-amber-500/20 text-amber-400 border border-amber-500/30">
              {pendingCount}
            </span>
          )}
        </Button>
      </div>

      {error && (
        <div className="mb-4 px-3 py-2 rounded-lg bg-red-500/10 border border-red-500/20 text-red-400 text-sm">
          {error}
        </div>
      )}

      {loading ? (
        <div className="text-muted-foreground text-sm py-8 text-center">Loading...</div>
      ) : tab === 'instances' ? (
        <InstancesTab nodes={nodes} />
      ) : (
        <DevicesTab
          devices={devices}
          pendingDevices={pendingDevices}
          onRefresh={fetchDevices}
        />
      )}
    </div>
  )
}

function InstancesTab({ nodes }: { nodes: PresenceEntry[] }) {
  if (nodes.length === 0) {
    return (
      <div className="text-muted-foreground text-sm py-8 text-center">
        No active instances. Nodes appear here when they connect to the gateway.
      </div>
    )
  }

  return (
    <div className="overflow-x-auto">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b border-border text-left text-muted-foreground">
            <th className="pb-2 pr-4 font-medium">Name</th>
            <th className="pb-2 pr-4 font-medium">Client ID</th>
            <th className="pb-2 pr-4 font-medium">Platform</th>
            <th className="pb-2 pr-4 font-medium">Version</th>
            <th className="pb-2 pr-4 font-medium">Roles</th>
            <th className="pb-2 pr-4 font-medium">Status</th>
            <th className="pb-2 pr-4 font-medium">Connected</th>
            <th className="pb-2 pr-4 font-medium">Last Activity</th>
            <th className="pb-2 font-medium">Host / IP</th>
          </tr>
        </thead>
        <tbody>
          {nodes.map((node) => (
            <tr key={node.id} className="border-b border-border/50">
              <td className="py-2 pr-4 text-foreground font-medium">{node.displayName}</td>
              <td className="py-2 pr-4 text-muted-foreground font-mono text-xs">
                {node.clientId?.slice(0, 12)}...
              </td>
              <td className="py-2 pr-4 text-muted-foreground">{node.platform}</td>
              <td className="py-2 pr-4 text-muted-foreground">{node.version}</td>
              <td className="py-2 pr-4">
                <div className="flex gap-1 flex-wrap">
                  {(node.roles || []).map((role) => (
                    <span
                      key={role}
                      className="px-1.5 py-0.5 rounded text-xs bg-secondary text-muted-foreground"
                    >
                      {role}
                    </span>
                  ))}
                </div>
              </td>
              <td className="py-2 pr-4">
                <span
                  className={`inline-flex px-2 py-0.5 rounded text-xs font-medium border ${statusColor(node.status)}`}
                >
                  {node.status}
                </span>
              </td>
              <td className="py-2 pr-4 text-muted-foreground text-xs">
                {relativeTime(node.connectedAt)}
              </td>
              <td className="py-2 pr-4 text-muted-foreground text-xs">
                {relativeTime(node.lastActivity)}
              </td>
              <td className="py-2 text-muted-foreground text-xs font-mono">
                {node.host || node.ip || '--'}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

function DevicesTab({
  devices,
  pendingDevices,
  onRefresh,
}: {
  devices: PairedDevice[]
  pendingDevices: PendingDevice[]
  onRefresh: () => void
}) {
  return (
    <div className="space-y-6">
      {pendingDevices.length > 0 && (
        <PendingDevicesSection devices={pendingDevices} onRefresh={onRefresh} />
      )}
      <PairedDevicesSection devices={devices} onRefresh={onRefresh} />
    </div>
  )
}

function PendingDevicesSection({
  devices,
  onRefresh,
}: {
  devices: PendingDevice[]
  onRefresh: () => void
}) {
  const [actionLoading, setActionLoading] = useState<string | null>(null)
  const [actionError, setActionError] = useState<string | null>(null)

  async function handleAction(action: 'approve' | 'reject', requestId: string) {
    setActionError(null)
    setActionLoading(`${action}-${requestId}`)
    const result = await deviceAction(action, { requestId })
    setActionLoading(null)
    if (!result.ok) {
      setActionError(result.error || 'Action failed')
    } else {
      onRefresh()
    }
  }

  return (
    <div>
      <h3 className="text-sm font-medium text-amber-400 mb-2">
        Pending Pairing Requests ({devices.length})
      </h3>
      {actionError && (
        <div className="mb-2 px-3 py-1.5 rounded bg-red-500/10 border border-red-500/20 text-red-400 text-xs">
          {actionError}
        </div>
      )}
      <div className="space-y-2">
        {devices.map((device) => (
          <div
            key={device.requestId}
            className="flex items-center justify-between px-3 py-2 rounded-lg bg-amber-500/5 border border-amber-500/20"
          >
            <div className="flex items-center gap-3">
              <div>
                <span className="text-sm font-medium text-foreground">
                  {device.displayName || device.deviceId}
                </span>
                <div className="flex items-center gap-2 text-xs text-muted-foreground">
                  <span className="font-mono">{device.deviceId?.slice(0, 16)}</span>
                  {device.role && (
                    <span className="px-1.5 py-0.5 rounded bg-secondary text-muted-foreground">
                      {device.role}
                    </span>
                  )}
                  {device.remoteIp && <span>{device.remoteIp}</span>}
                  {device.isRepair && (
                    <span className="px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400 border border-blue-500/30">
                      repair
                    </span>
                  )}
                  {device.ts && <span>{relativeTime(device.ts)}</span>}
                </div>
              </div>
            </div>
            <div className="flex gap-2">
              <Button
                size="sm"
                variant="ghost"
                className="text-green-400 hover:text-green-300 hover:bg-green-500/10"
                disabled={actionLoading !== null}
                onClick={() => handleAction('approve', device.requestId)}
              >
                {actionLoading === `approve-${device.requestId}` ? 'Approving...' : 'Approve'}
              </Button>
              <Button
                size="sm"
                variant="ghost"
                className="text-red-400 hover:text-red-300 hover:bg-red-500/10"
                disabled={actionLoading !== null}
                onClick={() => handleAction('reject', device.requestId)}
              >
                {actionLoading === `reject-${device.requestId}` ? 'Rejecting...' : 'Reject'}
              </Button>
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}

function PairedDevicesSection({
  devices,
  onRefresh,
}: {
  devices: PairedDevice[]
  onRefresh: () => void
}) {
  const [actionLoading, setActionLoading] = useState<string | null>(null)
  const [actionError, setActionError] = useState<string | null>(null)
  const [confirmRevoke, setConfirmRevoke] = useState<string | null>(null)
  const [expandedDevice, setExpandedDevice] = useState<string | null>(null)

  async function handleRotateToken(deviceId: string, role?: string) {
    setActionError(null)
    setActionLoading(`rotate-${deviceId}`)
    const result = await deviceAction('rotate-token', { deviceId, role })
    setActionLoading(null)
    if (!result.ok) {
      setActionError(result.error || 'Failed to rotate token')
    } else {
      onRefresh()
    }
  }

  async function handleRevokeToken(deviceId: string, role?: string) {
    setActionError(null)
    setActionLoading(`revoke-${deviceId}`)
    const result = await deviceAction('revoke-token', { deviceId, role })
    setActionLoading(null)
    setConfirmRevoke(null)
    if (!result.ok) {
      setActionError(result.error || 'Failed to revoke token')
    } else {
      onRefresh()
    }
  }

  if (devices.length === 0) {
    return (
      <div className="text-muted-foreground text-sm py-8 text-center">
        No paired devices.
      </div>
    )
  }

  return (
    <div>
      <h3 className="text-sm font-medium text-muted-foreground mb-2">
        Paired Devices ({devices.length})
      </h3>
      {actionError && (
        <div className="mb-2 px-3 py-1.5 rounded bg-red-500/10 border border-red-500/20 text-red-400 text-xs">
          {actionError}
        </div>
      )}
      <div className="overflow-x-auto">
        <table className="w-full text-sm">
          <thead>
            <tr className="border-b border-border text-left text-muted-foreground">
              <th className="pb-2 pr-4 font-medium">Name</th>
              <th className="pb-2 pr-4 font-medium">Device ID</th>
              <th className="pb-2 pr-4 font-medium">Roles</th>
              <th className="pb-2 pr-4 font-medium">Paired</th>
              <th className="pb-2 pr-4 font-medium">Last Seen</th>
              <th className="pb-2 pr-4 font-medium">Trust</th>
              <th className="pb-2 font-medium">Actions</th>
            </tr>
          </thead>
          <tbody>
            {devices.map((device) => {
              const deviceKey = device.deviceId || device.id
              const isExpanded = expandedDevice === deviceKey
              const tokens = device.tokens || []

              return (
                <tr key={device.id || device.deviceId} className="border-b border-border/50 align-top">
                  <td className="py-2 pr-4 text-foreground font-medium">
                    {device.displayName}
                  </td>
                  <td className="py-2 pr-4 text-muted-foreground font-mono text-xs">
                    {(device.deviceId || device.id)?.slice(0, 12)}...
                  </td>
                  <td className="py-2 pr-4">
                    <div className="flex gap-1 flex-wrap">
                      {(device.roles || []).map((role) => (
                        <span
                          key={role}
                          className="px-1.5 py-0.5 rounded text-xs bg-secondary text-muted-foreground"
                        >
                          {role}
                        </span>
                      ))}
                    </div>
                  </td>
                  <td className="py-2 pr-4 text-muted-foreground text-xs">
                    {relativeTime(device.pairedAt || device.approvedAtMs || device.createdAtMs || 0)}
                  </td>
                  <td className="py-2 pr-4 text-muted-foreground text-xs">
                    {device.lastSeen ? relativeTime(device.lastSeen) : '--'}
                  </td>
                  <td className="py-2 pr-4">
                    {device.trusted ? (
                      <span className="inline-flex px-2 py-0.5 rounded text-xs font-medium border bg-green-500/20 text-green-400 border-green-500/30">
                        trusted
                      </span>
                    ) : (
                      <span className="inline-flex px-2 py-0.5 rounded text-xs font-medium border bg-zinc-500/20 text-zinc-400 border-zinc-500/30">
                        untrusted
                      </span>
                    )}
                  </td>
                  <td className="py-2">
                    <div className="flex flex-col gap-1">
                      <div className="flex gap-1">
                        <Button
                          size="sm"
                          variant="ghost"
                          className="h-7 px-2 text-xs"
                          disabled={actionLoading !== null}
                          onClick={() => handleRotateToken(deviceKey)}
                        >
                          {actionLoading === `rotate-${deviceKey}` ? '...' : 'Rotate Token'}
                        </Button>
                        {confirmRevoke === deviceKey ? (
                          <div className="flex gap-1 items-center">
                            <span className="text-xs text-red-400">Revoke?</span>
                            <Button
                              size="sm"
                              variant="ghost"
                              className="h-7 px-2 text-xs text-red-400 hover:bg-red-500/10"
                              disabled={actionLoading !== null}
                              onClick={() => handleRevokeToken(deviceKey)}
                            >
                              {actionLoading === `revoke-${deviceKey}` ? '...' : 'Yes'}
                            </Button>
                            <Button
                              size="sm"
                              variant="ghost"
                              className="h-7 px-2 text-xs"
                              onClick={() => setConfirmRevoke(null)}
                            >
                              No
                            </Button>
                          </div>
                        ) : (
                          <Button
                            size="sm"
                            variant="ghost"
                            className="h-7 px-2 text-xs text-red-400 hover:bg-red-500/10"
                            disabled={actionLoading !== null}
                            onClick={() => setConfirmRevoke(deviceKey)}
                          >
                            Revoke
                          </Button>
                        )}
                        {tokens.length > 0 && (
                          <Button
                            size="sm"
                            variant="ghost"
                            className="h-7 px-2 text-xs text-muted-foreground"
                            onClick={() => setExpandedDevice(isExpanded ? null : deviceKey)}
                          >
                            {isExpanded ? 'Hide Tokens' : `Tokens (${tokens.length})`}
                          </Button>
                        )}
                      </div>
                      {isExpanded && tokens.length > 0 && (
                        <div className="mt-1 space-y-1">
                          {tokens.map((token, i) => (
                            <div
                              key={i}
                              className="flex items-center gap-2 px-2 py-1 rounded bg-secondary/50 text-xs"
                            >
                              <span className="font-medium text-foreground">{token.role}</span>
                              {token.scopes && token.scopes.length > 0 && (
                                <span className="text-muted-foreground">
                                  [{token.scopes.join(', ')}]
                                </span>
                              )}
                              {token.lastUsedAtMs && (
                                <span className="text-muted-foreground">
                                  used {relativeTime(token.lastUsedAtMs)}
                                </span>
                              )}
                              {token.revokedAtMs && (
                                <span className="text-red-400">revoked</span>
                              )}
                              <div className="flex gap-1 ml-auto">
                                <Button
                                  size="sm"
                                  variant="ghost"
                                  className="h-5 px-1.5 text-[10px]"
                                  disabled={actionLoading !== null}
                                  onClick={() => handleRotateToken(deviceKey, token.role)}
                                >
                                  Rotate
                                </Button>
                                <Button
                                  size="sm"
                                  variant="ghost"
                                  className="h-5 px-1.5 text-[10px] text-red-400 hover:bg-red-500/10"
                                  disabled={actionLoading !== null || !!token.revokedAtMs}
                                  onClick={() => handleRevokeToken(deviceKey, token.role)}
                                >
                                  Revoke
                                </Button>
                              </div>
                            </div>
                          ))}
                        </div>
                      )}
                    </div>
                  </td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
    </div>
  )
}
