import { describe, it, expect } from 'vitest';
import { buildLocalConversationContext } from './local-context.js';
import type { LocalTaskComment } from '../db/repository.js';

function comment(id: number, author: string, kind: string, body: string): LocalTaskComment {
  return { id, taskId: 1, author, kind, body, createdAt: `2026-05-29T00:00:${String(id).padStart(2, '0')}Z`, injectedAt: null };
}

describe('buildLocalConversationContext', () => {
  it('shows the original task with no follow-up when only the initial request exists', () => {
    const out = buildLocalConversationContext({
      comments: [comment(1, 'user', 'request', 'A を調べて')],
      jobInstruction: 'A を調べて',
      inputFiles: [],
      outputFiles: [],
    });
    expect(out).toContain('## タスク');
    expect(out).toContain('A を調べて');
    expect(out).not.toContain('## 現在のユーザー指示');
  });

  it('treats the latest interjection as the current instruction', () => {
    const comments = [
      comment(1, 'user', 'request', 'A を調べて'),
      comment(2, 'agent', 'progress', '調査中...'),
      comment(3, 'user', 'interjection', 'やっぱり B を優先して'),
    ];
    const out = buildLocalConversationContext({
      comments,
      jobInstruction: 'A を調べて',
      inputFiles: [],
      outputFiles: [],
    });
    expect(out).toContain('## 現在のユーザー指示 (これに対応する)');
    expect(out).toContain('やっぱり B を優先して');
    expect(out).toContain('## オリジナルタスク (参考、対応済みの可能性あり)');
    // interjection body also appears in the recent-conversation block
    expect(out).toContain('[user/interjection] やっぱり B を優先して');
  });

  it('keeps a user interjection visible even when many agent progress rows would crowd it out', () => {
    const comments: LocalTaskComment[] = [comment(1, 'user', 'interjection', 'C をやって')];
    for (let i = 2; i <= 14; i++) comments.push(comment(i, 'agent', 'progress', `step ${i}`));
    const out = buildLocalConversationContext({
      comments,
      jobInstruction: '元のタスク',
      inputFiles: [],
      outputFiles: [],
    });
    // last-10 window is all agent rows; the fix must still surface the user message
    expect(out).toContain('[user/interjection] C をやって');
    expect(out).toContain('## 現在のユーザー指示 (これに対応する)');
    expect(out).toContain('C をやって');
  });

  it('truncates long comment bodies in the recent-conversation block', () => {
    const long = 'x'.repeat(600);
    // `long` is an OLDER comment so it only appears in the recent block (truncated),
    // not as the current instruction (which would render the full body by design).
    const out = buildLocalConversationContext({
      comments: [comment(1, 'user', 'request', long), comment(2, 'user', 'request', 'newer')],
      jobInstruction: 'newer',
      inputFiles: [],
      outputFiles: [],
    });
    expect(out).toContain('x'.repeat(500) + '...');
    expect(out).not.toContain('x'.repeat(600));
  });

  it('lists workspace files', () => {
    const out = buildLocalConversationContext({
      comments: [],
      jobInstruction: 'task',
      inputFiles: ['a.csv'],
      outputFiles: ['report.md'],
    });
    expect(out).toContain('input/: a.csv');
    expect(out).toContain('output/: report.md');
  });
});
