import { expect, test } from '@playwright/test';

import {
  buildMonotonicWordToTokenMap,
  tokenizeCanonicalSegment,
} from '../../src/lib/client/epub/epub-word-highlight';
import type { CanonicalTtsSegment } from '../../src/lib/shared/tts-segment-plan';
import type { TTSSentenceAlignment } from '../../src/types/tts';

const segment = (text: string, offset = 0): CanonicalTtsSegment => ({
  key: `segment:${offset}:${text}`,
  ordinal: 0,
  text,
  ownerSourceKey: 'str:epubcfi(/6/2)',
  ownerLocator: { location: 'epubcfi(/6/2)', readerType: 'epub' },
  startAnchor: { sourceKey: 'str:epubcfi(/6/2)', offset },
  endAnchor: { sourceKey: 'str:epubcfi(/6/2)', offset: offset + text.length },
  spansSourceBoundary: false,
});

const alignmentWords = (words: string[]): TTSSentenceAlignment['words'] =>
  words.map((word, index) => ({
    text: word,
    startSec: index,
    endSec: index + 0.5,
    charStart: 0,
    charEnd: word.length,
  }));

test.describe('EPUB word highlight mapping', () => {
  test('tokenizes canonical segment words with source offsets', () => {
    const tokens = tokenizeCanonicalSegment(segment('"Hello," she said.', 12));

    expect(tokens).toEqual([
      { norm: 'hello', sourceStart: 13, sourceEnd: 18 },
      { norm: 'she', sourceStart: 21, sourceEnd: 24 },
      { norm: 'said', sourceStart: 25, sourceEnd: 29 },
    ]);
  });

  test('maps repeated words monotonically instead of jumping to later duplicates', () => {
    const tokens = tokenizeCanonicalSegment(segment('the light and the shadow and the light returned'));
    const map = buildMonotonicWordToTokenMap(
      alignmentWords(['the', 'light', 'and', 'the', 'shadow', 'and', 'the', 'light', 'returned']),
      tokens,
    );

    expect(map).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8]);
  });

  test('leaves unmatched alignment words unhighlighted instead of borrowing a neighbor', () => {
    const tokens = tokenizeCanonicalSegment(segment('alpha beta gamma'));
    const map = buildMonotonicWordToTokenMap(
      alignmentWords(['alpha', 'missing', 'gamma']),
      tokens,
    );

    expect(map).toEqual([0, -1, 2]);
  });
});
