import 'dart:async';
import 'package:socket_io_client/socket_io_client.dart' as IO;

/// 价格更新数据
class PriceUpdate {
  final String price;
  final String burnMultiplier;
  final int timestamp;

  PriceUpdate({
    required this.price,
    required this.burnMultiplier,
    required this.timestamp,
  });

  factory PriceUpdate.fromJson(Map<String, dynamic> json) {
    return PriceUpdate(
      price: json['price']?.toString() ?? '0',
      burnMultiplier: json['burnMultiplier']?.toString() ?? '0',
      timestamp: json['timestamp'] ?? DateTime.now().millisecondsSinceEpoch,
    );
  }
}

/// WebSocket 连接状态
enum WebSocketStatus {
  disconnected,
  connecting,
  connected,
  reconnecting,
}

/// 价格 WebSocket 服务
///
/// 特性:
/// - 自动断线重连 (指数退避)
/// - 页面切换时手动断开连接
/// - 心跳检测
/// - 连接状态监听
class PriceWebSocketService {
  static PriceWebSocketService? _instance;
  static PriceWebSocketService get instance {
    _instance ??= PriceWebSocketService._();
    return _instance!;
  }

  PriceWebSocketService._();

  IO.Socket? _socket;

  // 连接状态
  WebSocketStatus _status = WebSocketStatus.disconnected;
  WebSocketStatus get status => _status;

  // 重连相关
  Timer? _reconnectTimer;
  int _reconnectAttempts = 0;
  static const int _maxReconnectAttempts = 10;
  static const Duration _initialReconnectDelay = Duration(seconds: 1);
  static const Duration _maxReconnectDelay = Duration(seconds: 30);

  // 价格更新流
  final _priceUpdateController = StreamController<PriceUpdate>.broadcast();
  Stream<PriceUpdate> get priceUpdates => _priceUpdateController.stream;

  // 连接状态流
  final _statusController = StreamController<WebSocketStatus>.broadcast();
  Stream<WebSocketStatus> get statusStream => _statusController.stream;

  // WebSocket URL
  String _wsUrl = '';

  /// 连接到 WebSocket 服务器
  ///
  /// [baseUrl] API 基础地址，例如 https://api.example.com
  void connect(String baseUrl) {
    // 构建 WebSocket URL
    // https://api.example.com -> wss://api.example.com/ws/price
    _wsUrl = baseUrl
        .replaceFirst('https://', 'wss://')
        .replaceFirst('http://', 'ws://');
    _wsUrl = '$_wsUrl/ws/price';

    _doConnect();
  }

  void _doConnect() {
    if (_status == WebSocketStatus.connected ||
        _status == WebSocketStatus.connecting) {
      return;
    }

    _updateStatus(WebSocketStatus.connecting);

    _socket = IO.io(
      _wsUrl,
      IO.OptionBuilder()
          .setTransports(['websocket'])
          .disableAutoConnect()
          .enableReconnection()
          .setReconnectionAttempts(_maxReconnectAttempts)
          .setReconnectionDelay(1000)
          .setReconnectionDelayMax(30000)
          .build(),
    );

    _socket!.onConnect((_) {
      _updateStatus(WebSocketStatus.connected);
      _reconnectAttempts = 0;
      _cancelReconnectTimer();
    });

    _socket!.onDisconnect((_) {
      _updateStatus(WebSocketStatus.disconnected);
      // 如果不是主动断开，尝试重连
      if (_status != WebSocketStatus.disconnected) {
        _scheduleReconnect();
      }
    });

    _socket!.onConnectError((_) {
      _updateStatus(WebSocketStatus.disconnected);
      _scheduleReconnect();
    });

    _socket!.onError((_) {
      // 错误处理
    });

    _socket!.onConnectTimeout((_) {
      // 连接超时处理
    });

    // 监听价格更新事件
    _socket!.on('priceUpdate', (data) {
      try {
        final update = PriceUpdate.fromJson(data as Map<String, dynamic>);
        _priceUpdateController.add(update);
      } catch (_) {
        // 解析错误处理
      }
    });

    _socket!.connect();
  }

  /// 断开连接
  ///
  /// 调用此方法后不会自动重连
  void disconnect() {
    _cancelReconnectTimer();
    _reconnectAttempts = 0;

    if (_socket != null) {
      _socket!.disconnect();
      _socket!.dispose();
      _socket = null;
    }

    _updateStatus(WebSocketStatus.disconnected);
  }

  /// 检查是否已连接
  bool get isConnected => _status == WebSocketStatus.connected;

  /// 安排重连
  void _scheduleReconnect() {
    if (_reconnectAttempts >= _maxReconnectAttempts) {
      return;
    }

    _cancelReconnectTimer();
    _updateStatus(WebSocketStatus.reconnecting);

    // 指数退避: 1s, 2s, 4s, 8s, ... 最大30s
    final delay = Duration(
      milliseconds: (_initialReconnectDelay.inMilliseconds *
          (1 << _reconnectAttempts)).clamp(
        _initialReconnectDelay.inMilliseconds,
        _maxReconnectDelay.inMilliseconds,
      ),
    );

    _reconnectAttempts++;

    _reconnectTimer = Timer(delay, () {
      if (_status != WebSocketStatus.connected) {
        _doConnect();
      }
    });
  }

  void _cancelReconnectTimer() {
    _reconnectTimer?.cancel();
    _reconnectTimer = null;
  }

  void _updateStatus(WebSocketStatus newStatus) {
    if (_status != newStatus) {
      _status = newStatus;
      _statusController.add(newStatus);
    }
  }

  /// 释放资源
  void dispose() {
    disconnect();
    _priceUpdateController.close();
    _statusController.close();
  }
}
