import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { setupFileRig, type FileTestRig } from '../integration/helpers/rig.js';
import { FingerprintRequiredError, NotFoundError, type FileEntry } from '../../src/index.js';

describe('Fingerprint gate', () => {
  let rig: FileTestRig;
  const verifiedSet = new Set<string>();

  beforeAll(async () => {
    verifiedSet.clear();
    rig = await setupFileRig({
      requireFingerprintVerifiedFor: (ctx) => {
        // Mutations require verification; reads are optional.
        const op = ctx.op;
        if (op === 'mkdir' || op === 'delete' || op === 'move' || op === 'write') return 'required';
        if (op === 'list') return 'optional';
        return 'optional';
      },
      isFingerprintVerified: (sender) => verifiedSet.has(sender),
      stat: async (ctx) => {
        const e: FileEntry = {
          name: ctx.path.split('/').filter(Boolean).pop() ?? '',
          kind: 'file', size: 1, mtime: 0, metadata: {},
        };
        return e;
      },
      mkdir: async (ctx) => {
        const e: FileEntry = {
          name: ctx.path.split('/').filter(Boolean).pop() ?? '',
          kind: 'dir', size: 0, mtime: 0, metadata: {},
        };
        return { entry: e };
      },
      delete: async () => ({ deletedCount: 1 }),
      list: async () => ({ entries: [], hasMore: false }),
    });
  });

  afterAll(async () => {
    await rig.teardown();
  });

  test('mutation without verification → FingerprintRequiredError', async () => {
    verifiedSet.delete('alice');
    await expect(rig.fs.mkdir('/locked')).rejects.toBeInstanceOf(FingerprintRequiredError);
    await expect(rig.fs.delete('/locked')).rejects.toBeInstanceOf(FingerprintRequiredError);
  });

  test('mutation after marking peer verified → succeeds', async () => {
    verifiedSet.add('alice');
    const result = await rig.fs.mkdir('/verified-dir');
    expect(result.entry.name).toBe('verified-dir');
  });

  test('optional ops (stat, list) work without verification', async () => {
    verifiedSet.delete('alice');
    const stat = await rig.fs.stat('/anything');
    expect(stat.name).toBe('anything');
    const list = await rig.fs.list('/anything');
    expect(list.entries).toEqual([]);
  });
});

describe('Fingerprint gate with reject policy', () => {
  let rig: FileTestRig;
  beforeAll(async () => {
    rig = await setupFileRig({
      requireFingerprintVerifiedFor: () => 'reject',
      stat: async (ctx) => {
        const e: FileEntry = {
          name: 'x',
          kind: 'file',
          size: 1,
          mtime: 0,
          metadata: {},
        };
        return e;
      },
    });
  });
  afterAll(async () => { await rig.teardown(); });

  test('all ops rejected outright', async () => {
    await expect(rig.fs.stat('/x')).rejects.toBeInstanceOf(FingerprintRequiredError);
  });
});
