import 'TimelineIdentifiers.dart';
import 'entry_tree_item.dart';

const defaultLowestId = 9223372036854775807;
const defaultHighestId = 0;

class Timeline {
  final TimelineIdentifiers id;
  final List<EntryTreeItem> _posts = [];
  final Map<String, EntryTreeItem> _postsById = {};
  int _lowestStatusId = defaultLowestId;
  int _highestStatusId = defaultHighestId;

  int get highestStatusId => _highestStatusId;

  int get lowestStatusId => _lowestStatusId;

  Timeline(this.id, {List<EntryTreeItem>? initialPosts}) {
    if (initialPosts != null) {
      addOrUpdate(initialPosts);
    }
  }

  List<EntryTreeItem> get posts => List.unmodifiable(_posts);

  void addOrUpdate(List<EntryTreeItem> newPosts) {
    for (final p in newPosts) {
      final id = int.parse(p.id);
      if (_lowestStatusId > id) {
        _lowestStatusId = id;
      }

      if (_highestStatusId < id) {
        _highestStatusId = id;
      }
      _postsById[p.id] = p;
    }
    _posts.clear();
    _posts.addAll(_postsById.values);
    _posts.sort((p1, p2) {
      final id1 = num.parse(p1.id);
      final id2 = num.parse(p2.id);
      return id2.compareTo(id1);
      // return p2.entry.backdatedTimestamp.compareTo(p1.entry.backdatedTimestamp);
    });
  }

  bool tryUpdateComment(EntryTreeItem comment) {
    var changed = false;
    final parentId = comment.entry.parentId;
    for (final p in _posts) {
      final parent =
          p.id == parentId ? p : p.getChildById(comment.entry.parentId);
      if (parent != null) {
        parent.addOrUpdate(comment);
        changed = true;
      }
    }

    return changed;
  }

  void removeTimelineEntry(String id) {
    if (_postsById.containsKey(id)) {
      final post = _postsById.remove(id);
      _posts.remove(post);
      return;
    }

    for (final p in _posts) {
      p.removeChildById(id);
    }
  }

  void clear() {
    _posts.clear();
    _postsById.clear();
    _lowestStatusId = defaultLowestId;
    _highestStatusId = defaultHighestId;
  }

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

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