import 'package:flutter_test/flutter_test.dart';
import 'package:relatica/globals.dart';
import 'package:relatica/models/entry_tree_item.dart';
import 'package:relatica/models/timeline_entry.dart';
import 'package:relatica/utils/entry_tree_item_flattening.dart';

void main() {
  group('Flattening Tests', () {
    test('Single entry no children', () {
      final entry = TimelineEntry.randomBuilt();
      final treeItem = EntryTreeItem(entry);
      final flattened = treeItem.flatten();
      expect(flattened.length, equals(1));
      expect(flattened.first.isMine, equals(treeItem.isMine));
      expect(flattened.first.timelineEntry, equals(treeItem.entry));
    });

    test('Entry with two children', () {
      final post = TimelineEntry(id: '0');
      final children = {
        '1': EntryTreeItem(
          TimelineEntry(id: '1'),
        ),
        '2': EntryTreeItem(
          TimelineEntry(id: '2'),
        ),
      };
      final treeItem = EntryTreeItem(post, initialChildren: children);
      final flattened = treeItem.flatten();
      expect(flattened.length, equals(3));
      expect(
        flattened.map((e) => int.parse(e.timelineEntry.id)).toList(),
        equals([0, 1, 2]),
      );
      expect(
        flattened.map((e) => e.level).toList(),
        equals([0, 1, 1]),
      );
    });

    test('Entry with nesting children different authors', () {
      final post = TimelineEntry(id: '0');
      final children = {
        '1': EntryTreeItem(TimelineEntry(id: '1', authorId: randomId()),
            initialChildren: {
              '2': EntryTreeItem(
                TimelineEntry(id: '2', authorId: randomId()),
              ),
            }),
      };
      final treeItem = EntryTreeItem(post, initialChildren: children);
      final flattened = treeItem.flatten();
      expect(flattened.length, equals(3));
      expect(
        flattened.map((e) => int.parse(e.timelineEntry.id)).toList(),
        equals([0, 1, 2]),
      );
      expect(
        flattened.map((e) => e.level).toList(),
        equals([0, 1, 2]),
      );
    });

    test('Entry with nesting children same authors', () {
      final post = TimelineEntry(id: '0');
      final children = {
        '1': EntryTreeItem(TimelineEntry(id: '1'), initialChildren: {
          '2': EntryTreeItem(
            TimelineEntry(id: '2'),
          ),
        }),
      };
      final treeItem = EntryTreeItem(post, initialChildren: children);
      final flattened = treeItem.flatten();
      expect(flattened.length, equals(3));
      expect(
        flattened.map((e) => int.parse(e.timelineEntry.id)).toList(),
        equals([0, 1, 2]),
      );
      expect(
        flattened.map((e) => e.level).toList(),
        equals([0, 1, 1]),
      );
    });

    test('Entry fully nested children', () {
      var stamp = 0;
      final post =
          TimelineEntry(id: '0', authorId: 'a0', creationTimestamp: stamp++);
      final children = {
        '1': EntryTreeItem(
          TimelineEntry(id: '1', creationTimestamp: stamp++),
          initialChildren: {
            '1.1': EntryTreeItem(
              TimelineEntry(
                id: '1.1',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
            ),
            '1.2': EntryTreeItem(
              TimelineEntry(
                id: '1.2',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
            ),
            '1.3': EntryTreeItem(
              TimelineEntry(
                id: '1.3',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
            ),
          },
        ),
        '2': EntryTreeItem(
          TimelineEntry(
            id: '2',
            authorId: randomId(),
            creationTimestamp: stamp++,
          ),
          initialChildren: {
            '2.1': EntryTreeItem(
              TimelineEntry(
                id: '2.1',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
            ),
            '2.2': EntryTreeItem(
              TimelineEntry(
                id: '2.2',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
              initialChildren: {
                '2.2.1': EntryTreeItem(
                  TimelineEntry(
                    id: '2.2.1',
                    authorId: 'a1',
                    creationTimestamp: stamp++,
                  ),
                  initialChildren: {
                    '2.2.1.1': EntryTreeItem(
                      TimelineEntry(
                        id: '2.2.1.1',
                        creationTimestamp: stamp++,
                      ),
                    ),
                    '2.2.1.2': EntryTreeItem(
                      TimelineEntry(
                        id: '2.2.1.2',
                        authorId: 'a1',
                        creationTimestamp: stamp++,
                      ),
                    ),
                  },
                ),
                '2.2.2': EntryTreeItem(
                  TimelineEntry(
                    id: '2.2.2',
                    authorId: 'a2',
                    creationTimestamp: stamp++,
                  ),
                  initialChildren: {
                    '2.2.2.1': EntryTreeItem(
                      TimelineEntry(
                        id: '2.2.2.1',
                        creationTimestamp: (stamp++) + 100,
                      ),
                    ),
                    '2.2.2.2': EntryTreeItem(
                      TimelineEntry(
                        id: '2.2.2.2',
                        authorId: 'a2',
                        creationTimestamp: stamp++,
                      ),
                    ),
                    '2.2.2.3': EntryTreeItem(
                      TimelineEntry(
                        id: '2.2.2.3',
                        authorId: 'a2',
                        creationTimestamp: stamp++,
                      ),
                    ),
                    '2.2.2.4': EntryTreeItem(
                      TimelineEntry(
                        id: '2.2.2.4',
                        authorId: 'a0',
                        creationTimestamp: stamp++,
                      ),
                    ),
                  },
                ),
              },
            ),
            '2.3': EntryTreeItem(
              TimelineEntry(
                id: '2.3',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
            ),
          },
        ),
        '3': EntryTreeItem(
          TimelineEntry(
            id: '3',
            authorId: 'a0',
            creationTimestamp: stamp++,
          ),
          initialChildren: {
            '3.1': EntryTreeItem(TimelineEntry(
              id: '3.1',
              authorId: randomId(),
              creationTimestamp: stamp++,
            )),
            '3.2': EntryTreeItem(
              TimelineEntry(
                id: '3.2',
                authorId: 'a0',
                creationTimestamp: stamp++,
              ),
            ),
            '3.3': EntryTreeItem(
              TimelineEntry(
                id: '3.3',
                authorId: randomId(),
                creationTimestamp: stamp++,
              ),
            ),
          },
        ),
      };
      final treeItem = EntryTreeItem(post, initialChildren: children);
      final flattened = treeItem.flatten();
      expect(flattened.length, equals(21));
      expect(
        flattened.map((e) => e.timelineEntry.id).toList(),
        equals([
          '0',
          '1',
          '1.1',
          '1.2',
          '1.3',
          '2',
          '2.1',
          '2.2',
          '2.2.1',
          '2.2.1.2',
          '2.2.1.1',
          '2.2.2',
          '2.2.2.2',
          '2.2.2.3',
          '2.2.2.4',
          '2.2.2.1',
          '2.3',
          '3',
          '3.2',
          '3.1',
          '3.3',
        ]),
      );
      expect(
        flattened.map((e) => e.level).toList(),
        equals([0, 1, 2, 2, 2, 1, 2, 2, 3, 3, 4, 3, 3, 3, 4, 4, 2, 1, 1, 2, 2]),
      );
    });
  });
}
