import React, { useState, useEffect } from 'react';
import { Database, Cpu, Plus, Trash2, Copy, Check, AlertCircle, Loader2, Clock, Server } from 'lucide-react';
import { Card } from './ui/card';
import { Badge } from './ui/badge';
import { cn } from '../lib/utils';

const apiHeaders = () => ({
  'Content-Type': 'application/json',
  'Authorization': `Bearer ${localStorage.getItem('auth_token') ?? ''}`,
});

interface NodeInfo {
  id: string;
  name: string;
  type: 'storage' | 'worker';
  endpoint: string;
  status: 'pending' | 'online' | 'offline';
  version: string;
  lastSeen: string | null;
  createdAt: string;
}

interface NewTokenCard {
  nodeId: string;
  name: string;
  token: string;
  type: string;
}

const StatusDot: React.FC<{ status: string }> = ({ status }) => {
  if (status === 'online') return (
    <span className="relative flex h-2.5 w-2.5 flex-shrink-0">
      <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" />
      <span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500" />
    </span>
  );
  if (status === 'offline') return <span className="h-2.5 w-2.5 rounded-full bg-destructive flex-shrink-0" />;
  return <span className="h-2.5 w-2.5 rounded-full bg-amber-400 animate-pulse flex-shrink-0" />;
};

const formatLastSeen = (lastSeen: string | null): string => {
  if (!lastSeen) return 'Never';
  const diff = Math.floor((Date.now() - new Date(lastSeen).getTime()) / 1000);
  if (diff < 60) return `${diff}s ago`;
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
  return new Date(lastSeen).toLocaleString();
};

