import { useEffect, useRef, useCallback, useState, memo } from 'react';
import { ReactFlowProvider } from '@xyflow/react';
import { useShallow } from 'zustand/react/shallow';
import { io as ioClient, Socket } from 'socket.io-client';
import { useTopologyStore } from './store/topologyStore';
import {
  defaultNetworkInfo,
  discoverHosts,
  convertToTopology,
  DiscoveredHost
} from './services/discovery';
import Header from './components/Header';
import LeftPanel from './components/LeftPanel';
import RightPanel from './components/RightPanel';
import TopologyGraph from './components/Graph/TopologyGraph';
import CommandPalette from './components/CommandPalette';
import StaleWarning from './components/StaleWarning';
import TerminalPanel from './components/TerminalPanel';
import MetricsBar from './components/Dashboard/MetricsBar';

const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001';

interface ApiHost {
  name: string;
  ip: string;
  online: boolean;
  containers?: string[];
  services?: string[];
  vms?: Array<{ id: string; name: string; status: string; type: 'lxc' | 'qemu' }>;
}

interface ApiDiscoveryResponse {
  hosts: ApiHost[];
  timestamp: string;
  errors: string[];
}

function App() {
  const {
    setNodes,
    setEdges,
    setNetworkInfo,
    setHosts,
    setLastUpdated,
    setIsLoading,
    setDataSource,
    incrementFailures,
    resetFailures,
    setLastSuccessfulDiscovery,
  } = useTopologyStore(useShallow((s) => ({
    setNodes: s.setNodes,
    setEdges: s.setEdges,
    setNetworkInfo: s.setNetworkInfo,
    setHosts: s.setHosts,
    setLastUpdated: s.setLastUpdated,
    setIsLoading: s.setIsLoading,
    setDataSource: s.setDataSource,
    incrementFailures: s.incrementFailures,
    resetFailures: s.resetFailures,
    setLastSuccessfulDiscovery: s.setLastSuccessfulDiscovery,
  })));

  const setConnectionStatus = useTopologyStore((s) => s.setConnectionStatus);

  const {
    leftPanelOpen,
    rightPanelOpen,
    isLoading,
    pollInterval,
    terminalOpen,
    terminalHost,
  } = useTopologyStore(useShallow((s) => ({
    leftPanelOpen: s.leftPanelOpen,
    rightPanelOpen: s.rightPanelOpen,
    isLoading: s.isLoading,
    pollInterval: s.pollInterval,
    terminalOpen: s.terminalOpen,
    terminalHost: s.terminalHost,
  })));

  const toggleCommandPalette = useTopologyStore((s) => s.toggleCommandPalette);
  const closeTerminal = useTopologyStore((s) => s.closeTerminal);

  const isLoadingRef = useRef(isLoading);
  isLoadingRef.current = isLoading;
  const pollIntervalRef = useRef(pollInterval);
  pollIntervalRef.current = pollInterval;

  const loadData = useCallback(async () => {
    if (isLoadingRef.current) return;

    setIsLoading(true);

    try {
      const response = await fetch(`${API_BASE_URL}/api/discover`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      });

      if (response.ok) {
        const data: ApiDiscoveryResponse = await response.json();

        const discoveredHosts: DiscoveredHost[] = data.hosts.map((h: ApiHost) => ({
          name: h.name,
          ip: h.ip,
          online: h.online,
          containers: (h.containers || []).map((c: string) => ({
            name: c,
            image: '',
            status: 'running',
            ports: [],
            created: ''
          })),
          services: h.services,
          vms: h.vms
        }));

        const { nodes, edges } = convertToTopology(discoveredHosts, defaultNetworkInfo);

        const hosts = discoveredHosts.map(h => ({
          name: h.name,
          ip: h.ip,
          type: (h.name === 'ubuntu' ? 'vm' :
            h.name === 'proxmox' || h.name === 'truenas' ? 'physical' : 'rpi5') as 'vm' | 'physical' | 'rpi5' | 'container',
          role: h.name === 'ubuntu' ? 'Primary Docker Host' :
            h.name === 'grizzley' ? 'Edge Services' :
              h.name === 'truenas' ? 'Storage (NAS)' :
                h.name === 'proxmox' ? 'Hypervisor' : 'Host',
          containers: h.containers.map(c => c.name),
          services: h.services,
          vms: h.vms
        }));

        setNodes(nodes);
        setEdges(edges);
        setNetworkInfo(defaultNetworkInfo);
        setHosts(hosts);
        setLastUpdated(new Date());
        setDataSource('live');
        setLastSuccessfulDiscovery(new Date());
        resetFailures();
      } else {
        throw new Error(`API error: ${response.status}`);
      }
    } catch (error) {
      console.error('Discovery failed, using simulated data:', error);
      const discoveryResult = await discoverHosts(['ubuntu', 'grizzley', 'truenas', 'ice', 'panda', 'proxmox']);

      const { nodes, edges } = convertToTopology(discoveryResult.hosts, defaultNetworkInfo);

      const hosts = discoveryResult.hosts.map(h => ({
        name: h.name,
        ip: h.ip,
        type: (h.name === 'ubuntu' ? 'vm' :
          h.name === 'proxmox' || h.name === 'truenas' ? 'physical' : 'rpi5') as 'vm' | 'physical' | 'rpi5' | 'container',
        role: h.name === 'ubuntu' ? 'Primary Docker Host' :
          h.name === 'grizzley' ? 'Edge Services' :
            h.name === 'truenas' ? 'Storage (NAS)' :
              h.name === 'proxmox' ? 'Hypervisor' : 'Host',
        containers: h.containers.map(c => c.name)
      }));

      setNodes(nodes);
      setEdges(edges);
      setNetworkInfo(defaultNetworkInfo);
      setHosts(hosts);
      setLastUpdated(new Date());
      setDataSource('simulated');
      incrementFailures();
    } finally {
      setIsLoading(false);
    }
  }, [setNodes, setEdges, setNetworkInfo, setHosts, setLastUpdated, setIsLoading, setDataSource, incrementFailures, resetFailures, setLastSuccessfulDiscovery]);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault();
        toggleCommandPalette();
      }
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [toggleCommandPalette]);

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

  useEffect(() => {
    const intervalId = setInterval(loadData, pollIntervalRef.current);
    return () => clearInterval(intervalId);
  }, [loadData]);

  // --- WebSocket connection (websocket-engineer skill) ---
  useEffect(() => {
    const socket: Socket = ioClient(API_BASE_URL, {
      transports: ['websocket', 'polling'],
      reconnectionDelay: 1000,
      reconnectionDelayMax: 5000,
      reconnectionAttempts: Infinity,
    });

    socket.on('connect', () => {
      setConnectionStatus('ws');
    });

    socket.on('disconnect', () => {
      setConnectionStatus('polling');
    });

    socket.on('connect_error', () => {
      setConnectionStatus('polling');
    });

    // Listen for real-time topology updates
    socket.on('topology:update', (data: ApiDiscoveryResponse) => {
      if (data?.hosts) {
        const discoveredHosts: DiscoveredHost[] = data.hosts.map((h: ApiHost) => ({
          name: h.name,
          ip: h.ip,
          online: h.online,
          containers: (h.containers || []).map((c: string) => ({
            name: c, image: '', status: 'running', ports: [], created: ''
          })),
          services: h.services,
          vms: h.vms
        }));

        const { nodes, edges } = convertToTopology(discoveredHosts, defaultNetworkInfo);
        setNodes(nodes);
        setEdges(edges);
        setLastUpdated(new Date());
      }
    });

    return () => {
      socket.disconnect();
    };
  }, [setConnectionStatus, setNodes, setEdges, setLastUpdated]);

  return (
    <ReactFlowProvider>
      <div className="h-screen w-screen flex flex-col bg-slate-900">
        {/* Skip link for accessibility */}
        <a href="#main-content" className="skip-link">
          Skip to main content
        </a>

        <StaleWarning />
        <Header onRefresh={loadData} isLoading={isLoading} />
        <MetricsBar />

        <div className="flex-1 flex overflow-hidden" role="main" id="main-content" tabIndex={-1}>
          {leftPanelOpen && (
            <LeftPanel />
          )}

          <div className="flex-1">
            <TopologyGraph />
          </div>

          {rightPanelOpen && (
            <RightPanel />
          )}
        </div>

        <Footer />
        <CommandPalette />
        {terminalOpen && terminalHost && (
          <TerminalPanel host={terminalHost} onClose={closeTerminal} />
        )}
      </div>
    </ReactFlowProvider>
  );
}

