'use client' import { useState, useEffect } from 'react' import { ServerStackIcon, PlusIcon, MagnifyingGlassIcon, WifiIcon, ComputerDesktopIcon, ArrowPathIcon, CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon, UserGroupIcon, KeyIcon } from '@heroicons/react/24/outline' interface DiscoveredNode { id: string hostname: string ip: string port: number version: string capabilities: string[] status: 'online' | 'offline' | 'pending' lastSeen: Date } interface ClusterConfig { mode: 'create' | 'join' networkId: string clusterName: string nodeRole: 'coordinator' | 'worker' | 'hybrid' joinKey?: string targetNode?: string autoDiscovery: boolean encryption: boolean redundancy: number } interface ClusterFormationProps { systemInfo: any configData: any onComplete: (data: any) => void onBack?: () => void isCompleted: boolean } export default function ClusterFormation({ systemInfo, configData, onComplete, onBack, isCompleted }: ClusterFormationProps) { const [config, setConfig] = useState({ mode: 'create', networkId: '', clusterName: '', nodeRole: 'hybrid', autoDiscovery: true, encryption: true, redundancy: 2 }) const [discoveredNodes, setDiscoveredNodes] = useState([]) const [scanning, setScanning] = useState(false) const [generatingKey, setGeneratingKey] = useState(false) const [clusterKey, setClusterKey] = useState('') // Initialize configuration useEffect(() => { if (configData.cluster) { setConfig(prev => ({ ...prev, ...configData.cluster })) } // Generate default network ID based on hostname if (!config.networkId && systemInfo?.network?.hostname) { const hostname = systemInfo.network.hostname const timestamp = Date.now().toString(36).slice(-4) setConfig(prev => ({ ...prev, networkId: `bzzz-${hostname}-${timestamp}`, clusterName: `${hostname} BZZZ Cluster` })) } }, [systemInfo, configData]) // Auto-discover nodes when joining useEffect(() => { if (config.mode === 'join' && config.autoDiscovery) { scanForNodes() } }, [config.mode, config.autoDiscovery]) const scanForNodes = async () => { setScanning(true) try { // This would be a real mDNS/network scan in production // Simulating discovery for demo await new Promise(resolve => setTimeout(resolve, 2000)) const mockNodes: DiscoveredNode[] = [ { id: 'node-001', hostname: 'ironwood', ip: '192.168.1.72', port: 8080, version: '2.0.0', capabilities: ['coordinator', 'storage', 'compute'], status: 'online', lastSeen: new Date() }, { id: 'node-002', hostname: 'walnut', ip: '192.168.1.27', port: 8080, version: '2.0.0', capabilities: ['worker', 'compute'], status: 'online', lastSeen: new Date() } ] setDiscoveredNodes(mockNodes) } catch (error) { console.error('Node discovery failed:', error) } finally { setScanning(false) } } const generateClusterKey = async () => { setGeneratingKey(true) try { // Generate a secure cluster key const key = Array.from(crypto.getRandomValues(new Uint8Array(32))) .map(b => b.toString(16).padStart(2, '0')) .join('') setClusterKey(key) } catch (error) { // Fallback key generation const key = Math.random().toString(36).substr(2, 32) setClusterKey(key) } finally { setGeneratingKey(false) } } const getNodeRoleDescription = (role: string) => { switch (role) { case 'coordinator': return 'Manages cluster state and coordinates tasks. Requires stable network connection.' case 'worker': return 'Executes tasks assigned by coordinators. Can be dynamically added/removed.' case 'hybrid': return 'Can act as both coordinator and worker. Recommended for most deployments.' default: return '' } } const getSystemRecommendation = () => { const memoryGB = systemInfo?.memory_mb ? Math.round(systemInfo.memory_mb / 1024) : 8 const cpuCores = systemInfo?.cpu_cores || 4 const hasGPU = systemInfo?.gpus?.length > 0 if (memoryGB >= 16 && cpuCores >= 8) { return { role: 'coordinator', reason: 'High-performance system suitable for cluster coordination' } } else if (hasGPU) { return { role: 'hybrid', reason: 'GPU acceleration available - good for both coordination and compute tasks' } } else { return { role: 'worker', reason: 'Resource-optimized configuration for task execution' } } } const handleSubmit = (e: React.FormEvent) => { e.preventDefault() const clusterData = { ...config, clusterKey: config.mode === 'create' ? clusterKey : undefined, systemInfo: { hostname: systemInfo?.network?.hostname, ip: systemInfo?.network?.private_ips?.[0], capabilities: systemInfo?.gpus?.length > 0 ? ['compute', 'gpu'] : ['compute'] } } onComplete({ cluster: clusterData }) } const recommendation = getSystemRecommendation() return (
{/* Cluster Mode Selection */}

Cluster Mode

setConfig(prev => ({ ...prev, mode: 'create' }))} >
Create New Cluster
Start a new BZZZ cluster and become the initial coordinator node.
setConfig(prev => ({ ...prev, mode: 'join' }))} >
Join Existing Cluster
Connect to an existing BZZZ cluster as a worker or coordinator node.
{/* Create Cluster Configuration */} {config.mode === 'create' && (

New Cluster Configuration

setConfig(prev => ({ ...prev, clusterName: e.target.value }))} placeholder="My BZZZ Cluster" className="input-field" required />
setConfig(prev => ({ ...prev, networkId: e.target.value }))} placeholder="bzzz-cluster-001" className="input-field" required />

