import { describe, expect, it, vi } from 'vitest';

import { MemberWorkSyncTeamChangeRouter } from '@features/member-work-sync/main/adapters/input/MemberWorkSyncTeamChangeRouter';

function createRouter(activeMembers: string[] = ['alice', 'bob']) {
  const queue = {
    enqueue: vi.fn(),
    dropTeam: vi.fn(),
  };
  const router = new MemberWorkSyncTeamChangeRouter(
    {
      loadActiveMemberNames: async () => activeMembers,
    },
    queue as never
  );
  return { queue, router };
}

describe('MemberWorkSyncTeamChangeRouter', () => {
  it('routes task and config events to all active members', async () => {
    const { queue, router } = createRouter();

    router.noteTeamChange({ type: 'task', teamName: 'team-a', detail: 'task-1.json' });
    await Promise.resolve();

    expect(queue.enqueue).toHaveBeenCalledWith({
      teamName: 'team-a',
      memberName: 'alice',
      triggerReason: 'task_changed',
      runAfterMs: undefined,
    });
    expect(queue.enqueue).toHaveBeenCalledWith({
      teamName: 'team-a',
      memberName: 'bob',
      triggerReason: 'task_changed',
      runAfterMs: undefined,
    });
  });

  it('routes task events to resolver-impacted members when task identity is available', async () => {
    const queue = {
      enqueue: vi.fn(),
      dropTeam: vi.fn(),
    };
    const resolver = {
      resolve: vi.fn(async () => ({
        memberNames: ['bob'],
        fallbackTeamWide: false,
        diagnostics: [],
      })),
    };
    const router = new MemberWorkSyncTeamChangeRouter(
      { loadActiveMemberNames: async () => ['alice', 'bob'] },
      queue as never,
      undefined,
      resolver as never
    );

    router.noteTeamChange({
      type: 'task',
      teamName: 'team-a',
      detail: 'task-1.json',
      taskId: 'task-1',
    });
    await Promise.resolve();
    await Promise.resolve();

    expect(resolver.resolve).toHaveBeenCalledWith({ teamName: 'team-a', taskId: 'task-1' });
    expect(queue.enqueue).toHaveBeenCalledTimes(1);
    expect(queue.enqueue).toHaveBeenCalledWith({
      teamName: 'team-a',
      memberName: 'bob',
      triggerReason: 'task_changed',
    });
  });

  it('routes inbox and tool-finish events to the addressed member only', () => {
    const { queue, router } = createRouter();

    router.noteTeamChange({ type: 'inbox', teamName: 'team-a', detail: 'inboxes/bob.json' });
    router.noteTeamChange({
      type: 'tool-activity',
      teamName: 'team-a',
      detail: JSON.stringify({ action: 'finish', memberName: 'alice', toolUseId: 'tool-1' }),
    });

    expect(queue.enqueue).toHaveBeenCalledWith({
      teamName: 'team-a',
      memberName: 'bob',
      triggerReason: 'inbox_changed',
    });
    expect(queue.enqueue).toHaveBeenCalledWith({
      teamName: 'team-a',
      memberName: 'alice',
      triggerReason: 'tool_finished',
    });
  });

  it('drops queued work when the team goes offline', () => {
    const { queue, router } = createRouter();

    router.noteTeamChange({ type: 'lead-activity', teamName: 'team-a', detail: 'offline' });

    expect(queue.dropTeam).toHaveBeenCalledWith('team-a');
    expect(queue.enqueue).not.toHaveBeenCalled();
  });

  it('routes member-turn-settled events to one member reconcile', () => {
    const { queue, router } = createRouter();

    router.noteTeamChange({
      type: 'member-turn-settled',
      teamName: 'team-a',
      detail: JSON.stringify({ memberName: 'alice', sourceId: 'source-1', provider: 'claude' }),
    });

    expect(queue.enqueue).toHaveBeenCalledWith({
      teamName: 'team-a',
      memberName: 'alice',
      triggerReason: 'turn_settled',
    });
  });

  it('ignores malformed member-turn-settled details', () => {
    const { queue, router } = createRouter();

    router.noteTeamChange({
      type: 'member-turn-settled',
      teamName: 'team-a',
      detail: 'not-json',
    });

    expect(queue.enqueue).not.toHaveBeenCalled();
  });
});
