import { describe, it, expect } from 'vitest';

import {
  clampFrame,
  naturalSortFiles,
  naturalSortBy,
  IMAGE_QUAD_LABELS,
  frameLabel,
} from './imageSequenceModel';

// A minimal File stand-in — we only ever read `.name`. Avoids relying on the DOM
// File constructor under the `node` vitest env.
function mkFile(name: string): File {
  return { name } as File;
}

describe('clampFrame', () => {
  it('returns an in-range index unchanged', () => {
    expect(clampFrame(0, 10)).toBe(0);
    expect(clampFrame(4, 10)).toBe(4);
    expect(clampFrame(9, 10)).toBe(9);
  });

  it('clamps an over-range index down to count - 1', () => {
    expect(clampFrame(15, 10)).toBe(9);
    expect(clampFrame(10, 10)).toBe(9);
  });

  it('clamps a negative index up to 0', () => {
    expect(clampFrame(-3, 10)).toBe(0);
  });

  it('returns 0 for a NaN / non-finite index', () => {
    expect(clampFrame(NaN, 10)).toBe(0);
    // Infinity is non-finite → 0 per the contract (not the max index).
    expect(clampFrame(Infinity, 10)).toBe(0);
  });

  it('returns 0 for an empty sequence (count 0)', () => {
    expect(clampFrame(0, 0)).toBe(0);
    expect(clampFrame(3, 0)).toBe(0);
  });

  it('floors a fractional index', () => {
    expect(clampFrame(2.9, 10)).toBe(2);
  });
});

describe('naturalSortFiles', () => {
  it('orders frame names numerically (frame2 < frame10)', () => {
    const sorted = naturalSortFiles([
      mkFile('f10.png'),
      mkFile('f2.png'),
      mkFile('f1.png'),
    ]);
    expect(sorted.map((f) => f.name)).toEqual(['f1.png', 'f2.png', 'f10.png']);
  });

  it('returns a new array and does not mutate the input', () => {
    const input = [mkFile('b.png'), mkFile('a.png')];
    const sorted = naturalSortFiles(input);
    expect(sorted).not.toBe(input);
    expect(input.map((f) => f.name)).toEqual(['b.png', 'a.png']);
  });
});

describe('naturalSortBy', () => {
  it('sorts by a string key with numeric awareness', () => {
    expect(naturalSortBy(['x10', 'x2', 'x1'], (s) => s)).toEqual(['x1', 'x2', 'x10']);
  });
});

describe('IMAGE_QUAD_LABELS', () => {
  it('carries the Vietnamese pane labels with diacritics', () => {
    expect(IMAGE_QUAD_LABELS[0]).toBe('Ảnh gốc');
    expect(IMAGE_QUAD_LABELS[1]).toBe('Bản đồ độ sâu');
    expect(IMAGE_QUAD_LABELS[2]).toBe('Phủ phân vùng');
    expect(IMAGE_QUAD_LABELS[3]).toBe('Tái tạo 3D');
  });
});

describe('frameLabel', () => {
  it('returns "khung 0/0" for an empty sequence', () => {
    expect(frameLabel(0, 0)).toBe('khung 0/0');
  });

  it('formats a 1-based counter', () => {
    expect(frameLabel(4, 10)).toBe('khung 5/10');
    expect(frameLabel(0, 10)).toBe('khung 1/10');
  });

  it('clamps the index inside the counter', () => {
    expect(frameLabel(99, 10)).toBe('khung 10/10');
    expect(frameLabel(-5, 10)).toBe('khung 1/10');
  });
});
