/*
 * Phase 5 — priority directives. Tests the pure resolver core that turns a
 * stream of `priority_directive` memory events + a sharedTaskId→local-task map
 * into the pending directives a forge should apply. The async wrappers
 * (issue/get/apply) are thin I/O over this.
 */

import { describe, it, expect } from 'vitest';
import { resolveDirectives } from '../src/orchestration/shared-tasks';
import type { TeamMemoryEvent } from 'priority-forge-hub';
import type { Priority } from '../src/types/schema';

type Ref = { id: string; priority: Priority; status: string };

function directive(
  sharedTaskId: string,
  priority: Priority,
  ts: string,
  opts: { agentId?: string; eventId?: string; note?: string } = {},
): TeamMemoryEvent {
  return {
    eventId: opts.eventId ?? `e-${Math.random().toString(36).slice(2)}`,
    teamId: 't',
    agentId: opts.agentId ?? 'lead@team',
    workspaceId: 'w',
    eventType: 'priority_directive',
    timestamp: ts,
    payload: { sharedTaskId, priority, ...(opts.note ? { note: opts.note } : {}) },
    summary: '',
    metadata: {},
  };
}

describe('resolveDirectives', () => {
  it('keeps the latest directive per SharedTask and flags unsatisfied', () => {
    const events = [
      directive('st_1', 'P2', '2026-05-22T00:00:00Z'),
      directive('st_1', 'P0', '2026-05-22T01:00:00Z'), // newer wins
    ];
    const local = new Map<string, Ref>([['st_1', { id: 'L1', priority: 'P2', status: 'in_progress' }]]);
    const out = resolveDirectives(events, local);
    expect(out).toHaveLength(1);
    expect(out[0].suggestedPriority).toBe('P0');
    expect(out[0].currentPriority).toBe('P2');
    expect(out[0].satisfied).toBe(false);
    expect(out[0].localTaskId).toBe('L1');
  });

  it('marks satisfied when the local task already matches', () => {
    const events = [directive('st_1', 'P0', '2026-05-22T01:00:00Z')];
    const local = new Map<string, Ref>([['st_1', { id: 'L1', priority: 'P0', status: 'in_progress' }]]);
    expect(resolveDirectives(events, local)[0].satisfied).toBe(true);
  });

  it('skips directives for unowned or completed local tasks', () => {
    const events = [
      directive('st_unknown', 'P0', '2026-05-22T01:00:00Z'),
      directive('st_done', 'P0', '2026-05-22T01:00:00Z'),
    ];
    const local = new Map<string, Ref>([['st_done', { id: 'L9', priority: 'P2', status: 'complete' }]]);
    expect(resolveDirectives(events, local)).toHaveLength(0);
  });

  it('ignores non-directive events and malformed payloads', () => {
    const other: TeamMemoryEvent = {
      eventId: 'x', teamId: 't', agentId: 'a', workspaceId: 'w',
      eventType: 'task_created', timestamp: '2026-05-22T01:00:00Z',
      payload: { sharedTaskId: 'st_1', priority: 'P0' }, summary: '', metadata: {},
    };
    const malformed = directive('', 'P0', '2026-05-22T01:00:00Z'); // empty sharedTaskId
    const local = new Map<string, Ref>([['st_1', { id: 'L1', priority: 'P2', status: 'in_progress' }]]);
    expect(resolveDirectives([other, malformed], local)).toHaveLength(0);
  });

  it('carries the issuing agent + note through', () => {
    const events = [directive('st_1', 'P1', '2026-05-22T01:00:00Z', { agentId: 'nick@team', note: 'vision' })];
    const local = new Map<string, Ref>([['st_1', { id: 'L1', priority: 'P3', status: 'not_started' }]]);
    const out = resolveDirectives(events, local);
    expect(out[0].byAgentId).toBe('nick@team');
    expect(out[0].note).toBe('vision');
  });
});
