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

const SERVER_URL = process.env.SERVER_URL || 'http://localhost:3001';

export class NetworkClient extends EventEmitter {
  private token: string | null = null;
  private relaySocket: net.Socket | null = null;
  private relayParser = new FrameParser();

  setToken(token: string): void {
    this.token = token;
  }

  /**
   * 向 Control Server 发送 HTTP 请求
   */
  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',
          ...(this.token ? { Authorization: `Bearer ${this.token}` } : {}),
          ...(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 {
            resolve({ success: false, error: 'PARSE_ERROR', message: body });
          }
        });
      });

      req.on('error', (err) => {
        resolve({ success: false, error: 'NETWORK_ERROR', message: err.message });
      });

      if (data) req.write(data);
      req.end();
    });
  }

  /**
   * 带认证的请求
   */
  async authenticatedRequest(path: string, method = 'GET', body?: any): Promise<any> {
    if (!this.token) {
      return { success: false, error: 'NOT_AUTHENTICATED', message: 'Please login first' };
    }
    return this.apiRequest(path, method, body);
  }

  /**
   * 连接到 Relay Node
   */
  connectToRelay(host: string, port: number, token: string, deviceId: number): Promise<void> {
    return new Promise((resolve, reject) => {
      this.disconnectFromRelay();

      this.relaySocket = new net.Socket();
      this.relayParser.reset();

      const timeout = setTimeout(() => {
        reject(new Error('Connection timeout'));
        this.relaySocket?.destroy();
      }, 10000);

      this.relaySocket.connect(port, host, () => {
        clearTimeout(timeout);
        this.emit('status', 'connected');
        console.log(`[Client] 已连接到 Relay Node: ${host}:${port}`);

        // 发送认证消息
        const authMsg: NetworkMessage = {
          type: 'auth',
          from_device_id: deviceId,
          to_device_id: 0,
          payload: JSON.stringify({
            action: 'connect',
            device_id: deviceId,
            token,
          }),
          timestamp: Date.now(),
          message_id: this.generateId(),
        };

        this.relaySocket!.write(encodeMessage(authMsg));
        this.emit('status', 'authenticating');
      });

      this.relaySocket.on('data', (chunk: Buffer) => {
        const messages = this.relayParser.push(chunk);
        for (const msg of messages) {
          if (msg.type === 'control') {
            try {
              const ctrl = JSON.parse(msg.payload);
              if (ctrl.action === 'connect_ok') {
                this.emit('status', 'authenticated');
                resolve();
                continue;
              }
            } catch {}
          }

          // 转发所有消息给渲染进程
          this.emit('message', msg);
        }
      });

      this.relaySocket.on('error', (err) => {
        clearTimeout(timeout);
        this.emit('status', 'error');
        reject(err);
      });

      this.relaySocket.on('close', () => {
        this.emit('status', 'disconnected');
        this.relaySocket = null;
      });
    });
  }

  /**
   * 通过 Relay 发送消息
   */
  sendMessage(targetDeviceId: number, payload: string): void {
    if (!this.relaySocket || this.relaySocket.destroyed) {
      throw new Error('Not connected to relay');
    }

    const msg: NetworkMessage = {
      type: 'data',
      from_device_id: 0, // 不暴露真实 device id 给对端 (relay 会处理)
      to_device_id: targetDeviceId,
      payload,
      timestamp: Date.now(),
      message_id: this.generateId(),
    };

    this.relaySocket.write(encodeMessage(msg));
  }

  /**
   * 断开 Relay 连接
   */
  disconnectFromRelay(): void {
    if (this.relaySocket) {
      this.relaySocket.destroy();
      this.relaySocket = null;
    }
    this.emit('status', 'disconnected');
  }

  private generateId(): string {
    return Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
  }
}
