import net from 'net';
import http from 'http';
import { FrameParser, encodeMessage } from '@network-tool/shared-protocol';
import type { NetworkMessage, ControlMessage } from '@network-tool/shared-types';

// ============================================================
// 配置
// ============================================================
const SERVER_URL = process.env.SERVER_URL || 'http://localhost:3001';
const NODE_NAME = process.env.NODE_NAME || 'relay-node-1';
const NODE_HOST = process.env.NODE_HOST || '0.0.0.0';
const NODE_PORT = parseInt(process.env.NODE_PORT || '4001', 10);
const TCP_PORT = parseInt(process.env.TCP_PORT || '4101', 10);
const HEARTBEAT_INTERVAL = parseInt(process.env.HEARTBEAT_INTERVAL || '15000', 10);

// ============================================================
// 全局状态
// ============================================================
let nodeId: number | null = null;
const connectedClients = new Map<number, net.Socket>();
// 逻辑连接：两个设备通过同一个节点建立的对等连接
const peerConnections = new Map<string, { deviceA: number; deviceB: number }>();

// ============================================================
// HTTP 请求辅助
// ============================================================
function apiRequest(path: string, method = 'GET', body?: any): Promise<any> {
  return new Promise((resolve, reject) => {
    const url = new URL(path, SERVER_URL);
    const data = body ? JSON.stringify(body) : undefined;

    const options: http.RequestOptions = {
      hostname: url.hostname,
      port: url.port,
      path: url.pathname,
      method,
      headers: {
        'Content-Type': 'application/json',
        ...(data ? { 'Content-Length': Buffer.byteLength(data).toString() } : {}),
      },
    };

    const req = http.request(options, (res) => {
      let body = '';
      res.on('data', (chunk) => (body += chunk));
      res.on('end', () => {
        try {
          resolve(JSON.parse(body));
        } catch {
          reject(new Error(`Invalid JSON response: ${body}`));
        }
      });
    });

    req.on('error', reject);
    if (data) req.write(data);
    req.end();
  });
}

// ============================================================
// 节点注册
// ============================================================
async function registerNode(): Promise<void> {
  try {
    console.log(`[Node] 正在向服务器注册: ${SERVER_URL}`);
    const res = await apiRequest('/api/nodes/register', 'POST', {
      name: NODE_NAME,
      host: NODE_HOST,
      port: TCP_PORT,
    });

    if (res.success) {
      nodeId = res.data.id;
      console.log(`[Node] 注册成功! Node ID: ${nodeId}`);
    } else {
      throw new Error(res.error || 'Registration failed');
    }
  } catch (err) {
    console.error('[Node] 注册失败:', err);
    // 5 秒后重试
    setTimeout(registerNode, 5000);
  }
}

// ============================================================
// 心跳
// ============================================================
async function sendHeartbeat(): Promise<void> {
  if (!nodeId) return;

  try {
    const load = connectedClients.size;
    await apiRequest('/api/nodes/heartbeat', 'POST', {
      node_id: nodeId,
      load,
      status: 'online',
    });
    console.log(`[Node] 心跳 OK | 连接数: ${load}`);
  } catch (err) {
    console.error('[Node] 心跳失败:', err);
  }
}

// ============================================================
// Token 验证
// ============================================================
async function verifyToken(token: string, deviceId: number): Promise<boolean> {
  try {
    const res = await apiRequest('/api/connections/verify-token', 'POST', {
      token,
      device_id: deviceId,
    });
    return res.success && res.data?.valid === true;
  } catch (err) {
    console.error('[Node] Token 验证失败:', err);
    return false;
  }
}

