import { afterEach, describe, expect, it, vi } from 'vitest';
import { fairnessHandled, markFairnessHandled, sendFairness } from './feedback';

afterEach(() => {
  vi.unstubAllGlobals();
});

function stubStorage(): Map<string, string> {
  const data = new Map<string, string>();
  vi.stubGlobal('window', {
    localStorage: { getItem: (k: string) => data.get(k) ?? null, setItem: (k: string, v: string) => void data.set(k, v) },
  });
  return data;
}

describe('fairness prompt memory', () => {
  it('asks once per round and remembers it across reloads', () => {
    const data = stubStorage();
    expect(fairnessHandled('round-a')).toBe(false);
    markFairnessHandled('round-a');
    expect(fairnessHandled('round-a')).toBe(true);
    expect(JSON.parse(data.get('pintrush:fairness') ?? '[]')).toEqual(['round-a']);
  });

  it('keeps only the most recent rounds', () => {
    const data = stubStorage();
    for (let i = 0; i < 40; i++) markFairnessHandled(`r${i}`);
    const stored = JSON.parse(data.get('pintrush:fairness') ?? '[]') as string[];
    expect(stored).toHaveLength(30);
    expect(stored[0]).toBe('r39');
  });

  it('still works for this tab when storage is blocked', () => {
    vi.stubGlobal('window', {
      localStorage: {
        getItem: () => {
          throw new Error('blocked');
        },
        setItem: () => {
          throw new Error('blocked');
        },
      },
    });
    markFairnessHandled('round-z');
    expect(fairnessHandled('round-z')).toBe(true);
  });
});

describe('sendFairness', () => {
  it('posts the vote as JSON and swallows network errors', async () => {
    const fetchMock = vi.fn(async () => Promise.reject(new Error('offline')));
    vi.stubGlobal('fetch', fetchMock);
    sendFairness({ roomId: 'room', roundId: 'round', fair: false });
    expect(fetchMock).toHaveBeenCalledWith(
      '/api/feedback',
      expect.objectContaining({ method: 'POST', body: JSON.stringify({ roomId: 'room', roundId: 'round', fair: false }) }),
    );
    await Promise.resolve();
  });
});
