import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";
import "@testing-library/jest-dom/vitest";
import { Controls } from "../Controls";

describe("Controls Component", () => {
  // Test basic rendering with required props
  describe("Basic Rendering", () => {
    it("should render a button element with correct icon", () => {
      // Test that the component renders as a button with the specified icon
      render(<Controls icon="close" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
      expect(button).toHaveClass("controls");
    });

    it("should render with custom className", () => {
      // Test that custom CSS classes can be added
      render(<Controls icon="search" className="custom-class" />);

      const button = screen.getByRole("button");
      expect(button).toHaveClass("controls");
      expect(button).toHaveClass("custom-class");
    });

    it('should have type="button" by default', () => {
      // Test that the button has type="button" by default
      render(<Controls icon="close" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("type", "button");
    });
  });

  // Test different icon types
  describe("Icon Types", () => {
    it("should render with close icon", () => {
      // Test rendering with close icon
      render(<Controls icon="close" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should render with menu icon", () => {
      // Test rendering with menu icon
      render(<Controls icon="menu" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should render with search icon", () => {
      // Test rendering with search icon
      render(<Controls icon="search" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should render with chevron-down icon", () => {
      // Test rendering with chevron-down icon
      render(<Controls icon="chevron-down" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should render with chevron-up icon", () => {
      // Test rendering with chevron-up icon
      render(<Controls icon="chevron-up" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should render with chevron-left icon", () => {
      // Test rendering with chevron-left icon
      render(<Controls icon="chevron-left" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should render with chevron-right icon", () => {
      // Test rendering with chevron-right icon
      render(<Controls icon="chevron-right" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });
  });

  // Test button functionality
  describe("Button Functionality", () => {
    it("should be clickable and trigger onClick handler", () => {
      // Test that the button can be clicked and triggers the onClick handler
      const handleClick = vi.fn();
      render(<Controls icon="close" onClick={handleClick} />);

      const button = screen.getByRole("button");
      fireEvent.click(button);

      expect(handleClick).toHaveBeenCalledTimes(1);
    });

    it("should be focusable", () => {
      // Test that the button can receive focus
      render(<Controls icon="menu" />);

      const button = screen.getByRole("button");
      button.focus();

      expect(button).toHaveFocus();
    });

    it("should be keyboard accessible", async () => {
      // Test that the button responds to keyboard events
      const user = userEvent.setup();
      const handleClick = vi.fn();
      render(<Controls icon="search" onClick={handleClick} />);

      const button = screen.getByRole("button");
      await user.click(button);

      expect(handleClick).toHaveBeenCalledTimes(1);
    });

    it("should support Enter key press", async () => {
      // Test that Enter key triggers the onClick handler
      const user = userEvent.setup();
      const handleClick = vi.fn();
      render(<Controls icon="close" onClick={handleClick} />);

      const button = screen.getByRole("button");
      button.focus();
      await user.keyboard("{Enter}");

      expect(handleClick).toHaveBeenCalledTimes(1);
    });

    it("should support Space key press", async () => {
      // Test that Space key triggers the onClick handler
      const user = userEvent.setup();
      const handleClick = vi.fn();
      render(<Controls icon="menu" onClick={handleClick} />);

      const button = screen.getByRole("button");
      button.focus();
      await user.keyboard(" ");

      expect(handleClick).toHaveBeenCalledTimes(1);
    });
  });

  // Test disabled state
  describe("Disabled State", () => {
    it("should be disabled when isDisabled prop is true", () => {
      // Test that the button is disabled when isDisabled prop is true
      render(<Controls icon="close" isDisabled />);

      const button = screen.getByRole("button");
      expect(button).toBeDisabled();
    });

    it("should not be disabled when isDisabled prop is false", () => {
      // Test that the button is not disabled when isDisabled prop is false
      render(<Controls icon="menu" isDisabled={false} />);

      const button = screen.getByRole("button");
      expect(button).not.toBeDisabled();
    });

    it("should not trigger onClick when disabled", () => {
      // Test that onClick is not triggered when button is disabled
      const handleClick = vi.fn();
      render(<Controls icon="search" isDisabled onClick={handleClick} />);

      const button = screen.getByRole("button");
      fireEvent.click(button);

      expect(handleClick).not.toHaveBeenCalled();
    });

    it("should have aria-disabled attribute when disabled", () => {
      // Test that disabled button has aria-disabled attribute
      render(<Controls icon="close" isDisabled />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("aria-disabled", "true");
    });

    it("should not have aria-disabled attribute when not disabled", () => {
      // Test that non-disabled button does not have aria-disabled attribute
      render(<Controls icon="menu" isDisabled={false} />);

      const button = screen.getByRole("button");
      expect(button).not.toHaveAttribute("aria-disabled");
    });
  });

  // Test ref functionality
  describe("Ref Functionality", () => {
    it("should support elemRef prop", () => {
      // Test that elemRef prop works correctly
      const elemRef = React.createRef();
      render(<Controls icon="close" elemRef={elemRef} />);

      const button = screen.getByRole("button");
      expect(elemRef.current).toBe(button);
    });

    it("should support forwardRef", () => {
      // Test that forwardRef works correctly
      const ref = React.createRef();
      render(<Controls icon="menu" ref={ref} />);

      const button = screen.getByRole("button");
      expect(ref.current).toBe(button);
    });

    it("should prioritize elemRef over forwardRef", () => {
      // Test that elemRef takes priority over forwardRef
      const elemRef = React.createRef();
      const forwardRef = React.createRef();
      render(<Controls icon="search" elemRef={elemRef} ref={forwardRef} />);

      const button = screen.getByRole("button");
      expect(elemRef.current).toBe(button);
      expect(forwardRef.current).toBeNull();
    });
  });

  // Test accessibility
  describe("Accessibility", () => {
    it("should have proper ARIA attributes", () => {
      // Test that the button has proper ARIA attributes
      render(<Controls icon="close" aria-label="Close dialog" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("aria-label", "Close dialog");
    });

    it("should support aria-describedby", () => {
      // Test that the button supports aria-describedby attribute
      render(<Controls icon="menu" aria-describedby="menu-description" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("aria-describedby", "menu-description");
    });

    it("should support aria-expanded for toggle controls", () => {
      // Test that the button supports aria-expanded for toggle functionality
      render(<Controls icon="chevron-down" aria-expanded="false" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("aria-expanded", "false");
    });

    it("should support aria-pressed for toggle controls", () => {
      // Test that the button supports aria-pressed for toggle functionality
      render(<Controls icon="star" aria-pressed="false" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("aria-pressed", "false");
    });

    it("should support aria-controls for controlling other elements", () => {
      // Test that the button supports aria-controls for controlling other elements
      render(<Controls icon="menu" aria-controls="navigation-menu" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("aria-controls", "navigation-menu");
    });
  });

  // Test different button types
  describe("Button Types", () => {
    it("should support submit type", () => {
      // Test that the button can be rendered as submit type
      render(<Controls icon="check" type="submit" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("type", "submit");
    });

    it("should support reset type", () => {
      // Test that the button can be rendered as reset type
      render(<Controls icon="refresh" type="reset" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("type", "reset");
    });
  });

  // Test form integration
  describe("Form Integration", () => {
    it("should work within a form context", () => {
      // Test that the button works properly within a form
      const handleSubmit = vi.fn((e) => e.preventDefault());

      render(
        <form onSubmit={handleSubmit}>
          <Controls icon="check" type="submit" />
        </form>,
      );

      const button = screen.getByRole("button");
      fireEvent.submit(button.closest("form"));

      expect(handleSubmit).toHaveBeenCalledTimes(1);
    });

    it("should support form attribute", () => {
      // Test that the button supports form attribute
      render(<Controls icon="submit" form="my-form" />);

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("form", "my-form");
    });
  });

  // Test event handling
  describe("Event Handling", () => {
    it("should handle onFocus event", () => {
      // Test that the button handles onFocus event
      const handleFocus = vi.fn();
      render(<Controls icon="close" onFocus={handleFocus} />);

      const button = screen.getByRole("button");
      fireEvent.focus(button);

      expect(handleFocus).toHaveBeenCalledTimes(1);
    });

    it("should handle onBlur event", () => {
      // Test that the button handles onBlur event
      const handleBlur = vi.fn();
      render(<Controls icon="menu" onBlur={handleBlur} />);

      const button = screen.getByRole("button");
      fireEvent.blur(button);

      expect(handleBlur).toHaveBeenCalledTimes(1);
    });

    it("should handle onMouseEnter event", () => {
      // Test that the button handles onMouseEnter event
      const handleMouseEnter = vi.fn();
      render(<Controls icon="search" onMouseEnter={handleMouseEnter} />);

      const button = screen.getByRole("button");
      fireEvent.mouseEnter(button);

      expect(handleMouseEnter).toHaveBeenCalledTimes(1);
    });

    it("should handle onMouseLeave event", () => {
      // Test that the button handles onMouseLeave event
      const handleMouseLeave = vi.fn();
      render(<Controls icon="close" onMouseLeave={handleMouseLeave} />);

      const button = screen.getByRole("button");
      fireEvent.mouseLeave(button);

      expect(handleMouseLeave).toHaveBeenCalledTimes(1);
    });

    it("should handle onKeyDown event", () => {
      // Test that the button handles onKeyDown event
      const handleKeyDown = vi.fn();
      render(<Controls icon="menu" onKeyDown={handleKeyDown} />);

      const button = screen.getByRole("button");
      fireEvent.keyDown(button, { key: "Tab" });

      expect(handleKeyDown).toHaveBeenCalledTimes(1);
    });
  });

  // Test edge cases
  describe("Edge Cases", () => {
    it("should handle empty icon name gracefully", () => {
      // Test that the component handles empty icon name gracefully
      render(<Controls icon="" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should handle very long icon names", () => {
      // Test that the component handles very long icon names
      const longIconName = "a".repeat(100);
      render(<Controls icon={longIconName} />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should handle special characters in icon names", () => {
      // Test that the component handles special characters in icon names
      render(<Controls icon="icon-with-special-chars-@#$%" />);

      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
    });

    it("should handle multiple className values", () => {
      // Test that the component handles multiple className values
      render(<Controls icon="close" className="class1 class2 class3" />);

      const button = screen.getByRole("button");
      expect(button).toHaveClass("controls");
      expect(button).toHaveClass("class1");
      expect(button).toHaveClass("class2");
      expect(button).toHaveClass("class3");
    });

    it("should handle all HTML button attributes", () => {
      // Test that the component handles all HTML button attributes
      render(
        <Controls
          icon="close"
          name="test-button"
          value="test-value"
          autoFocus
          data-testid="test-controls"
        />,
      );

      const button = screen.getByRole("button");
      expect(button).toHaveAttribute("name", "test-button");
      expect(button).toHaveAttribute("value", "test-value");
      expect(button).toHaveAttribute("data-testid", "test-controls");
    });
  });

  // Test component display name
  describe("Component Metadata", () => {
    it("should have correct display name", () => {
      // Test that the component has the correct display name
      expect(Controls.displayName).toBe("Controls");
    });
  });
});
