import 'dart:async';

import 'package:comunic/models/comment.dart';
import 'package:comunic/models/conversation_message.dart';
import 'package:event_bus/event_bus.dart';
import 'package:flutter_webrtc/rtc_ice_candidate.dart';
import 'package:flutter_webrtc/rtc_session_description.dart';

/// Events helper
///
/// @author Pierre Hubert

/// Invalid login token
class InvalidLoginTokensEvent {}

/// Main WebSocket closed
class WSClosedEvent {}

/// New number of notifications
class NewNumberNotifsEvent {
  final int newNum;

  NewNumberNotifsEvent(this.newNum);
}

/// New number of unread conversations
class NewNumberUnreadConversations {
  final int newNum;

  NewNumberUnreadConversations(this.newNum);
}

/// New comment
class NewCommentEvent {
  final Comment comment;

  NewCommentEvent(this.comment);
}

/// Updated comment
class UpdatedCommentEvent {
  final Comment comment;

  UpdatedCommentEvent(this.comment);
}

/// Deleted comment
class DeletedCommentEvent {
  final int commentID;

  DeletedCommentEvent(this.commentID);
}

/// New conversation message
class NewConversationMessageEvent {
  final ConversationMessage msg;

  NewConversationMessageEvent(this.msg);
}

/// Updated conversation message
class UpdatedConversationMessageEvent {
  final ConversationMessage msg;

  UpdatedConversationMessageEvent(this.msg);
}

/// Deleted conversation message
class DeletedConversationMessageEvent {
  final ConversationMessage msg;

  DeletedConversationMessageEvent(this.msg);
}

/// User joined call event
class UserJoinedCallEvent {
  final int callID;
  final int userID;

  UserJoinedCallEvent(this.callID, this.userID);
}

/// User left call event
class UserLeftCallEvent {
  final int callID;
  final int userID;

  UserLeftCallEvent(this.callID, this.userID);
}

/// New call signal event
class NewCallSignalEvent {
  final int callID;
  final int peerID;
  final RTCSessionDescription sessionDescription;
  final RTCIceCandidate candidate;

  const NewCallSignalEvent({
    this.callID,
    this.peerID,
    this.sessionDescription,
    this.candidate,
  })  : assert(callID != null),
        assert(peerID != null),
        assert(sessionDescription != null || candidate != null);
}

/// Call peer ready event
class CallPeerReadyEvent {
  final int callID;
  final int peerID;

  CallPeerReadyEvent(this.callID, this.peerID);
}

/// Call peer interrupted streaming event
class CallPeerInterruptedStreamingEvent {
  final int callID;
  final int peerID;

  CallPeerInterruptedStreamingEvent(this.callID, this.peerID);
}

/// Call closed event
class CallClosedEvent {
  final int callID;

  CallClosedEvent(this.callID);
}

class EventsHelper {
  static EventBus _mgr = EventBus();

  /// Listen to event
  ///
  /// Do not use this method directly. You should instead prefer to use
  /// [SafeState.listen] to handle safely widgets lifecycle...
  ///
  /// You can not register to global events
  static StreamSubscription<T> on<T>(void onData(T event)) {
    if (T == dynamic) throw Exception("Do not register to all events!");

    final stream = _mgr.on<T>();
    return stream.listen(onData);
  }

  /// Propagate an event
  static void emit<T>(T event) {
    _mgr.fire(event);
  }
}