import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:siro_driver/print.dart';

class SignalingService {
  WebSocket? _socket;
  final String _url = "wss://calls.intaleqapp.com/ws";
  
  // Callbacks
  Function(List<dynamic> iceServers)? onConnected;
  Function(String reason)? onDisconnected;
  Function(Map<String, dynamic> offer)? onOffer;
  Function(Map<String, dynamic> answer)? onAnswer;
  Function(Map<String, dynamic> candidate)? onIceCandidate;
  Function(String reason)? onCallEnded;
  Function()? onParticipantJoined;

  bool get isConnected => _socket != null && _socket!.readyState == WebSocket.open;

  Future<void> connect(String sessionId, String userId) async {
    if (isConnected) return;
    
    try {
      Log.print("Signaling: Connecting to $_url");
      _socket = await WebSocket.connect(_url)
          .timeout(const Duration(seconds: 8));
      
      _socket!.listen(
        (data) {
          _handleMessage(data);
        },
        onError: (err) {
          Log.print("Signaling socket error: $err");
          disconnect("socket_error");
        },
        onDone: () {
          Log.print("Signaling socket closed by server");
          disconnect("socket_closed");
        },
        cancelOnError: true,
      );

      // Send the authenticate message as the first message
      send("authenticate", {
        "session_id": sessionId,
        "user_id": userId,
      });
    } catch (e) {
      Log.print("Signaling connection failed: $e");
      onDisconnected?.call("connection_failed");
    }
  }

  void _handleMessage(dynamic data) {
    try {
      Log.print("Signaling received raw: $data");
      final message = jsonDecode(data);
      if (message is! Map<String, dynamic>) return;
      
      final type = message['type'];
      switch (type) {
        case 'authenticated':
          final iceServers = message['ice_servers'] as List<dynamic>? ?? [];
          onConnected?.call(iceServers);
          break;
        case 'participant_joined':
          onParticipantJoined?.call();
          break;
        case 'offer':
          if (message['sdp'] != null) {
            onOffer?.call(message['sdp']);
          }
          break;
        case 'answer':
          if (message['sdp'] != null) {
            onAnswer?.call(message['sdp']);
          }
          break;
        case 'ice_candidate':
          if (message['candidate'] != null) {
            onIceCandidate?.call(message['candidate']);
          }
          break;
        case 'call_ended':
          onCallEnded?.call(message['reason'] ?? 'normal');
          break;
      }
    } catch (e) {
      Log.print("Error handling signaling message: $e");
    }
  }

  void send(String type, Map<String, dynamic> data) {
    if (!isConnected) return;
    final msg = jsonEncode({
      'type': type,
      ...data,
    });
    Log.print("Signaling sending: $msg");
    _socket!.add(msg);
  }

  void disconnect([String reason = "user_hangup"]) {
    if (_socket != null) {
      _socket!.close();
      _socket = null;
      onDisconnected?.call(reason);
    }
  }
}
