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, type InitialConfigType } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import { $createParagraphNode, $createTextNode, $getRoot, type LexicalEditor } from 'lexical';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import ClearTriggerPlugin from './ClearTriggerPlugin.js';

function AddContentButton({ text }: { text: string }) {
  const [editor] = useLexicalComposerContext();

  const handleClick = () => {
    editor.update(() => {
      const root = $getRoot();
      const paragraph = $createParagraphNode();
      paragraph.append($createTextNode(text));
      root.append(paragraph);
    });
  };

  return <button onClick={handleClick}>Add Content</button>;
}

function createInitialConfig(initialText?: string): InitialConfigType {
  return {
    namespace: 'TestEditor',
    onError: (error: Error, _editor: LexicalEditor) => {
      console.error(error);
    },
    ...(initialText && {
      editorState: (_editor: LexicalEditor) => {
        const root = $getRoot();
        const paragraph = $createParagraphNode();
        paragraph.append($createTextNode(initialText));
        root.append(paragraph);
      },
    }),
  };
}

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

describe('ClearTriggerPlugin', () => {
  test('clears editor when clearTrigger changes from 0 to positive number', async () => {
    const user = userEvent.setup();

    const TestWrapper = () => {
      const [clearTrigger, setClearTrigger] = useState(0);

      return (
        <>
          <TestEditor initialText="Some content to clear">
            <ClearTriggerPlugin clearTrigger={clearTrigger} />
          </TestEditor>
          <button onClick={() => setClearTrigger((prev) => prev + 1)}>Clear</button>
        </>
      );
    };

    render(<TestWrapper />);

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

    await waitFor(() => {
      expect(editor.textContent).toContain('Some content to clear');
    });

    const clearButton = screen.getByRole('button', { name: 'Clear' });
    await user.click(clearButton);

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

  test('does not clear editor when clearTrigger is 0', async () => {
    const TestWrapper = () => {
      return (
        <TestEditor initialText="Content should remain">
          <ClearTriggerPlugin clearTrigger={0} />
        </TestEditor>
      );
    };

    render(<TestWrapper />);

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

    await waitFor(() => {
      expect(editor.textContent).toContain('Content should remain');
    });

    // Content should still be there since clearTrigger is 0
    expect(editor.textContent).toContain('Content should remain');
  });

  test('clears editor multiple times when clearTrigger increments', async () => {
    const user = userEvent.setup();

    const TestWrapper = () => {
      const [clearTrigger, setClearTrigger] = useState(0);

      return (
        <>
          <TestEditor initialText="Initial content">
            <ClearTriggerPlugin clearTrigger={clearTrigger} />
            <AddContentButton text="New content" />
          </TestEditor>
          <button onClick={() => setClearTrigger((prev) => prev + 1)}>Clear</button>
        </>
      );
    };

    render(<TestWrapper />);

    const editor = await screen.findByTestId('editor');
    const clearButton = screen.getByRole('button', { name: 'Clear' });
    const addContentButton = screen.getByRole('button', { name: 'Add Content' });

    await waitFor(() => {
      expect(editor.textContent).toContain('Initial content');
    });

    // First clear
    await user.click(clearButton);
    await waitFor(() => {
      expect(editor.textContent).toBe('');
    });

    // Add new content
    await user.click(addContentButton);
    await waitFor(() => {
      expect(editor.textContent).toContain('New content');
    });

    // Second clear
    await user.click(clearButton);
    await waitFor(() => {
      expect(editor.textContent).toBe('');
    });

    // Add content again
    await user.click(addContentButton);
    await waitFor(() => {
      expect(editor.textContent).toContain('New content');
    });

    // Third clear
    await user.click(clearButton);
    await waitFor(() => {
      expect(editor.textContent).toBe('');
    });
  });
});
