import { describe, it, expect } from 'vitest';
import { resolveMoves, basename, parentDir } from './fileMove';

describe('basename / parentDir', () => {
  it('extracts the last segment', () => {
    expect(basename('a/b/c.txt')).toBe('c.txt');
    expect(basename('top')).toBe('top');
    expect(basename('/a/b/')).toBe('b');
  });
  it('extracts the parent', () => {
    expect(parentDir('a/b/c.txt')).toBe('a/b');
    expect(parentDir('top.txt')).toBe('');
    expect(parentDir('/a/b/')).toBe('a');
  });
});

describe('resolveMoves', () => {
  it('moves a file into a subfolder', () => {
    const r = resolveMoves(['report.pdf'], 'archive');
    expect(r.moves).toEqual([{ from: 'report.pdf', to: 'archive/report.pdf' }]);
    expect(r.skipped).toEqual([]);
  });

  it('moves a file to root', () => {
    const r = resolveMoves(['archive/report.pdf'], '');
    expect(r.moves).toEqual([{ from: 'archive/report.pdf', to: 'report.pdf' }]);
  });

  it('moves multiple files preserving their basenames', () => {
    const r = resolveMoves(['a/x.txt', 'b/y.txt'], 'dest');
    expect(r.moves).toEqual([
      { from: 'a/x.txt', to: 'dest/x.txt' },
      { from: 'b/y.txt', to: 'dest/y.txt' },
    ]);
  });

  it('skips a file already directly in the destination (no-op)', () => {
    const r = resolveMoves(['archive/report.pdf'], 'archive');
    expect(r.moves).toEqual([]);
    expect(r.skipped).toEqual(['archive/report.pdf']);
  });

  it('skips a root file dropped onto root', () => {
    const r = resolveMoves(['report.pdf'], '');
    expect(r.moves).toEqual([]);
    expect(r.skipped).toEqual(['report.pdf']);
  });

  it('skips moving a folder into itself', () => {
    const r = resolveMoves(['docs'], 'docs');
    expect(r.moves).toEqual([]);
    expect(r.skipped).toEqual(['docs']);
  });

  it('skips moving a folder into its own descendant', () => {
    const r = resolveMoves(['docs'], 'docs/sub');
    expect(r.moves).toEqual([]);
    expect(r.skipped).toEqual(['docs']);
  });

  it('does NOT treat a sibling prefix-collision folder as a descendant', () => {
    // 'docs2' starts with 'docs' lexically but is not inside 'docs'.
    const r = resolveMoves(['docs'], 'docs2');
    expect(r.moves).toEqual([{ from: 'docs', to: 'docs2/docs' }]);
    expect(r.skipped).toEqual([]);
  });

  it('normalizes leading/trailing slashes', () => {
    const r = resolveMoves(['/a/x.txt/'], '/dest/');
    expect(r.moves).toEqual([{ from: 'a/x.txt', to: 'dest/x.txt' }]);
  });

  it('dedupes repeated source paths', () => {
    const r = resolveMoves(['a/x.txt', 'a/x.txt'], 'dest');
    expect(r.moves).toEqual([{ from: 'a/x.txt', to: 'dest/x.txt' }]);
  });

  it('partitions a mixed batch into moves and skips', () => {
    const r = resolveMoves(['a/x.txt', 'dest/y.txt', 'b/z.txt'], 'dest');
    expect(r.moves).toEqual([
      { from: 'a/x.txt', to: 'dest/x.txt' },
      { from: 'b/z.txt', to: 'dest/z.txt' },
    ]);
    expect(r.skipped).toEqual(['dest/y.txt']);
  });
});
