import 'package:logging/logging.dart';

import '../globals.dart';
import '../services/connections_manager.dart';
import '../utils/active_profile_selector.dart';
import 'connection.dart';
import 'direct_message.dart';

class DirectMessageThread {
  static final _logger = Logger('$DirectMessageThread');
  final List<DirectMessage> messages;

  final List<Connection> participants;

  final String title;

  final String parentUri;

  DirectMessageThread({
    required this.messages,
    required this.participants,
    required this.title,
    required this.parentUri,
  });

  get allSeen => messages.isEmpty
      ? false
      : messages
          .map((m) => m.seen)
          .reduce((allUnseen, thisUnseen) => allUnseen && thisUnseen);

  static List<DirectMessageThread> createThreads(
      Iterable<DirectMessage> messages) {
    final cm =
        getIt<ActiveProfileSelector<ConnectionsManager>>().activeEntry.fold(
            onSuccess: (m) => m,
            onError: (error) {
              _logger.severe('Error getting connection manager: $error');
              return null;
            });
    final threads = <String, List<DirectMessage>>{};
    for (final m in messages) {
      final thread = threads.putIfAbsent(m.parentUri, () => []);
      thread.add(m);
    }

    final result = <DirectMessageThread>[];
    for (final t in threads.entries) {
      final parentUri = t.key;
      final threadMessages = t.value;
      final participantIds = <String>{};
      var title = '';
      threadMessages.sort((m1, m2) => m1.createdAt.compareTo(m2.createdAt));
      for (final m in threadMessages) {
        participantIds.add(m.senderId);
        participantIds.add(m.recipientId);
        if (title.isEmpty) {
          title = m.title;
        }
      }
      final participants = participantIds
          .map((pid) => cm?.getById(pid))
          .where((pr) => pr != null && pr.isSuccess)
          .map((pr) => pr!.value)
          .toList();
      final thread = DirectMessageThread(
        messages: threadMessages,
        participants: participants,
        title: title,
        parentUri: parentUri,
      );
      result.add(thread);
    }

    result.sort((t1, t2) =>
        t2.messages.first.createdAt.compareTo(t1.messages.first.createdAt));

    return result;
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is DirectMessageThread &&
          runtimeType == other.runtimeType &&
          parentUri == other.parentUri;

  @override
  int get hashCode => parentUri.hashCode;
}
