import { describe, it, expect } from 'vitest';
import { computeServerDeletions } from './serverDeletions.js';

const M = (obj = {}) => new Map(Object.entries(obj));
const S = (arr = []) => new Set(arr);

const base = {
  prevServerFiles: null,
  serverFiles: M(),
  localFiles: S(),
  baseHashes: M(),
  changelistDel: S(),
  answered: S(),
  recentlySubmitted: S(),
};

describe('computeServerDeletions', () => {
  it('flags a genuine teammate deletion (synced + on disk + gone from depot)', () => {
    const gone = computeServerDeletions({
      ...base,
      serverFiles: M(),               // depot no longer has it
      localFiles: S(['a.txt']),       // still on disk
      baseHashes: M({ 'a.txt': 'h1' }), // we synced it once
    });
    expect(gone).toEqual(['a.txt']);
  });

  it('does NOT flag a file this client just submitted (stale depot tree race)', () => {
    // Repro of the human-testing bug: add + submit -> manifest has the file,
    // it's on disk, but serverFiles is still the pre-submit snapshot.
    const gone = computeServerDeletions({
      ...base,
      serverFiles: M(),                    // stale: hasn't caught up to the submit yet
      localFiles: S(['new.txt']),
      baseHashes: M({ 'new.txt': 'h9' }),  // submit recorded it as synced
      recentlySubmitted: S(['new.txt']),   // we know WE just put it there
    });
    expect(gone).toEqual([]);
  });

  it('flags an in-session vanish via the prev-depot diff', () => {
    const gone = computeServerDeletions({
      ...base,
      prevServerFiles: M({ 'b.txt': 'h1' }), // was in the depot a moment ago
      serverFiles: M(),                       // now gone
      localFiles: S(['b.txt']),               // still on disk
    });
    expect(gone).toEqual(['b.txt']);
  });

  it('does not flag a file still present in the depot', () => {
    const gone = computeServerDeletions({
      ...base,
      serverFiles: M({ 'a.txt': 'h1' }),
      localFiles: S(['a.txt']),
      baseHashes: M({ 'a.txt': 'h1' }),
    });
    expect(gone).toEqual([]);
  });

  it('does not flag a file the user already answered about', () => {
    const gone = computeServerDeletions({
      ...base,
      localFiles: S(['a.txt']),
      baseHashes: M({ 'a.txt': 'h1' }),
      answered: S(['a.txt']),
    });
    expect(gone).toEqual([]);
  });

  it("does not flag the user's own marked-for-delete file", () => {
    const gone = computeServerDeletions({
      ...base,
      localFiles: S(['a.txt']),
      baseHashes: M({ 'a.txt': 'h1' }),
      changelistDel: S(['a.txt']),
    });
    expect(gone).toEqual([]);
  });

  it('does not flag a synced file that is no longer on disk (own delete already applied)', () => {
    const gone = computeServerDeletions({
      ...base,
      serverFiles: M(),
      localFiles: S([]),                 // not on disk
      baseHashes: M({ 'a.txt': 'h1' }),
    });
    expect(gone).toEqual([]);
  });
});
