import { describe, test, expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { useState } from 'react';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import InitialTextPlugin from './InitialTextPlugin.js';

const initialConfig = {
  namespace: 'TestEditor',
  onError: (error: Error) => console.error(error),
  nodes: [],
};

function TestEditor({ children }: { children: React.ReactNode }) {
  return (
    <LexicalComposer initialConfig={initialConfig}>
      <RichTextPlugin
        contentEditable={<ContentEditable data-testid="editor" />}
        ErrorBoundary={LexicalErrorBoundary}
      />
      {children}
    </LexicalComposer>
  );
}

describe('InitialTextPlugin', () => {
  test('sets plain text as initial content', async () => {
    render(
      <TestEditor>
        <InitialTextPlugin initialText="Hello initial text" />
      </TestEditor>,
    );

    const editor = await screen.findByTestId('editor');

    await waitFor(() => {
      expect(editor.textContent).toContain('Hello initial text');
    });
  });

  test('sets HTML as initial content', async () => {
    render(
      <TestEditor>
        <InitialTextPlugin initialText="<p><strong>Bold text</strong></p>" />
      </TestEditor>,
    );

    const editor = await screen.findByTestId('editor');

    await waitFor(() => {
      expect(editor.textContent).toContain('Bold text');
      // eslint-disable-next-line testing-library/no-node-access -- Lexical rich text DOM
      expect(editor.querySelector('strong')).toBeInTheDocument();
    });
  });

  test('does not set content when initialText is undefined', async () => {
    render(
      <TestEditor>
        <InitialTextPlugin initialText={undefined} />
      </TestEditor>,
    );

    const editor = await screen.findByTestId('editor');

    // Editor should be empty (Lexical adds a <br> by default)
    await waitFor(() => {
      expect(editor.textContent).toBe('');
    });
  });

  test('only initializes once even if initialText changes', async () => {
    const TestWrapper = () => {
      const [text, setText] = useState('First text');

      return (
        <>
          <TestEditor>
            <InitialTextPlugin initialText={text} />
          </TestEditor>
          <button onClick={() => setText('Second text')}>Change Text</button>
        </>
      );
    };

    const user = userEvent.setup();
    render(<TestWrapper />);

    const editor = await screen.findByTestId('editor');

    await waitFor(() => {
      expect(editor.textContent).toContain('First text');
    });

    const changeButton = screen.getByRole('button', { name: 'Change Text' });
    await user.click(changeButton);

    // Should still show first text since it only initializes once
    await waitFor(() => {
      expect(editor.textContent).toContain('First text');
      expect(editor.textContent).not.toContain('Second text');
    });
  });

  test('handles empty string as initial text', async () => {
    render(
      <TestEditor>
        <InitialTextPlugin initialText="" />
      </TestEditor>,
    );

    const editor = await screen.findByTestId('editor');

    await waitFor(() => {
      expect(editor.textContent).toBe('');
    });
  });
});
