import { describe, test, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { useRef, 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 type { LexicalEditor } from 'lexical';
import EditorRefPlugin from './EditorRefPlugin.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('EditorRefPlugin', () => {
  test('stores editor instance in provided ref', async () => {
    const TestWrapper = () => {
      const editorRef = useRef<LexicalEditor | null>(null);
      const [hasEditor, setHasEditor] = useState(false);

      return (
        <>
          <TestEditor>
            <EditorRefPlugin editorRef={editorRef} />
          </TestEditor>
          <button onClick={() => setHasEditor(editorRef.current !== null)}>Check Ref</button>
          <div data-testid="result">{hasEditor ? 'Has Editor' : 'No Editor'}</div>
        </>
      );
    };

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

    await screen.findByTestId('editor');

    const checkButton = screen.getByRole('button', { name: 'Check Ref' });
    await user.click(checkButton);

    const result = screen.getByTestId('result');
    expect(result.textContent).toBe('Has Editor');
  });

  test('editor ref has expected methods', async () => {
    const TestWrapper = () => {
      const editorRef = useRef<LexicalEditor | null>(null);
      const [methods, setMethods] = useState<string[]>([]);

      const checkMethods = () => {
        if (editorRef.current) {
          const availableMethods: string[] = [];
          if (typeof editorRef.current.update === 'function') availableMethods.push('update');
          if (typeof editorRef.current.getEditorState === 'function')
            availableMethods.push('getEditorState');
          if (typeof editorRef.current.registerUpdateListener === 'function')
            availableMethods.push('registerUpdateListener');
          setMethods(availableMethods);
        }
      };

      return (
        <>
          <TestEditor>
            <EditorRefPlugin editorRef={editorRef} />
          </TestEditor>
          <button onClick={checkMethods}>Check Methods</button>
          <div data-testid="methods">{methods.join(',')}</div>
        </>
      );
    };

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

    await screen.findByTestId('editor');

    const checkButton = screen.getByRole('button', { name: 'Check Methods' });
    await user.click(checkButton);

    const methodsDiv = screen.getByTestId('methods');
    expect(methodsDiv.textContent).toContain('update');
    expect(methodsDiv.textContent).toContain('getEditorState');
    expect(methodsDiv.textContent).toContain('registerUpdateListener');
  });
});