const Footer = memo(function Footer() {
  const { lastUpdated, nodes, dataSource, pollInterval } = useTopologyStore(
    useShallow((s) => ({
      lastUpdated: s.lastUpdated,
      nodes: s.nodes,
      dataSource: s.dataSource,
      pollInterval: s.pollInterval,
    }))
  );
  const [countdown, setCountdown] = useState(Math.ceil(pollInterval / 1000));
  const pollIntervalRef = useRef(pollInterval);
  pollIntervalRef.current = pollInterval;

  const formatTime = (date: Date | null) => {
    if (!date) return 'Never';
    return date.toLocaleTimeString();
  };

  useEffect(() => {
    setCountdown(Math.ceil(pollInterval / 1000));

    const intervalId = setInterval(() => {
      setCountdown(prev => {
        if (prev <= 1) return Math.ceil(pollIntervalRef.current / 1000);
        return prev - 1;
      });
    }, 1000);

    return () => clearInterval(intervalId);
  }, [lastUpdated, pollInterval]);

  return (
    <div
      className="h-8 bg-slate-800 border-t border-slate-700 px-4 flex items-center justify-between text-xs text-slate-400"
      aria-live="polite"
      aria-atomic="true"
    >
      <span>Nodes: {nodes.length}</span>
      <div className="flex items-center gap-4">
        <span className={`px-2 py-0.5 rounded ${dataSource === 'live' ? 'bg-green-900 text-green-400' : 'bg-yellow-900 text-yellow-400'}`}>
          {dataSource === 'live' ? 'Live' : 'Simulated'}
        </span>
        <span>Next refresh: {countdown}s</span>
        <span>Last updated: {formatTime(lastUpdated)}</span>
      </div>
    </div>
  );
});

export default App;
