/**
 * Phase 9 / Task 24: job-crossing screen injection.
 *
 * Phase 4 unit tests in agent-loop.test.ts already verify the *one-shot*
 * `buildSystemPrompt` console injection logic. This file is a focused
 * regression for the multi-iteration / job-crossing property: when the
 * orchestrator runs multiple ReAct iterations (or even multiple jobs
 * within the same local task), each new system prompt must re-read the
 * live PTY screen rather than caching a stale snapshot. The plan
 * (docs/superpowers/plans/2026-05-13-ssh-console.md §9.2) calls this out
 * because the orchestrator's auto-context-trim path can rebuild prompts
 * mid-task without an explicit Send/Snapshot tool call.
 */
import { describe, it, expect, afterEach } from 'vitest';
import { buildSystemPrompt, __setActiveSessionLookup, type Movement } from './agent-loop.js';

function makeConsoleMovement(allowedTools: string[]): Movement {
  return {
    name: 'm',
    edit: false,
    persona: 'p',
    instruction: 'i',
    allowedTools,
    rules: [{ condition: 'done', next: 'COMPLETE' }],
    defaultNext: 'COMPLETE',
  };
}

describe('console session lookup across jobs', () => {
  afterEach(() => {
    __setActiveSessionLookup(null);
  });

  it('agent-loop reads injected screen on every iteration for the same task', () => {
    const fakeSession = {
      cols: 80,
      rows: 24,
      snapshotScreen: () => ({
        cols: 80,
        rows: 24,
        text: '$ pwd\n/var/log\n$ ',
        cursor: { x: 0, y: 0 },
      }),
    };
    __setActiveSessionLookup((_t: string) => fakeSession);

    // Build the prompt twice (simulating two ReAct iterations against the
    // same task: e.g. the engine reruns buildSystemPrompt after a
    // context-window trim, or for a fresh movement visit on revisit). Both
    // prompts must contain the live screen tail.
    const p1 = buildSystemPrompt(
      makeConsoleMovement(['SshConsoleSend']),
      1, // visitCount
      5, // maxVisits
      [], // tools
      undefined, // workspaceMemory
      null, // missionBrief
      undefined, // userId
      undefined, // userFolderRoot
      undefined, // workspacePath
      't1', // taskId
    );
    const p2 = buildSystemPrompt(
      makeConsoleMovement(['SshConsoleSend']),
      2,
      5,
      [],
      undefined,
      null,
      undefined,
      undefined,
      undefined,
      't1',
    );
    expect(p1).toContain('/var/log');
    expect(p2).toContain('/var/log');
    expect(p1).toContain('Console screen');
    expect(p2).toContain('Console screen');
  });

  it('updates the injected screen when the session text changes between calls', () => {
    // Simulates a real shell session: the AI's first iteration sees the
    // login banner; a subsequent SshConsoleSend mutates the screen; the
    // *next* iteration must see the post-Send screen, not the cached one.
    let screen = '$ ';
    __setActiveSessionLookup((_t: string) => ({
      cols: 80,
      rows: 24,
      snapshotScreen: () => ({ cols: 80, rows: 24, text: screen, cursor: { x: 0, y: 0 } }),
    }));

    const before = buildSystemPrompt(
      makeConsoleMovement(['SshConsoleSnapshot']),
      1,
      5,
      [],
      undefined,
      null,
      undefined,
      undefined,
      undefined,
      't1',
    );
    expect(before).toContain('Console screen');
    expect(before).not.toContain('hello-world');

    screen = '$ echo hello-world\nhello-world\n$ ';
    const after = buildSystemPrompt(
      makeConsoleMovement(['SshConsoleSnapshot']),
      2,
      5,
      [],
      undefined,
      null,
      undefined,
      undefined,
      undefined,
      't1',
    );
    expect(after).toContain('hello-world');
  });

  it('lookup receives the taskId so distinct tasks resolve to distinct sessions', () => {
    const lookups: string[] = [];
    __setActiveSessionLookup((tid: string) => {
      lookups.push(tid);
      return {
        cols: 80,
        rows: 24,
        snapshotScreen: () => ({ cols: 80, rows: 24, text: `screen-for-${tid}`, cursor: { x: 0, y: 0 } }),
      };
    });

    const pA = buildSystemPrompt(
      makeConsoleMovement(['SshConsoleSend']),
      1,
      5,
      [],
      undefined,
      null,
      undefined,
      undefined,
      undefined,
      'task-A',
    );
    const pB = buildSystemPrompt(
      makeConsoleMovement(['SshConsoleSend']),
      1,
      5,
      [],
      undefined,
      null,
      undefined,
      undefined,
      undefined,
      'task-B',
    );
    expect(lookups).toEqual(['task-A', 'task-B']);
    expect(pA).toContain('screen-for-task-A');
    expect(pB).toContain('screen-for-task-B');
    expect(pA).not.toContain('screen-for-task-B');
    expect(pB).not.toContain('screen-for-task-A');
  });
});