Unique identifier for your cluster network

setClusterKey(e.target.value)} placeholder="Click generate or enter custom key" className="input-field flex-1" readOnly={!clusterKey} />

This key will be required for other nodes to join your cluster

)} {/* Join Cluster Configuration */} {config.mode === 'join' && (

Available Clusters

{discoveredNodes.length > 0 ? (
{discoveredNodes.map((node) => (
setConfig(prev => ({ ...prev, targetNode: node.id }))} >
{node.hostname} {node.status}
{node.ip}:{node.port} • Version {node.version}
{node.capabilities.map((cap, index) => ( {cap} ))}
))}
) : (

{scanning ? 'Scanning for BZZZ clusters...' : 'No clusters found. Click scan to search for available clusters.'}

)} {config.targetNode && (
setConfig(prev => ({ ...prev, joinKey: e.target.value }))} placeholder="Enter cluster security key" className="input-field" required />

Enter the security key provided by the cluster administrator

)}
)} {/* Node Role Configuration */}

Node Role

{/* System Recommendation */}
Recommended: {recommendation.role.charAt(0).toUpperCase() + recommendation.role.slice(1)}
{recommendation.reason}
{['coordinator', 'worker', 'hybrid'].map((role) => (
setConfig(prev => ({ ...prev, nodeRole: role as any }))} >
setConfig(prev => ({ ...prev, nodeRole: role as any }))} className="h-4 w-4 text-bzzz-primary focus:ring-bzzz-primary border-gray-300" />
{role}
{getNodeRoleDescription(role)}
))}
{/* Advanced Options */}

Advanced Options

setConfig(prev => ({ ...prev, autoDiscovery: e.target.checked }))} className="h-4 w-4 text-bzzz-primary focus:ring-bzzz-primary border-gray-300 rounded" />
setConfig(prev => ({ ...prev, encryption: e.target.checked }))} className="h-4 w-4 text-bzzz-primary focus:ring-bzzz-primary border-gray-300 rounded" />

Number of replicas for critical cluster data

{/* Configuration Summary */}
Configuration Summary

• Mode: {config.mode === 'create' ? 'Create new cluster' : 'Join existing cluster'}

• Role: {config.nodeRole}

• Hostname: {systemInfo?.network?.hostname || 'Unknown'}

• IP Address: {systemInfo?.network?.private_ips?.[0] || 'Unknown'}

{config.mode === 'create' &&

• Cluster: {config.clusterName}

} {config.encryption &&

• Security: Encrypted communication enabled

}
{/* Action Buttons */}
{onBack && ( )}
) }