import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, it, expect, beforeEach, vi } from "vitest";
import { EntryEditor } from "../EntryEditor";

// Mock the LinkAutocomplete component
vi.mock("../LinkAutocomplete", () => ({
  LinkAutocomplete: (): React.JSX.Element => (
    <div data-testid="link-autocomplete">LinkAutocomplete</div>
  ),
}));

describe("EntryEditor", (): void => {
  const defaultProps = {
    content: "",
    onChange: vi.fn(),
  };

  beforeEach((): void => {
    vi.clearAllMocks();
  });

  it("should render textarea in edit mode by default", (): void => {
    render(<EntryEditor {...defaultProps} />);

    const textarea = screen.getByPlaceholderText(/Write your content here/);
    expect(textarea).toBeInTheDocument();
    expect(textarea.tagName).toBe("TEXTAREA");
  });

  it("should display current content in textarea", (): void => {
    const content = "# Test Content\n\nThis is a test.";
    render(<EntryEditor {...defaultProps} content={content} />);

    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
    const textarea = screen.getByPlaceholderText(/Write your content here/) as HTMLTextAreaElement;
    expect(textarea.value).toBe(content);
  });

  it("should call onChange when content is modified", async (): Promise<void> => {
    const user = userEvent.setup();
    const onChangeMock = vi.fn();

    render(<EntryEditor {...defaultProps} onChange={onChangeMock} />);

    const textarea = screen.getByPlaceholderText(/Write your content here/);
    await user.type(textarea, "Hello");

    expect(onChangeMock).toHaveBeenCalled();
  });

  it("should toggle between edit and preview modes", async (): Promise<void> => {
    const user = userEvent.setup();
    const content = "# Test\n\nPreview this content.";

    render(<EntryEditor {...defaultProps} content={content} />);

    // Initially in edit mode
    expect(screen.getByPlaceholderText(/Write your content here/)).toBeInTheDocument();
    expect(screen.getByText("Preview")).toBeInTheDocument();

    // Switch to preview mode
    const previewButton = screen.getByText("Preview");
    await user.click(previewButton);

    // Should show preview
    expect(screen.queryByPlaceholderText(/Write your content here/)).not.toBeInTheDocument();
    expect(screen.getByText("Edit")).toBeInTheDocument();
    // Check for partial content (newlines may split text across elements)
    expect(screen.getByText(/Test/)).toBeInTheDocument();
    expect(screen.getByText(/Preview this content/)).toBeInTheDocument();

    // Switch back to edit mode
    const editButton = screen.getByText("Edit");
    await user.click(editButton);

    // Should show textarea again
    expect(screen.getByPlaceholderText(/Write your content here/)).toBeInTheDocument();
    expect(screen.getByText("Preview")).toBeInTheDocument();
  });

  it("should render LinkAutocomplete component in edit mode", (): void => {
    render(<EntryEditor {...defaultProps} />);

    expect(screen.getByTestId("link-autocomplete")).toBeInTheDocument();
  });

  it("should not render LinkAutocomplete in preview mode", async (): Promise<void> => {
    const user = userEvent.setup();

    render(<EntryEditor {...defaultProps} />);

    // LinkAutocomplete should be present in edit mode
    expect(screen.getByTestId("link-autocomplete")).toBeInTheDocument();

    // Switch to preview mode
    const previewButton = screen.getByText("Preview");
    await user.click(previewButton);

    // LinkAutocomplete should not be in preview mode
    expect(screen.queryByTestId("link-autocomplete")).not.toBeInTheDocument();
  });

  it("should show help text about wiki-link syntax", (): void => {
    render(<EntryEditor {...defaultProps} />);

    expect(screen.getByText(/Type/)).toBeInTheDocument();
    expect(screen.getByText(/\[\[/)).toBeInTheDocument();
    expect(screen.getByText(/to insert links/)).toBeInTheDocument();
  });

  it("should maintain content when toggling between modes", async (): Promise<void> => {
    const user = userEvent.setup();
    const content = "# My Content\n\nThis should persist.";

    render(<EntryEditor {...defaultProps} content={content} />);

    // Verify content in edit mode
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
    const textarea = screen.getByPlaceholderText(/Write your content here/) as HTMLTextAreaElement;
    expect(textarea.value).toBe(content);

    // Toggle to preview
    await user.click(screen.getByText("Preview"));
    // Check for partial content (newlines may split text across elements)
    expect(screen.getByText(/My Content/)).toBeInTheDocument();
    expect(screen.getByText(/This should persist/)).toBeInTheDocument();

    // Toggle back to edit
    await user.click(screen.getByText("Edit"));
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
    const textareaAfter = screen.getByPlaceholderText(
      /Write your content here/
    ) as HTMLTextAreaElement;
    expect(textareaAfter.value).toBe(content);
  });

  it("should apply correct styling classes", (): void => {
    render(<EntryEditor {...defaultProps} />);

    const textarea = screen.getByPlaceholderText(/Write your content here/);
    expect(textarea).toHaveClass("font-mono");
    expect(textarea).toHaveClass("text-sm");
    expect(textarea).toHaveClass("min-h-[300px]");
  });

  it("should have label for content field", (): void => {
    render(<EntryEditor {...defaultProps} />);

    expect(screen.getByText("Content (Markdown)")).toBeInTheDocument();
  });
});
