import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { Composer } from './composer';

function mount(onSend = vi.fn().mockResolvedValue(undefined)) {
  render(<Composer members={[]} canUpload={false} upload={vi.fn()} onSend={onSend} />);
  return { onSend, box: screen.getByLabelText('Message') as HTMLTextAreaElement };
}

describe('<Composer /> formatting + native text services', () => {
  it('is a textarea with the platform spellchecker enabled', () => {
    const { box } = mount();
    expect(box.tagName).toBe('TEXTAREA');
    // The red squiggle + right-click suggestions come from the OS via these attributes.
    expect(box.getAttribute('spellcheck')).toBe('true');
    expect(box.getAttribute('autocorrect')).toBe('on');
  });

  it('does NOT reuse .miu-textarea — that class belongs to the inbox mail composer', () => {
    // Regression: sharing it let the mail rule (resize: vertical; min-height: 90px), which is
    // declared later in the stylesheet, win at equal specificity and inflate the chat composer.
    const { box } = mount();
    expect(box.classList.contains('miu-composer-box')).toBe(true);
    expect(box.classList.contains('miu-textarea')).toBe(false);
  });

  it('Enter sends, Shift+Enter does not (it makes a newline)', async () => {
    const { onSend, box } = mount();
    fireEvent.change(box, { target: { value: 'hello' } });

    fireEvent.keyDown(box, { key: 'Enter', shiftKey: true });
    expect(onSend).not.toHaveBeenCalled();

    fireEvent.keyDown(box, { key: 'Enter' });
    await waitFor(() => expect(onSend).toHaveBeenCalledWith('hello', expect.anything()));
  });

  it('does not send mid-IME composition', () => {
    const { onSend, box } = mount();
    fireEvent.change(box, { target: { value: 'にほん' } });
    fireEvent.keyDown(box, { key: 'Enter', isComposing: true });
    expect(onSend).not.toHaveBeenCalled();
  });

  it('a toolbar button wraps the current selection in its marker', () => {
    const { box } = mount();
    fireEvent.change(box, { target: { value: 'make me bold' } });
    box.setSelectionRange(8, 12); // "bold"
    fireEvent.click(screen.getByLabelText('Bold (⌘B)'));
    expect(box.value).toBe('make me *bold*');
  });

  it('⌘B / ⌘I wrap the selection too', () => {
    const { box } = mount();
    fireEvent.change(box, { target: { value: 'hello world' } });
    box.setSelectionRange(0, 5);
    fireEvent.keyDown(box, { key: 'b', metaKey: true });
    expect(box.value).toBe('*hello* world');

    box.setSelectionRange(8, 13); // "world" shifted by the two markers
    fireEvent.keyDown(box, { key: 'i', ctrlKey: true });
    expect(box.value).toBe('*hello* _world_');
  });

  it('with nothing selected, a marker pair is inserted at the caret', () => {
    const { box } = mount();
    fireEvent.change(box, { target: { value: 'ab' } });
    box.setSelectionRange(2, 2);
    fireEvent.click(screen.getByLabelText('Italic (⌘I)'));
    expect(box.value).toBe('ab__');
  });

  it('sends the raw markers as plain text — formatting is a render concern', async () => {
    const { onSend, box } = mount();
    fireEvent.change(box, { target: { value: 'ship *today*' } });
    fireEvent.keyDown(box, { key: 'Enter' });
    await waitFor(() => expect(onSend).toHaveBeenCalledWith('ship *today*', expect.anything()));
  });
});
