import 'dart:async';
import 'dart:convert';
import 'package:web_socket_channel/web_socket_channel.dart';
import '../logging/logger.dart';

class WebSocketManager {
  static WebSocketManager? _instance;
  static WebSocketManager get instance => _instance ??= WebSocketManager._();

  WebSocketManager._();

  final Set<WebSocketChannel> _connections = {};

  void addConnection(WebSocketChannel channel) {
    _connections.add(channel);
    Logger.info('WebSocket connection added. Total connections: ${_connections.length}');
    
    // Listen for messages and connection close
    channel.stream.listen(
      (message) {
        try {
          final data = jsonDecode(message as String) as Map<String, dynamic>;
          final messageType = data['type'] as String?;
          
          // Handle ping messages
          if (messageType == 'ping') {
            final pongMessage = {
              'type': 'pong',
              'timestamp': DateTime.now().millisecondsSinceEpoch,
            };
            channel.sink.add(jsonEncode(pongMessage));
          }
        } catch (e) {
          Logger.error('Error processing WebSocket message: $e');
        }
      },
      onDone: () => _removeConnection(channel),
      onError: (error) {
        Logger.error('WebSocket connection error: $error');
        _removeConnection(channel);
      },
    );
  }

  void _removeConnection(WebSocketChannel channel) {
    _connections.remove(channel);
    Logger.info('WebSocket connection removed. Total connections: ${_connections.length}');
  }

  void broadcast(Map<String, dynamic> message) {
    if (_connections.isEmpty) {
      return;
    }

    final jsonMessage = jsonEncode(message);
    final connectionsToRemove = <WebSocketChannel>[];

    for (final connection in _connections) {
      try {
        connection.sink.add(jsonMessage);
      } catch (e) {
        Logger.error('Failed to send WebSocket message: $e');
        connectionsToRemove.add(connection);
      }
    }

    // Remove failed connections
    for (final connection in connectionsToRemove) {
      _removeConnection(connection);
    }
  }

  void close() {
    for (final connection in _connections) {
      try {
        connection.sink.close();
      } catch (e) {
        Logger.error('Error closing WebSocket connection: $e');
      }
    }
    _connections.clear();
    Logger.info('All WebSocket connections closed');
  }

  int get connectionCount => _connections.length;
  bool get hasConnections => _connections.isNotEmpty;
}
