import { describe, it, expect, vi, afterEach } from 'vitest';
import { AlqoveClient } from '../../client';
import { createTimekeepingEndpoints } from '../timekeeping';
afterEach(() => vi.unstubAllGlobals());
describe('timekeeping wire contract', () => {
  it('sends explicit payroll acknowledgement and retrieves authenticated CSV blobs', async () => {
    const fetcher = vi.fn().mockImplementation(async (url: string) => new Response(url.endsWith('/download') ? 'Employee,Hours\nAda,8' : JSON.stringify({ data: { id: 'e1' } })));
    vi.stubGlobal('fetch', fetcher);
    const api = createTimekeepingEndpoints(new AlqoveClient({ baseUrl: 'https://api.test', getToken: () => 'owner' }));
    await api.payroll.create('s1', { week_starts: ['2026-09-07'], acknowledge_oversized_sessions: false }, 'export-key');
    await api.payroll.list('s1');
    const blob = await api.payroll.download('s1', 'e1');
    expect(fetcher.mock.calls[0][1].headers['Idempotency-Key']).toBe('export-key');
    expect(fetcher.mock.calls[2][0]).toBe('https://api.test/v1/stores/s1/payroll/exports/e1/download');
    expect(fetcher.mock.calls[2][1].headers.Authorization).toBe('Bearer owner');
    expect(blob.size).toBeGreaterThan(0);
  });
  it('scopes timesheets and audited corrections with revision-bearing DELETE bodies', async () => {
    const fetcher = vi.fn().mockImplementation(async () => new Response(JSON.stringify({ data: [] })));
    vi.stubGlobal('fetch', fetcher);
    const api = createTimekeepingEndpoints(new AlqoveClient({ baseUrl: 'https://api.test' }));
    await api.timesheets.own('s1');
    await api.timesheets.list('s1', '2026-09-07');
    await api.timesheets.detail('s1', 't1');
    await api.timesheets.recalculate('s1', '2026-09-07');
    await api.timesheets.approve('s1', 't1', true);
    await api.timesheets.unlock('s1', 't1');
    await api.punches.remove('s1', 'p1', { revision: 'r1', note: 'Duplicate' });
    expect(fetcher.mock.calls[0][0]).toBe('https://api.test/v1/stores/s1/my/timesheets');
    expect(fetcher.mock.calls[1][0]).toContain('/s1/timesheets?week_start=2026-09-07');
    expect(JSON.parse(fetcher.mock.calls[4][1].body)).toEqual({ acknowledge_oversized_sessions: true });
    expect(fetcher.mock.calls[6][1].method).toBe('DELETE');
    expect(JSON.parse(fetcher.mock.calls[6][1].body)).toEqual({ revision: 'r1', note: 'Duplicate' });
  });
  it('sends only clock intent and preserves caller retry keys', async () => {
    const fetcher = vi.fn().mockImplementation(async () => new Response(JSON.stringify({ data: { status: 'clocked_in' } })));
    vi.stubGlobal('fetch', fetcher);
    const api = createTimekeepingEndpoints(new AlqoveClient({ baseUrl: 'https://api.test', getToken: () => 'token' }));
    await api.clock.act('s1', { action: 'clock', state_revision: 'empty' }, 'same-command');
    await api.clock.act('s1', { action: 'clock', state_revision: 'empty' }, 'same-command');
    for (const [url, options] of fetcher.mock.calls) {
      expect(url).toBe('https://api.test/v1/stores/s1/my/clock');
      expect(options.headers['Idempotency-Key']).toBe('same-command');
      expect(JSON.parse(options.body)).toEqual({ action: 'clock', state_revision: 'empty' });
    }
  });
});