export const Nodes: React.FC = () => {
  const [nodes, setNodes] = useState<NodeInfo[]>([]);
  const [loading, setLoading] = useState(true);
  const [tab, setTab] = useState<'storage' | 'worker'>('storage');
  const [showAdd, setShowAdd] = useState(false);
  const [addForm, setAddForm] = useState({ name: '', type: 'storage' as 'storage' | 'worker', endpoint: '' });
  const [addLoading, setAddLoading] = useState(false);
  const [addError, setAddError] = useState<string | null>(null);
  const [newToken, setNewToken] = useState<NewTokenCard | null>(null);
  const [copied, setCopied] = useState(false);
  const isDev = import.meta.env.DEV;

  const fetchNodes = async () => {
    try {
      const res = await fetch('/api/nodes', { headers: apiHeaders() });
      const data = await res.json();
      setNodes(data.nodes ?? []);
    } catch (err) {
      console.error('Failed to fetch nodes', err);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { fetchNodes(); }, []);

  const handleAdd = async (e: React.FormEvent) => {
    e.preventDefault();
    setAddError(null);
    setAddLoading(true);
    try {
      const res = await fetch('/api/nodes', {
        method: 'POST',
        headers: apiHeaders(),
        body: JSON.stringify(addForm),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Failed to create node');
      setNodes(prev => [...prev, data]);
      setNewToken({ nodeId: data.id, name: data.name, token: data.token, type: data.type });
      setShowAdd(false);
      setAddForm({ name: '', type: 'storage', endpoint: '' });
      setTab(data.type);
    } catch (err) {
      setAddError((err as Error).message);
    } finally {
      setAddLoading(false);
    }
  };

  const handleDelete = async (nodeId: string) => {
    try {
      await fetch(`/api/nodes?id=${nodeId}`, { method: 'DELETE', headers: apiHeaders() });
      setNodes(prev => prev.filter(n => n.id !== nodeId));
    } catch (err) {
      console.error('Failed to delete node', err);
    }
  };

  const handleDevPing = async (nodeId: string) => {
    try {
      const res = await fetch(`/api/dev/nodes/ping?id=${nodeId}`, { method: 'POST', headers: apiHeaders() });
      if (res.ok) fetchNodes();
    } catch (err) {
      console.error('Failed to ping node', err);
    }
  };

  const copyToClipboard = async (text: string) => {
    await navigator.clipboard.writeText(text);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  const filteredNodes = nodes.filter(n => n.type === tab);
  const storageCount = nodes.filter(n => n.type === 'storage').length;
  const workerCount = nodes.filter(n => n.type === 'worker').length;

  return (
    <div className="space-y-8 animate-in fade-in slide-in-from-bottom-2 duration-500">
      <div className="flex items-center justify-between">
        <div>
          <h2 className="text-3xl font-black tracking-tight text-foreground">Infrastructure</h2>
          <p className="text-sm text-muted-foreground mt-1">Manage your self-hosted storage nodes and workers.</p>
        </div>
        <button
          onClick={() => setShowAdd(v => !v)}
          className="flex items-center gap-2 px-4 py-2.5 bg-primary text-primary-foreground rounded-xl font-bold text-sm hover:bg-primary/90 shadow-lg shadow-primary/20 transition-all"
        >
          <Plus className="w-4 h-4" />
          Add Node
        </button>
      </div>

      {/* Token reveal card — shown once after node creation */}
      {newToken && (
        <Card className="border-emerald-500/30 bg-emerald-500/5 p-6">
          <div className="flex items-start justify-between mb-3">
            <div>
              <h3 className="font-black text-base text-foreground">Node registered: {newToken.name}</h3>
              <p className="text-xs text-muted-foreground mt-0.5">Copy this token now — it won't be shown again.</p>
            </div>
            <button onClick={() => setNewToken(null)} className="text-muted-foreground hover:text-foreground text-xl leading-none px-1">&times;</button>
          </div>
          <div className="bg-background/60 rounded-xl p-4 font-mono text-xs break-all text-foreground border border-border/50 mb-3">
            {newToken.token}
          </div>
          <div className="flex gap-2 flex-wrap mb-4">
            <button
              onClick={() => copyToClipboard(newToken.token)}
              className="flex items-center gap-1.5 px-3 py-1.5 bg-primary/10 text-primary rounded-xl text-xs font-bold hover:bg-primary/20 transition-all"
            >
              {copied ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />}
              {copied ? 'Copied!' : 'Copy Token'}
            </button>
          </div>
          <div className="space-y-1.5">
            <p className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/60">Connect command (websocat)</p>
            <div className="bg-background/60 rounded-xl p-3 font-mono text-xs text-muted-foreground border border-border/50 break-all">
              {`websocat ws://localhost:8080/ws/node?token=${newToken.token}`}
            </div>
          </div>
          <div className="mt-2 space-y-1.5">
            <p className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/60">Send heartbeat (over the open connection)</p>
            <div className="bg-background/60 rounded-xl p-3 font-mono text-xs text-muted-foreground border border-border/50">
              {'{"type":"heartbeat","version":"1.0.0"}'}
            </div>
          </div>
          <p className="mt-2 text-[10px] text-muted-foreground/40">The node connects outbound — no open ports needed. Status updates to offline when the connection drops.</p>
          {isDev && (
            <div className="mt-3">
              <p className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/60 mb-2">Dev: simulate heartbeat</p>
              <button
                onClick={() => handleDevPing(newToken.nodeId)}
                className="px-3 py-1.5 bg-muted text-foreground rounded-lg text-xs font-bold hover:bg-muted/80 transition-all"
              >
                Ping Node
              </button>
            </div>
          )}
        </Card>
      )}

      {/* Add form */}
      {showAdd && (
        <Card className="border-border/50 bg-card/40 backdrop-blur-xl p-6">
          <h3 className="font-black text-lg mb-4">Register Node</h3>
          <form onSubmit={handleAdd} className="space-y-4">
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <div className="space-y-1.5">
                <label className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/60">Name</label>
                <input
                  type="text"
                  value={addForm.name}
                  onChange={e => setAddForm(f => ({ ...f, name: e.target.value }))}
                  placeholder="e.g. Primary Storage"
                  className="w-full px-4 py-3 bg-background border border-border/50 rounded-xl text-foreground placeholder:text-muted-foreground/30 focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all text-sm"
                  required
                />
              </div>
              <div className="space-y-1.5">
                <label className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/60">Type</label>
                <select
                  value={addForm.type}
                  onChange={e => setAddForm(f => ({ ...f, type: e.target.value as 'storage' | 'worker' }))}
                  className="w-full px-4 py-3 bg-background border border-border/50 rounded-xl text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all text-sm"
                >
                  <option value="storage">Storage Node</option>
                  <option value="worker">Worker Node</option>
                </select>
              </div>
            </div>
            <div className="space-y-1.5">
              <label className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/60">Endpoint URL (optional)</label>
              <input
                type="url"
                value={addForm.endpoint}
                onChange={e => setAddForm(f => ({ ...f, endpoint: e.target.value }))}
                placeholder="http://your-node.example.com:9000"
                className="w-full px-4 py-3 bg-background border border-border/50 rounded-xl text-foreground placeholder:text-muted-foreground/30 focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all text-sm"
              />
            </div>
            {addError && (
              <div className="flex items-center gap-2 text-destructive text-xs">
                <AlertCircle className="w-4 h-4 flex-shrink-0" />
                {addError}
              </div>
            )}
            <div className="flex gap-2">
              <button
                type="submit"
                disabled={addLoading || !addForm.name.trim()}
                className="px-6 py-2.5 bg-primary text-primary-foreground rounded-xl font-bold text-sm hover:bg-primary/90 disabled:opacity-50 transition-all flex items-center gap-2"
              >
                {addLoading && <Loader2 className="w-4 h-4 animate-spin" />}
                Register
              </button>
              <button
                type="button"
                onClick={() => { setShowAdd(false); setAddError(null); }}
                className="px-6 py-2.5 bg-muted text-foreground rounded-xl font-bold text-sm hover:bg-muted/80 transition-all"
              >
                Cancel
              </button>
            </div>
          </form>
        </Card>
      )}

      {/* Tabs */}
      <Card className="border-border/50 bg-card/40 backdrop-blur-xl p-1">
        <div className="flex p-1 gap-1">
          {(['storage', 'worker'] as const).map(t => (
            <button
              key={t}
              onClick={() => setTab(t)}
              className={cn(
                "flex-1 flex items-center justify-center gap-2 py-3 rounded-xl text-[10px] font-black uppercase tracking-widest transition-all",
                tab === t
                  ? "bg-primary text-primary-foreground shadow-lg shadow-primary/20"
                  : "text-muted-foreground hover:bg-muted hover:text-foreground"
              )}
            >
              {t === 'storage' ? <Database className="w-4 h-4" /> : <Cpu className="w-4 h-4" />}
              {t === 'storage' ? `Storage (${storageCount})` : `Workers (${workerCount})`}
            </button>
          ))}
        </div>
      </Card>

      {/* Node list */}
      {loading ? (
        <div className="flex flex-col items-center justify-center py-20 gap-4">
          <Loader2 className="w-10 h-10 animate-spin text-primary opacity-20" />
          <span className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/40">Loading nodes...</span>
        </div>
      ) : filteredNodes.length === 0 ? (
        <Card className="border-dashed border-2 py-24 bg-muted/5">
          <div className="flex flex-col items-center justify-center text-center space-y-4 opacity-40">
            {tab === 'storage' ? <Database className="w-14 h-14 text-muted-foreground" /> : <Cpu className="w-14 h-14 text-muted-foreground" />}
            <div className="space-y-1">
              <h3 className="text-lg font-black tracking-tighter">
                No {tab === 'storage' ? 'Storage Nodes' : 'Workers'}
              </h3>
              <p className="text-sm text-muted-foreground max-w-xs mx-auto">
                Register a {tab === 'storage' ? 'storage node' : 'worker'} to get started.
              </p>
            </div>
          </div>
        </Card>
      ) : (
        <div className="grid grid-cols-1 gap-4">
          {filteredNodes.map(node => (
            <Card key={node.id} className="border-border/50 bg-card/40 backdrop-blur-sm group hover:border-primary/30 transition-all">
              <div className="p-6">
                <div className="flex items-start justify-between">
                  <div className="flex items-center gap-4">
                    <div className="w-12 h-12 rounded-xl bg-primary/10 border border-primary/20 flex items-center justify-center text-primary">
                      {node.type === 'storage' ? <Database className="w-5 h-5" /> : <Cpu className="w-5 h-5" />}
                    </div>
                    <div>
                      <div className="flex items-center gap-2">
                        <StatusDot status={node.status} />
                        <h4 className="font-black text-lg text-foreground tracking-tight">{node.name}</h4>
                      </div>
                      <p className="text-xs text-muted-foreground/60 mt-0.5">{node.endpoint || 'No endpoint configured'}</p>
                    </div>
                  </div>
                  <div className="flex items-center gap-2">
                    <Badge className={cn(
                      "text-[10px] font-black uppercase tracking-widest",
                      node.status === 'online' ? "bg-emerald-500/10 text-emerald-500 border-emerald-500/20" :
                      node.status === 'offline' ? "bg-destructive/10 text-destructive border-destructive/20" :
                      "bg-amber-400/10 text-amber-400 border-amber-400/20"
                    )}>
                      {node.status}
                    </Badge>
                    {isDev && (
                      <button
                        onClick={() => handleDevPing(node.id)}
                        className="px-2.5 py-1.5 bg-muted/60 text-muted-foreground hover:text-foreground rounded-lg text-[10px] font-black uppercase tracking-widest opacity-0 group-hover:opacity-100 transition-all"
                        title="Simulate heartbeat (dev only)"
                      >
                        Ping
                      </button>
                    )}
                    <button
                      onClick={() => handleDelete(node.id)}
                      className="p-2 text-muted-foreground/40 hover:text-destructive rounded-lg opacity-0 group-hover:opacity-100 transition-all"
                    >
                      <Trash2 className="w-4 h-4" />
                    </button>
                  </div>
                </div>
                <div className="mt-4 flex flex-wrap gap-4 text-xs text-muted-foreground/60">
                  {node.version && (
                    <span className="flex items-center gap-1">
                      <Server className="w-3.5 h-3.5" />
                      v{node.version}
                    </span>
                  )}
                  <span className="flex items-center gap-1">
                    <Clock className="w-3.5 h-3.5" />
                    Last seen: {formatLastSeen(node.lastSeen)}
                  </span>
                </div>
              </div>
            </Card>
          ))}
        </div>
      )}
    </div>
  );
};
