import { describe, expect, it } from 'vitest';
import { partitionFeatureIds } from '../src/core/roleRouter';
import { classifyTopology, type ProvidersFile } from '../src/core/providers';
import { EscalationQueue } from '../src/core/workQueue';

describe('Part N topology + partition', () => {
  it('classifies valid stacks without orchestrator role', () => {
    const base: ProvidersFile = {
      advancedMode: true,
      operators: [],
      supervisor: null,
      supervisorModes: { resolveIr: true, resolveAllFailures: false, resolveEscalationsOnly: true },
    };
    const op = { type: 'mock' as const, connected: true, kind: 'mock' as const, label: 'm' };
    expect(classifyTopology({ ...base, advancedMode: false }).kind).toBe('solo');
    expect(classifyTopology({ ...base, operators: [op] }).kind).toBe('solo');
    expect(classifyTopology({ ...base, operators: [op], supervisor: op }).kind).toBe('failsafe');
    expect(classifyTopology({ ...base, operators: [op, op] }).kind).toBe('parallel');
    expect(classifyTopology({ ...base, operators: [op, op], supervisor: op }).kind).toBe('full');
  });

  it('partitions features into two non-empty disjoint sets', () => {
    const features = [
      { id: 'F1', deps: [], parentId: null },
      { id: 'F2', deps: ['F1'], parentId: null },
      { id: 'F3', deps: [], parentId: null },
      { id: 'F4', deps: ['F3'], parentId: null },
    ];
    const [a, b] = partitionFeatureIds(features);
    expect(a.length + b.length).toBe(4);
    expect(new Set([...a, ...b]).size).toBe(4);
    expect(a.length).toBeGreaterThan(0);
    expect(b.length).toBeGreaterThan(0);
  });

  it('work-stealing queue is enqueue-then-steal without blocking', () => {
    const q = new EscalationQueue();
    expect(q.enqueue('F1', 0)).toBe(true);
    expect(q.enqueue('F1', 0)).toBe(false);
    expect(q.enqueue('F2', 0)).toBe(true);
    expect(q.trySteal(['F9'], 1)).toBeNull();
    expect(q.trySteal(['F2', 'F1'], 1)).toBe('F1');
    expect(q.size).toBe(1);
    q.resolve('F2', 1);
    expect(q.size).toBe(0);
    expect(q.events.map(e => e.op)).toEqual(['enqueue', 'enqueue', 'steal', 'resolve']);
  });
});
