import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { jest } from "@jest/globals";
import Dropdown from "./Dropdown";

describe("Dropdown Component", () => {
  const mockDropDownData = [
    { Id: 1, Name: "Option 1" },
    { Id: 2, Name: "Option 2" },
    { Id: 3, Name: "Option 3" },
  ];

  const mockDropDownKeys = {
    key: "testKey",
    title: "Select Option",
  };

  const mockOnSelectChange = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  test("renders with dropdown data", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
      />
    );

    expect(screen.getByRole("combobox")).toBeInTheDocument();
  });

  test("selects first item by default when no value provided", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
      />
    );

    expect(screen.getByRole("combobox")).toHaveTextContent("Option 1");
  });

  test("renders dropdown with activityType key", () => {
    const activityTypeKeys = {
      key: "activityType",
      title: "Activity Type",
    };

    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={activityTypeKeys}
      />
    );

    // Component renders and can be interacted with
    expect(screen.getByRole("combobox")).toBeInTheDocument();
  });

  test("uses controlled value prop when provided", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
        value="Option 2"
      />
    );

    expect(screen.getByRole("combobox")).toHaveTextContent("Option 2");
  });

  test("calls onSelectChange when selection changes", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
        onSelectChange={mockOnSelectChange}
      />
    );

    const select = screen.getByRole("combobox");
    fireEvent.mouseDown(select);

    const option = screen.getByRole("option", { name: "Option 2" });
    fireEvent.click(option);

    expect(mockOnSelectChange).toHaveBeenCalledWith("Option 2", "testKey");
  });

  test("renders all menu items when dropdown is opened", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
      />
    );

    const select = screen.getByRole("combobox");
    fireEvent.mouseDown(select);

    expect(screen.getByRole("option", { name: "Option 1" })).toBeInTheDocument();
    expect(screen.getByRole("option", { name: "Option 2" })).toBeInTheDocument();
    expect(screen.getByRole("option", { name: "Option 3" })).toBeInTheDocument();
  });

  test("renders with empty dropdown data", () => {
    render(
      <Dropdown
        dropDownData={[]}
        dropDownKeys={mockDropDownKeys}
      />
    );

    expect(screen.getByRole("combobox")).toBeInTheDocument();
  });

  test("renders with undefined dropdown data using default props", () => {
    render(
      <Dropdown
        dropDownKeys={mockDropDownKeys}
      />
    );

    expect(screen.getByRole("combobox")).toBeInTheDocument();
  });

  test("displays empty when no selection and no data", () => {
    render(
      <Dropdown
        dropDownData={[]}
        dropDownKeys={mockDropDownKeys}
        value=""
      />
    );

    // Combobox renders even with empty data
    expect(screen.getByRole("combobox")).toBeInTheDocument();
  });

  test("updates selected value when different option clicked", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
        onSelectChange={mockOnSelectChange}
      />
    );

    const select = screen.getByRole("combobox");
    fireEvent.mouseDown(select);
    fireEvent.click(screen.getByRole("option", { name: "Option 3" }));

    expect(mockOnSelectChange).toHaveBeenCalledWith("Option 3", "testKey");
  });

  test("does not call onSelectChange when callback is not provided", () => {
    render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
      />
    );

    const select = screen.getByRole("combobox");
    fireEvent.mouseDown(select);
    fireEvent.click(screen.getByRole("option", { name: "Option 2" }));

    // No error should be thrown
    expect(screen.getByRole("combobox")).toHaveTextContent("Option 2");
  });

  test("handles dropDownData with string Id", () => {
    const stringIdData = [
      { Id: "a", Name: "Alpha" },
      { Id: "b", Name: "Beta" },
    ];

    render(
      <Dropdown
        dropDownData={stringIdData}
        dropDownKeys={mockDropDownKeys}
      />
    );

    const select = screen.getByRole("combobox");
    fireEvent.mouseDown(select);

    expect(screen.getByRole("option", { name: "Alpha" })).toBeInTheDocument();
    expect(screen.getByRole("option", { name: "Beta" })).toBeInTheDocument();
  });

  test("sets empty string when value prop changes and dropDownData is present", () => {
    const { rerender } = render(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
        value="Option 1"
      />
    );

    expect(screen.getByRole("combobox")).toHaveTextContent("Option 1");

    rerender(
      <Dropdown
        dropDownData={mockDropDownData}
        dropDownKeys={mockDropDownKeys}
        value="Option 2"
      />
    );

    expect(screen.getByRole("combobox")).toHaveTextContent("Option 2");
  });
});