// ============================================================
// TCP 客户端处理
// ============================================================
function handleClientConnection(socket: net.Socket): void {
  const parser = new FrameParser();
  let clientDeviceId: number | null = null;
  let authenticated = false;

  const remoteAddr = `${socket.remoteAddress}:${socket.remotePort}`;
  console.log(`[Node] 新客户端连接: ${remoteAddr}`);

  socket.on('data', async (chunk: Buffer) => {
    const messages = parser.push(chunk);

    for (const msg of messages) {
      // 第一条消息必须是认证消息
      if (!authenticated) {
        if (msg.type === 'auth') {
          try {
            const authData: ControlMessage = JSON.parse(msg.payload);
            if (authData.action === 'connect' && authData.token) {
              const valid = await verifyToken(authData.token, authData.device_id);
              if (valid) {
                authenticated = true;
                clientDeviceId = authData.device_id;
                connectedClients.set(clientDeviceId, socket);

                console.log(`[Node] 客户端认证通过: Device ${clientDeviceId}`);
                socket.write(encodeMessage({
                  type: 'control',
                  from_device_id: 0,
                  to_device_id: clientDeviceId,
                  payload: JSON.stringify({ action: 'connect_ok' }),
                  timestamp: Date.now(),
                  message_id: generateId(),
                }));
              } else {
                socket.write(encodeMessage({
                  type: 'error',
                  from_device_id: 0,
                  to_device_id: authData.device_id,
                  payload: 'Authentication failed: invalid token',
                  timestamp: Date.now(),
                  message_id: generateId(),
                }));
                socket.end();
              }
            }
          } catch {
            socket.write(encodeMessage({
              type: 'error',
              from_device_id: 0,
              to_device_id: 0,
              payload: 'Authentication failed: invalid message',
              timestamp: Date.now(),
              message_id: generateId(),
            }));
            socket.end();
          }
        } else {
          socket.end();
        }
        continue;
      }

      // 已认证的消息转发
      if (msg.type === 'data' || msg.type === 'control') {
        forwardMessage(msg);
      }
    }
  });

  socket.on('close', () => {
    console.log(`[Node] 客户端断开: ${remoteAddr}`);
    if (clientDeviceId !== null) {
      connectedClients.delete(clientDeviceId);
      // 通知对等端
      notifyPeerDisconnect(clientDeviceId);
    }
  });

  socket.on('error', (err) => {
    console.error(`[Node] 客户端错误 ${remoteAddr}:`, err.message);
  });
}

// ============================================================
// 消息转发
// ============================================================
function forwardMessage(msg: NetworkMessage): void {
  const targetSocket = connectedClients.get(msg.to_device_id);

  if (targetSocket && !targetSocket.destroyed) {
    targetSocket.write(encodeMessage(msg));
    console.log(`[Node] 转发消息: Device ${msg.from_device_id} -> Device ${msg.to_device_id}`);
  } else {
    // 目标不在线，通知发送方
    const sourceSocket = connectedClients.get(msg.from_device_id);
    if (sourceSocket && !sourceSocket.destroyed) {
      sourceSocket.write(encodeMessage({
        type: 'error',
        from_device_id: 0,
        to_device_id: msg.from_device_id,
        payload: `Target device ${msg.to_device_id} is not connected`,
        timestamp: Date.now(),
        message_id: generateId(),
      }));
    }
  }
}

// ============================================================
// 对等端断开通告
// ============================================================
function notifyPeerDisconnect(deviceId: number): void {
  for (const [otherId, socket] of connectedClients) {
    if (otherId !== deviceId && !socket.destroyed) {
      socket.write(encodeMessage({
        type: 'control',
        from_device_id: 0,
        to_device_id: otherId,
        payload: JSON.stringify({
          action: 'peer_disconnect',
          device_id: deviceId,
        }),
        timestamp: Date.now(),
        message_id: generateId(),
      }));
    }
  }
}

// ============================================================
// 辅助
// ============================================================
function generateId(): string {
  return Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
}

// ============================================================
// 启动
// ============================================================
async function main(): Promise<void> {
  console.log('═══════════════════════════════════════');
  console.log('  Network Tool - Relay Node');
  console.log('═══════════════════════════════════════');
  console.log(`  Server URL:     ${SERVER_URL}`);
  console.log(`  Node Name:      ${NODE_NAME}`);
  console.log(`  TCP Port:       ${TCP_PORT}`);
  console.log('═══════════════════════════════════════');

  // 1. 注册节点
  await registerNode();

  // 2. 启动 TCP 服务器
  const tcpServer = net.createServer(handleClientConnection);
  tcpServer.listen(TCP_PORT, NODE_HOST, () => {
    console.log(`[Node] TCP 服务启动: ${NODE_HOST}:${TCP_PORT}`);
  });

  // 3. 心跳定时器
  setInterval(sendHeartbeat, HEARTBEAT_INTERVAL);
  // 首次心跳
  setTimeout(sendHeartbeat, 2000);

  // 优雅退出
  process.on('SIGINT', () => {
    console.log('\n[Node] 正在关闭...');
    tcpServer.close(() => {
      console.log('[Node] TCP 服务已关闭');
      process.exit(0);
    });
  });

  process.on('SIGTERM', () => {
    console.log('[Node] 收到 SIGTERM，正在关闭...');
    tcpServer.close(() => process.exit(0));
  });
}

main().catch((err) => {
  console.error('[Node] 启动失败:', err);
  process.exit(1);
});
