/**
 * Unit tests for blocked-handler
 *
 * Tests blocked state handling including user input callback flow.
 */

import { describe, it, expect, vi } from 'vitest';
import { handleBlocked } from '../core/piece/engine/blocked-handler.js';
import type { AgentResponse } from '../core/models/types.js';
import type { PieceEngineOptions } from '../core/piece/types.js';
import { makeMovement } from './test-helpers.js';

function makeResponse(content: string): AgentResponse {
  return {
    persona: 'tester',
    status: 'blocked',
    content,
    timestamp: new Date(),
  };
}

function makeOptions(overrides: Partial<PieceEngineOptions> = {}): PieceEngineOptions {
  return {
    projectCwd: '/tmp/project',
    ...overrides,
  };
}

describe('handleBlocked', () => {
  it('should return shouldContinue=false when no onUserInput callback', async () => {
    const result = await handleBlocked(
      makeMovement(),
      makeResponse('blocked message'),
      makeOptions(),
    );

    expect(result.shouldContinue).toBe(false);
    expect(result.userInput).toBeUndefined();
  });

  it('should call onUserInput and return user input', async () => {
    const onUserInput = vi.fn().mockResolvedValue('user response');
    const result = await handleBlocked(
      makeMovement(),
      makeResponse('質問: どうしますか？'),
      makeOptions({ onUserInput }),
    );

    expect(result.shouldContinue).toBe(true);
    expect(result.userInput).toBe('user response');
    expect(onUserInput).toHaveBeenCalledOnce();
  });

  it('should return shouldContinue=false when user cancels (returns null)', async () => {
    const onUserInput = vi.fn().mockResolvedValue(null);
    const result = await handleBlocked(
      makeMovement(),
      makeResponse('blocked'),
      makeOptions({ onUserInput }),
    );

    expect(result.shouldContinue).toBe(false);
    expect(result.userInput).toBeUndefined();
  });

  it('should pass extracted prompt in the request', async () => {
    const onUserInput = vi.fn().mockResolvedValue('answer');
    await handleBlocked(
      makeMovement(),
      makeResponse('質問: 環境は何ですか？'),
      makeOptions({ onUserInput }),
    );

    const request = onUserInput.mock.calls[0]![0];
    expect(request.prompt).toBe('環境は何ですか？');
  });

  it('should pass the full content as prompt when no pattern matches', async () => {
    const onUserInput = vi.fn().mockResolvedValue('answer');
    const content = 'I need more information to continue';
    await handleBlocked(
      makeMovement(),
      makeResponse(content),
      makeOptions({ onUserInput }),
    );

    const request = onUserInput.mock.calls[0]![0];
    expect(request.prompt).toBe(content);
  });

  it('should pass movement and response in the request', async () => {
    const step = makeMovement();
    const response = makeResponse('blocked');
    const onUserInput = vi.fn().mockResolvedValue('answer');

    await handleBlocked(step, response, makeOptions({ onUserInput }));

    const request = onUserInput.mock.calls[0]![0];
    expect(request.movement).toBe(step);
    expect(request.response).toBe(response);
  });
});
