import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { MessagingProvider } from './provider';
import { Messenger } from './components/messenger';
import { MockAdapter } from './adapters/mock';
import { insertMention, resolveMentions, trailingMentionQuery } from './mentions';
import type { Person } from './types';

const people: Person[] = [
  { id: 'pp_sofia', name: 'Sofia Ramirez', kind: 'staff' },
  { id: 'pp_dan', name: 'Dan Whitaker', kind: 'staff' },
];

describe('mention helpers', () => {
  it('trailingMentionQuery finds the @token being typed', () => {
    expect(trailingMentionQuery('hey @Sof')).toBe('Sof');
    expect(trailingMentionQuery('@')).toBe('');
    expect(trailingMentionQuery('no mention here')).toBeNull();
    expect(trailingMentionQuery('done @Sofia Ramirez ')).toBeNull(); // completed, trailing space
  });

  it('insertMention replaces the trailing query, keeping the boundary', () => {
    expect(insertMention('hey @Sof', 'Sofia Ramirez')).toBe('hey @Sofia Ramirez ');
    expect(insertMention('@ch', 'channel')).toBe('@channel ');
  });

  it('resolveMentions maps names to ids; @channel expands to everyone', () => {
    expect(resolveMentions('ping @Sofia Ramirez', people)).toEqual(['pp_sofia']);
    expect(resolveMentions('nobody here', people)).toEqual([]);
    expect(resolveMentions('@channel ship it', people).sort()).toEqual(['pp_dan', 'pp_sofia']);
  });
});

describe('<Thread /> @mention autocomplete', () => {
  it('picking a suggestion inserts the name and send carries the mention id', async () => {
    const adapter = new MockAdapter();
    const sendSpy = vi.spyOn(adapter, 'send');
    render(
      <MessagingProvider adapter={adapter}>
        <Messenger />
      </MessagingProvider>,
    );
    const input = (await screen.findByLabelText('Message')) as HTMLInputElement;
    fireEvent.change(input, { target: { value: 'hey @Sof' } });

    // The suggestion (role=option) is distinct from the sidebar row of the same name.
    fireEvent.click(await screen.findByRole('option', { name: 'Sofia Ramirez' }));
    expect(input.value).toBe('hey @Sofia Ramirez ');

    fireEvent.click(screen.getByText('Send'));
    await waitFor(() => expect(sendSpy).toHaveBeenCalled());
    const opts = sendSpy.mock.calls[0]![2];
    expect(opts?.mentions).toContain('pp_sofia');
  });
});
