// Tests for the one-notebook-per-PDF logical page model (F6).

import 'package:flutter_test/flutter_test.dart';

import 'package:badnote/editor/notebook/page_map.dart';

void main() {
  test('fromSource is the identity map (one source page per PDF page)', () {
    final m = PageMap.fromSource(3);
    expect(m.length, 3);
    expect(m.sourceCount, 3);
    expect(m.blankCount, 0);
    expect([m.sourceIndexAt(0), m.sourceIndexAt(1), m.sourceIndexAt(2)],
        [0, 1, 2]);
  });

  test('fromSource(0) is empty', () {
    final m = PageMap.fromSource(0);
    expect(m.isEmpty, isTrue);
    expect(m.length, 0);
  });

  test('insertBlankAt inserts a blank and shifts logical order, NOT source idx',
      () {
    final m = PageMap.fromSource(2).insertBlankAt(1);
    expect(m.length, 3);
    expect(m[0], const NotebookPage.source(0));
    expect(m[1].isBlank, isTrue);
    expect(m[2], const NotebookPage.source(1)); // source index UNCHANGED
    expect(m.sourceIndexAt(1), isNull);
    expect(m.blankCount, 1);
  });

  test('insertBlankAfter(-1) prepends; after(last) appends', () {
    final m = PageMap.fromSource(2);
    expect(m.insertBlankAfter(-1)[0].isBlank, isTrue);
    final appended = m.insertBlankAfter(1);
    expect(appended[2].isBlank, isTrue);
    expect(appended.length, 3);
  });

  test('insertBlankAt at length appends (boundary)', () {
    final m = PageMap.fromSource(2).insertBlankAt(2);
    expect(m.length, 3);
    expect(m[2].isBlank, isTrue);
  });

  test('removeAt drops the logical page', () {
    final m = PageMap.fromSource(3).removeAt(1);
    expect(m.length, 2);
    expect([m.sourceIndexAt(0), m.sourceIndexAt(1)], [0, 2]);
  });

  test('move reorders (drag-reorder thumbnails)', () {
    final m = PageMap.fromSource(3).move(0, 2); // [1,2,0]
    expect([m.sourceIndexAt(0), m.sourceIndexAt(1), m.sourceIndexAt(2)],
        [1, 2, 0]);
  });

  test('move to same index is a no-op (returns identical instance)', () {
    final m = PageMap.fromSource(3);
    expect(identical(m.move(1, 1), m), isTrue);
  });

  test('out-of-range edits throw RangeError', () {
    final m = PageMap.fromSource(2);
    expect(() => m.insertBlankAt(3), throwsRangeError);
    expect(() => m.removeAt(2), throwsRangeError);
    expect(() => m.move(0, 5), throwsRangeError);
    expect(() => m.insertBlankAfter(2), throwsRangeError);
  });

  test('value equality + immutability of the page list', () {
    expect(PageMap.fromSource(2), PageMap.fromSource(2));
    expect(PageMap.fromSource(2).insertBlankAt(0) == PageMap.fromSource(2),
        isFalse);
    final m = PageMap.fromSource(1);
    expect(() => m.pages.add(const NotebookPage.blank()),
        throwsUnsupportedError);
  });

  test('NotebookPage equality distinguishes kind + source index', () {
    expect(const NotebookPage.source(1), const NotebookPage.source(1));
    expect(const NotebookPage.source(1) == const NotebookPage.source(2),
        isFalse);
    expect(const NotebookPage.blank() == const NotebookPage.source(0), isFalse);
    expect(const NotebookPage.blank(), const NotebookPage.blank());
  });
}
