// @vitest-environment happy-dom

import { describe, expect, test, vi } from 'vitest';
import { renderSelectableTextLayer } from '../pdf-preview-pane';

describe('mobile-safe PDF text layer', () => {
  test('falls back when the native PDF.js TextLayer throws instead of failing the page', async () => {
    const container = document.createElement('div');
    const cancel = vi.fn();

    class ThrowingTextLayer {
      render = async () => {
        throw new TypeError("Undefined is not a function (near '...e of n...')");
      };

      cancel = cancel;
    }

    const content = {
      items: [
        {
          str: 'Learnitive mobile PDF',
          dir: 'ltr',
          width: 90,
          height: 12,
          transform: [12, 0, 0, 12, 18, 80],
          fontName: 'f1',
          hasEOL: false,
        },
      ],
      styles: {
        f1: { fontFamily: 'sans-serif', ascent: 0.8 },
      },
      lang: null,
    } as never;
    const viewport = {
      scale: 1,
      width: 612,
      height: 792,
      transform: [1, 0, 0, -1, 0, 792],
    } as never;

    const result = await renderSelectableTextLayer({
      container,
      content,
      viewport,
      textLayerConstructor: ThrowingTextLayer as never,
    });

    expect(cancel).toHaveBeenCalledOnce();
    expect(result.mode).toBe('fallback');
    expect(container.textContent).toContain('Learnitive mobile PDF');
    expect(container.querySelector('span')?.dataset.learnitiveTextIndex).toBe('0');
  });

  test('renders the compatibility text layer when PDF.js exposes no native TextLayer', async () => {
    const container = document.createElement('div');
    const content = {
      items: [
        {
          str: 'Fallback text',
          dir: 'ltr',
          width: 60,
          height: 10,
          transform: [10, 0, 0, 10, 10, 50],
          fontName: 'f1',
          hasEOL: false,
        },
      ],
      styles: { f1: { fontFamily: 'sans-serif', ascent: 0.8 } },
      lang: null,
    } as never;
    const viewport = {
      scale: 1,
      width: 612,
      height: 792,
      transform: [1, 0, 0, -1, 0, 792],
    } as never;

    const result = await renderSelectableTextLayer({
      container,
      content,
      viewport,
      textLayerConstructor: null,
    });

    expect(result.mode).toBe('fallback');
    expect(container.textContent).toContain('Fallback text');
    expect(container.style.getPropertyValue('--total-scale-factor')).toBe('1');
    expect(container.style.getPropertyValue('--scale-factor')).toBe('1');
    expect(container.style.userSelect).toBe('text');
    expect(container.style.pointerEvents).toBe('auto');
    expect(container.style.cursor).toBe('text');
    const fallbackSpan = container.querySelector<HTMLElement>('span');
    expect(fallbackSpan?.style.userSelect).toBe('text');
    expect(fallbackSpan?.style.position).toBe('absolute');
    expect(fallbackSpan?.style.whiteSpace).toBe('pre');
    expect(fallbackSpan?.style.transformOrigin).toBe('0 0');
    expect(fallbackSpan?.style.minWidth).toBe('60px');
  });

  test('configures the native PDF.js 6 text layer with selectable scale semantics', async () => {
    const container = document.createElement('div');
    let receivedContainer: HTMLElement | undefined;

    class NativeTextLayer {
      constructor(options: { container: HTMLElement }) {
        receivedContainer = options.container;
      }

      render = async () => {
        const span = document.createElement('span');
        span.textContent = 'Selectable native text';
        receivedContainer?.appendChild(span);
      };
    }

    const content = { items: [], styles: {}, lang: null } as never;
    const viewport = {
      scale: 1.75,
      width: 714,
      height: 924,
      transform: [1.75, 0, 0, -1.75, 0, 924],
    } as never;

    const result = await renderSelectableTextLayer({
      container,
      content,
      viewport,
      textLayerConstructor: NativeTextLayer as never,
    });

    expect(result.mode).toBe('native');
    expect(container.style.getPropertyValue('--total-scale-factor')).toBe('1.75');
    expect(container.style.getPropertyValue('--scale-factor')).toBe('1.75');
    expect(container.style.userSelect).toBe('text');
    expect(container.style.pointerEvents).toBe('auto');
    expect(container.querySelector<HTMLElement>('span')?.style.userSelect).toBe('text');
  });
});
