// @vitest-environment jsdom
import '../../test/dom-setup';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWithProviders } from '../../test/render-helpers';
import { ChatPane } from './ChatPane';
import { __resetDraftPruneForTest } from '../../hooks/useDraft';
import type { LocalTask, LocalTaskComment } from '../../api';

const DRAFT_KEY = 'maestro:draft:v1:chat:42';

// useJobStream が EventSource を張るため jsdom にスタブを入れる
class FakeEventSource {
  onmessage: ((e: MessageEvent) => void) | null = null;
  onerror: (() => void) | null = null;
  addEventListener() {}
  removeEventListener() {}
  close() {}
}

const task = {
  id: 42,
  title: 'テストタスク',
  pieceName: 'chat',
  latestJob: undefined,
} as unknown as LocalTask;

beforeEach(() => {
  localStorage.clear();
  __resetDraftPruneForTest();
  vi.stubGlobal('EventSource', FakeEventSource);
  vi.stubGlobal('fetch', vi.fn(async () => new Response('{}', { status: 404 })));
  // ChatPetOverlay (rendered unconditionally by ChatPane) reads matchMedia for
  // prefers-reduced-motion; jsdom doesn't implement it. Minimal stub only —
  // not part of the brief, needed to get past mount.
  vi.stubGlobal('matchMedia', (query: string) => ({
    matches: false,
    media: query,
    addEventListener: () => {},
    removeEventListener: () => {},
  }));
});

describe('ChatPane drafts', () => {
  it('入力途中の内容がアンマウント後も復元される', async () => {
    const user = userEvent.setup();
    const first = renderWithProviders(
      <ChatPane task={task} comments={[]} onSubmit={vi.fn(async () => {})} />,
    );
    await user.type(screen.getByRole('textbox'), '書きかけの返信');
    first.unmount();
    expect(JSON.parse(localStorage.getItem(DRAFT_KEY)!).text).toBe('書きかけの返信');

    renderWithProviders(
      <ChatPane task={task} comments={[]} onSubmit={vi.fn(async () => {})} />,
    );
    expect(screen.getByRole('textbox')).toHaveValue('書きかけの返信');
  });

  it('送信成功で下書きが消える', async () => {
    localStorage.setItem(DRAFT_KEY, JSON.stringify({ text: '送る内容', updatedAt: Date.now() }));
    const user = userEvent.setup();
    const onSubmit = vi.fn(async () => {});
    renderWithProviders(<ChatPane task={task} comments={[]} onSubmit={onSubmit} />);
    const textbox = screen.getByRole('textbox');
    expect(textbox).toHaveValue('送る内容');
    // Ctrl+Enter は textarea にフォーカスがないと発火しないため、まずフォーカスする。
    await user.click(textbox);
    await user.keyboard('{Control>}{Enter}{/Control}');
    await waitFor(() => expect(onSubmit).toHaveBeenCalled());
    expect(localStorage.getItem(DRAFT_KEY)).toBeNull();
  });

  it('queued のままでもコメントが反映されたら送信ロックを外す', async () => {
    const user = userEvent.setup();
    const onSubmit = vi.fn(async () => {});
    const queuedTask = {
      ...task,
      latestJob: { status: 'queued' },
    } as LocalTask;
    const rendered = renderWithProviders(<ChatPane task={queuedTask} comments={[]} onSubmit={onSubmit} />);
    const textbox = screen.getByRole('textbox');
    await user.click(textbox);
    await user.type(textbox, '追記');

    const queuedButton = screen.getByRole('button', { name: /Add to task|追加/ });
    await user.click(queuedButton);
    await waitFor(() => expect(onSubmit).toHaveBeenCalledWith('追記', undefined));
    expect(queuedButton).toBeDisabled();

    rendered.rerender(
      <ChatPane
        task={queuedTask}
        comments={[
          {
            id: 1,
            taskId: 42,
            author: 'agent',
            kind: 'comment',
            body: '追記',
            createdAt: new Date().toISOString(),
            injectedAt: null,
          } as LocalTaskComment,
        ]}
        onSubmit={onSubmit}
      />,
    );

    const textboxAfter = screen.getByRole('textbox');
    await user.click(textboxAfter);
    await user.type(textboxAfter, '続き');
    await waitFor(() => expect(screen.getByRole('button', { name: /Add to task|追加/ })).toBeEnabled());
  });

  it('入力中のプロンプトコーチを常設ボタンから開閉できる', async () => {
    const user = userEvent.setup();
    renderWithProviders(<ChatPane task={task} comments={[]} onSubmit={vi.fn(async () => {})} />);
    await user.type(screen.getByRole('textbox'), '評価してほしい依頼');
    const coachButton = screen.getByRole('button', { name: /Evaluate prompt|プロンプトを評価/i });
    await user.click(coachButton);
    expect(screen.getByTestId('chat-prompt-coach')).toBeInTheDocument();
    await user.click(coachButton);
    expect(screen.queryByTestId('chat-prompt-coach')).not.toBeInTheDocument();
  });
});
