import { useState, useCallback, ReactNode } from 'react';
import {
  ReactFlow,
  applyNodeChanges,
  applyEdgeChanges,
  addEdge,
  Background,
  Controls,
  ReactFlowProvider,
  NodeTypes,
  NodeChange,
  OnEdgesChange,
  OnConnect,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { AppNode, AppEdge, NodeData } from './types/graph';
import CustomNode from './components/CustomNode';
import NodeEditor from './components/NodeEditor';
import ConfigViewer from './components/ConfigViewer';
import './App.css';

const initialNodes: AppNode[] = [
  {
    id: 'n1',
    position: { x: 250, y: 50 },
    data: {
      label: 'Node-A',
      ipAddress: '10.0.0.1',
      listenPort: '51820',
      privateKey: '',
      publicKey: '',
    },
    type: 'custom',
  },
];
const initialEdges: AppEdge[] = [];


const nodeTypes : NodeTypes = {
  custom: CustomNode,
};

function FlowContent(): ReactNode {
  const [nodes, setNodes] = useState<AppNode[]>(initialNodes);
  const [edges, setEdges] = useState<AppEdge[]>(initialEdges);
  const [editingNode, setEditingNode] = useState<NodeData | null>(null);
  const [showConfigViewer, setShowConfigViewer] = useState(false);

  const onNodesChange = useCallback(
    (changes: NodeChange<AppNode>[]) => setNodes((nds) => applyNodeChanges<AppNode>(changes, nds)),
    [],
  );

  const onEdgesChange = useCallback<OnEdgesChange>(
    (changes) => setEdges((edgesSnapshot) => applyEdgeChanges(changes, edgesSnapshot)),
    [],
  );

  const onConnect = useCallback<OnConnect>(
    (params) => setEdges((edgesSnapshot) => addEdge(params, edgesSnapshot)),
    [],
  );

  const onNodeClick = useCallback((_event: React.MouseEvent, node: AppNode) => {
    setEditingNode(node.data);
  }, []);

  const handleAddNode = (): void => {
    const newNodeId = `n${Date.now()}`;
    const newNode: AppNode = {
      id: newNodeId,
      position: { x: Math.random() * 500, y: Math.random() * 500 },
      data: {
        label: `Node-${String.fromCharCode(65 + (nodes.length % 26))}`,
        ipAddress: `10.0.0.${nodes.length + 2}`,
        listenPort: `${51820 + nodes.length}`,
        privateKey: '',
        publicKey: '',
      },
      type: 'custom',
    };
    setNodes((prev) => [...prev, newNode]);
  };

  const handleUpdateNode = (updatedData: NodeData): void => {
    setNodes((prev) =>
      prev.map((node) => {
        if (node.data.label === editingNode?.label) {
          return { ...node, data: updatedData };
        }
        return node;
      })
    );
    setEditingNode(null);
  };

  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        onNodeClick={onNodeClick}
        nodeTypes={nodeTypes}
        fitView
      >
        <Background />
        <Controls />
      </ReactFlow>

      <div className="toolbar">
        <div className="toolbar-group">
          <button className="toolbar-btn" onClick={handleAddNode} title="添加新节点">
            ➕ 添加节点
          </button>
          <button
            className="toolbar-btn"
            onClick={() => setShowConfigViewer(true)}
            title="查看和下载WireGuard配置"
          >
            📋 配置
          </button>
        </div>
      </div>

      {editingNode && (
        <NodeEditor
          node={editingNode}
          onUpdate={handleUpdateNode}
          onClose={() => setEditingNode(null)}
        />
      )}

      {showConfigViewer && (
        <ConfigViewer
          nodes={nodes}
          edges={edges}
          onClose={() => setShowConfigViewer(false)}
        />
      )}
    </div>
  );
}

export default function App(): ReactNode {
  return (
    <ReactFlowProvider>
      <FlowContent />
    </ReactFlowProvider>
  );
}
