import { renderToStaticMarkup } from 'react-dom/server';
import { describe, expect, it } from 'vitest';
import type { ModelLoadProgress, ModelOption } from '../../lib/contracts';
import { ChatSurface } from './ChatSurface';

const model: ModelOption = {
  id: 'bonsai-1.7b',
  manifestId: '1_7b',
  label: 'Bonsai 1.7B',
  architectureLabel: 'Qwen3 dense',
  parameters: '1.7B',
  runtimeLabel: 'WebGPU · WASM fallback',
  footprint: '237 MiB',
  availability: 'loaded',
  contextLimit: 32_768,
  defaultContext: 4_096,
};

const progress: ModelLoadProgress = {
  modelId: model.id,
  modelLabel: model.label,
  stage: 'ready',
  stageProgress: 1,
  downloadedBytes: 1,
  totalBytes: 1,
  residentBytes: 1,
  nativeStage: null,
  shards: [],
};

describe('ChatSurface message actions', () => {
  it('puts copy and role-specific regeneration controls under messages', () => {
    const html = renderToStaticMarkup(
      <ChatSurface
        activeModel={model}
        loadedModelId={model.id}
        messages={[
          { id: 'user', role: 'user', content: 'Write code', timestamp: '10:00' },
          { id: 'assistant', role: 'assistant', content: 'Done', timestamp: '10:01' },
        ]}
        streamState="complete"
        modelLoadProgress={progress}
        toolsEnabled={false}
        runtimeStatus="Ready"
        error={null}
        shardRetry={null}
        theme="light"
        onLoadModel={() => undefined}
        onDismissError={() => undefined}
        onRetryShard={() => undefined}
        onSend={() => undefined}
        onRegenerate={() => undefined}
        onEditUserMessage={() => undefined}
        onCancel={() => undefined}
        onToolsEnabledChange={() => undefined}
        onOpenConversationList={() => undefined}
        onOpenSettings={() => undefined}
      />,
    );

    expect(html.match(/aria-label="Copy message"/g)).toHaveLength(2);
    expect(html).toContain('aria-label="Regenerate from this message"');
    expect(html).toContain('aria-label="Regenerate this response"');
    expect(html).toContain('aria-label="Edit message and regenerate response"');
    expect(html).not.toContain('Regenerate last');
    expect(html).toContain('aria-label="Show available tools"');
    expect(html).toContain('<code>html_artifact</code>');
    expect(html).toContain('<code>artifact_update</code>');
    expect(html).toContain('<code>bar_chart</code>');
    expect(html).toContain('<code>pie_chart</code>');
    expect(html).toContain('<code>web_search</code>');
    expect(html).toContain('Network tools ask before sending a query.');
  });

  it('keeps text visible and identifies a structured tool call while streaming', () => {
    const html = renderToStaticMarkup(
      <ChatSurface
        activeModel={model}
        loadedModelId={model.id}
        messages={[
          {
            id: 'text',
            role: 'assistant',
            content: 'Visible streamed text',
            timestamp: '10:00',
            state: 'streaming',
          },
          {
            id: 'tool',
            role: 'assistant',
            content: '',
            timestamp: '10:01',
            state: 'streaming',
            toolActivity: { name: 'html_artifact', argumentCharacters: 12_345 },
          },
        ]}
        streamState="streaming"
        modelLoadProgress={progress}
        toolsEnabled
        runtimeStatus="Generating"
        error={null}
        shardRetry={null}
        theme="light"
        onLoadModel={() => undefined}
        onDismissError={() => undefined}
        onRetryShard={() => undefined}
        onSend={() => undefined}
        onRegenerate={() => undefined}
        onEditUserMessage={() => undefined}
        onCancel={() => undefined}
        onToolsEnabledChange={() => undefined}
        onOpenConversationList={() => undefined}
        onOpenSettings={() => undefined}
      />,
    );

    expect(html).toContain('Visible streamed text');
    expect(html).toContain('Generating html_artifact tool call');
    expect(html).toContain('<code>html_artifact</code>');
    expect(html).toContain('12,345 chars');
    expect(html.match(/stream-cursor/g)).toHaveLength(2);
  });

  it('renders generated artifacts inline with HTML and Rendered tabs', () => {
    const html = renderToStaticMarkup(
      <ChatSurface
        activeModel={model}
        loadedModelId={model.id}
        messages={[{
          id: 'assistant',
          role: 'assistant',
          content: 'Here is the app.',
          timestamp: '10:01',
          artifacts: [{
            id: 'artifact-one',
            title: 'Counter app',
            source: '<main>Counter</main>',
            sandboxedSource: '<!doctype html><main>Counter</main>',
            runtimeToken: 'artifact-one-runtime',
            createdAt: 1,
          }],
        }]}
        streamState="complete"
        modelLoadProgress={progress}
        toolsEnabled
        runtimeStatus="Ready"
        error={null}
        shardRetry={null}
        theme="light"
        onLoadModel={() => undefined}
        onDismissError={() => undefined}
        onRetryShard={() => undefined}
        onSend={() => undefined}
        onRegenerate={() => undefined}
        onEditUserMessage={() => undefined}
        onCancel={() => undefined}
        onToolsEnabledChange={() => undefined}
        onOpenConversationList={() => undefined}
        onOpenSettings={() => undefined}
      />,
    );

    expect(html).toContain('id="artifact-artifact-one"');
    expect(html).toContain('role="tab" aria-selected="true"');
    expect(html).toContain('>HTML</button>');
    expect(html).toContain('>Rendered</button>');
    expect(html).toContain('&lt;main&gt;Counter&lt;/main&gt;');
    expect(html).not.toContain('<iframe');
  });

  it('keeps text, tool results, artifacts, and later text in chronological order', () => {
    const html = renderToStaticMarkup(
      <ChatSurface
        activeModel={model}
        loadedModelId={model.id}
        messages={[{
          id: 'assistant',
          role: 'assistant',
          content: 'Before the chart. After the chart.',
          timestamp: '10:01',
          segments: [
            { id: 'before', kind: 'text', content: 'Before the chart.' },
            { id: 'chart-call', kind: 'tool', toolCallId: 'tool-one' },
            { id: 'after', kind: 'text', content: 'After the chart.' },
          ],
          tools: [{
            id: 'tool-one',
            name: 'bar_chart',
            input: '{"title":"Quarterly sales"}',
            output: '{"ok":true,"evaluation":{"status":"passed","errors":[]}}',
            state: 'complete',
            artifactId: 'artifact-one',
          }],
          artifacts: [{
            id: 'artifact-one',
            title: 'Quarterly sales',
            source: '<main>Quarterly sales</main>',
            sandboxedSource: '<!doctype html><main>Quarterly sales</main>',
            runtimeToken: 'artifact-one-runtime',
            createdAt: 1,
          }],
        }]}
        streamState="complete"
        modelLoadProgress={progress}
        toolsEnabled
        runtimeStatus="Ready"
        error={null}
        shardRetry={null}
        theme="light"
        onLoadModel={() => undefined}
        onDismissError={() => undefined}
        onRetryShard={() => undefined}
        onSend={() => undefined}
        onRegenerate={() => undefined}
        onEditUserMessage={() => undefined}
        onCancel={() => undefined}
        onToolsEnabledChange={() => undefined}
        onOpenConversationList={() => undefined}
        onOpenSettings={() => undefined}
      />,
    );

    const before = html.indexOf('Before the chart.');
    const tool = html.indexOf('<code>bar_chart</code>');
    const artifact = html.indexOf('id="artifact-artifact-one"');
    const after = html.indexOf('After the chart.');
    expect(before).toBeGreaterThan(-1);
    expect(tool).toBeGreaterThan(before);
    expect(artifact).toBeGreaterThan(tool);
    expect(after).toBeGreaterThan(artifact);
  });
});
