import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Radio, RadioGroup } from ".";
import type { HTMLElementEvent } from "../../types/events";
import { Icon } from "../Icon";
import { truck } from "@simplybusiness/icons";

const RADIO_GROUP_CLASS = "mobius-radio-group";
const LABEL_CLASS = "mobius-label";
const RADIO_WRAPPER_CLASS = "mobius-radio__wrapper";
const RADIO_INPUT_CLASS = "mobius-radio__input";

const mockElementDimensions = (
  element: Element,
  dimensions: {
    scrollHeight?: number;
    clientHeight?: number;
    scrollWidth?: number;
    clientWidth?: number;
  },
) => {
  Object.entries(dimensions).forEach(([key, value]) => {
    Object.defineProperty(element, key, {
      configurable: true,
      value,
    });
  });
};

const mockOverflow = (element: Element) => {
  mockElementDimensions(element, {
    scrollHeight: 100,
    clientHeight: 50,
    scrollWidth: 100,
    clientWidth: 100,
  });
};

const mockNoOverflow = (element: Element) => {
  mockElementDimensions(element, {
    scrollHeight: 50,
    clientHeight: 50,
    scrollWidth: 100,
    clientWidth: 100,
  });
};

describe("Radio", () => {
  it("should render without error", () => {
    const view = render(
      <RadioGroup label="Color">
        <Radio value="red">Red</Radio>
        <Radio value="blue">Blue</Radio>
      </RadioGroup>,
    );

    expect(view).toBeTruthy();
  });

  describe("given a name prop", () => {
    it("should render child radios with the provided name prop", () => {
      const name = "unique-name";

      render(
        <RadioGroup label="Color" name={name}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const inputs = screen.getAllByRole("radio");

      inputs.forEach(input => expect(input).toHaveAttribute("name", name));
    });
  });

  describe("default value in `<RadioGroup>`", () => {
    describe("set to an existing option", () => {
      it("should render only one `<Radio>` as checked with defaultValue prop", () => {
        const uncheckedText = "red";
        const checkedText = "blue";

        render(
          <RadioGroup label="Color" defaultValue={checkedText}>
            <Radio value={uncheckedText}>Red</Radio>
            <Radio value={checkedText}>Blue</Radio>
          </RadioGroup>,
        );

        const uncheckedRadio = screen.getByDisplayValue(uncheckedText);
        const checkedRadio = screen.getByDisplayValue(checkedText);

        expect(uncheckedRadio).not.toBeChecked();
        expect(checkedRadio).toBeChecked();
      });

      it("should render only one `<Radio>` as checked with value prop", () => {
        const uncheckedText = "red";
        const checkedText = "blue";

        render(
          <RadioGroup label="Color" value={checkedText}>
            <Radio value={uncheckedText}>Red</Radio>
            <Radio value={checkedText}>Blue</Radio>
          </RadioGroup>,
        );

        const uncheckedRadio = screen.getByDisplayValue(uncheckedText);
        const checkedRadio = screen.getByDisplayValue(checkedText);

        expect(uncheckedRadio).not.toBeChecked();
        expect(checkedRadio).toBeChecked();
      });

      it("should respect the value prop after re-render", () => {
        const uncheckedText = "red";
        const checkedText = "blue";

        const { rerender } = render(
          <RadioGroup label="Color" value={uncheckedText}>
            <Radio value={uncheckedText}>Red</Radio>
            <Radio value={checkedText}>Blue</Radio>
          </RadioGroup>,
        );

        const uncheckedRadio = screen.getByDisplayValue(uncheckedText);
        const checkedRadio = screen.getByDisplayValue(checkedText);

        expect(uncheckedRadio).toBeChecked();
        expect(checkedRadio).not.toBeChecked();
        // Re-render
        rerender(
          <RadioGroup label="Color" value={checkedText}>
            <Radio value={uncheckedText}>Red</Radio>
            <Radio value={checkedText}>Blue</Radio>
          </RadioGroup>,
        );

        expect(uncheckedRadio).not.toBeChecked();
        expect(checkedRadio).toBeChecked();
      });
    });

    describe("set to a non-existing option", () => {
      it("should render only one `<Radio>` as checked", () => {
        const nonExistingText = "orange";

        render(
          <RadioGroup label="Color" defaultValue={nonExistingText}>
            <Radio value="red">Red</Radio>
            <Radio value="blue">Blue</Radio>
          </RadioGroup>,
        );

        const inputs = screen.getAllByRole("radio");

        inputs.forEach(input => expect(input).not.toBeChecked());
      });
    });

    describe("set to an empty string", () => {
      it("should render only one `<Radio>` as checked", () => {
        const emptyString = "";

        render(
          <RadioGroup label="Color" defaultValue={emptyString}>
            <Radio value="red">Red</Radio>
            <Radio value="blue">Blue</Radio>
          </RadioGroup>,
        );

        const inputs = screen.getAllByRole("radio");

        inputs.forEach(input => expect(input).not.toBeChecked());
      });
    });
  });

  describe("default checked in `<Radio>`", () => {
    it("should render unchecked by default", () => {
      render(<Radio value="red">Red</Radio>);

      const input = screen.getByRole("radio");

      expect(input).not.toBeChecked();
    });

    describe("given defaultChecked prop is set", () => {
      it("should render checked", () => {
        render(
          <Radio value="red" defaultChecked>
            Red
          </Radio>,
        );

        const input = screen.getByRole("radio");

        expect(input).toBeChecked();
      });
    });

    describe("given defaultChecked prop is set to false", () => {
      it("should render checked", () => {
        render(
          <Radio value="red" defaultChecked={false}>
            Red
          </Radio>,
        );

        const input = screen.getByRole("radio");

        expect(input).not.toBeChecked();
      });
    });
  });

  it("should set aria-describedby for all radios when errorMessage is set", () => {
    render(
      <RadioGroup label="Radio Group" errorMessage="Error message">
        <Radio label="Radio 1" value="value1" />
        <Radio label="Radio 2" value="value2" />
        <Radio label="Radio 3" value="value3" />
      </RadioGroup>,
    );

    const radios = screen.getAllByRole("radio");

    radios.forEach(radio => {
      expect(radio).toHaveAccessibleDescription("Error message");
    });
  });

  it("should render with role attribute", () => {
    const { container } = render(
      <RadioGroup label="Color">
        <Radio value="red">Red</Radio>
        <Radio value="blue">Blue</Radio>
      </RadioGroup>,
    );

    expect(container.firstChild).toHaveAttribute("role", "radiogroup");
  });

  it("should call onChange with the selected value when clicked", async () => {
    const callback = vi.fn();
    const handleChange = (e: HTMLElementEvent<HTMLInputElement>) => {
      callback(e.target.value);
    };
    const redOptionText = "Red";
    const blueOptionText = "Blue";

    const { getByLabelText } = render(
      <RadioGroup label="Color" onChange={handleChange}>
        <Radio value="red">{redOptionText}</Radio>
        <Radio value="blue">{blueOptionText}</Radio>
      </RadioGroup>,
    );

    const redOption = screen.getByLabelText(redOptionText);
    const blueOption = screen.getByLabelText(blueOptionText);

    await userEvent.click(getByLabelText(redOptionText));

    expect(callback).toHaveBeenCalledWith("red");
    expect(redOption).toBeChecked();

    await userEvent.click(getByLabelText(blueOptionText));

    expect(callback).toHaveBeenCalledWith("blue");
    expect(blueOption).toBeChecked();
  });

  it("should be selectable via keyboard", async () => {
    const callback = vi.fn();
    const redOptionText = "Red";
    const blueOptionText = "Blue";
    const redOptionValue = redOptionText.toLowerCase();
    const blueOptionValue = blueOptionText.toLowerCase();

    render(
      <RadioGroup label="Color" onChange={callback}>
        <Radio value={redOptionValue}>Red</Radio>
        <Radio value={blueOptionValue}>Blue</Radio>
      </RadioGroup>,
    );

    const redOption = screen.getByLabelText(redOptionText);
    const blueOption = screen.getByLabelText(blueOptionText);

    await userEvent.tab();

    await userEvent.keyboard("[Space]");

    expect(callback).toHaveBeenCalled();
    expect(redOption).toBeChecked();
    expect(blueOption).not.toBeChecked();

    await userEvent.keyboard("[ArrowDown]");

    expect(callback).toHaveBeenCalled();
    expect(blueOption).toBeChecked();
    expect(redOption).not.toBeChecked();
  });

  describe("when child component is null", () => {
    it("renders without errors", () => {
      expect(() =>
        render(
          <RadioGroup label="Color">
            <Radio value="red">Red</Radio>
            {null}
          </RadioGroup>,
        ),
      ).not.toThrow();
    });
  });

  describe("isRequired", () => {
    it("should set aria-required to true", () => {
      render(
        <RadioGroup label="Color" isRequired>
          <Radio value="red">Red</Radio>
          {null}
        </RadioGroup>,
      );
      const container = screen.getByLabelText("Color");
      const input = screen.getByRole("radio");

      expect(container).toBeRequired();
      expect(input).toBeRequired();
    });

    it("should have className of --is-required when true", () => {
      render(
        <RadioGroup label="Color" isRequired>
          <Radio value="red">Red</Radio>
          {null}
        </RadioGroup>,
      );

      expect(screen.getByLabelText("Color")).toHaveClass("--is-required");
    });

    it("should have className of --is-optional when false", () => {
      render(
        <RadioGroup label="Color" isRequired={false}>
          <Radio value="red">Red</Radio>
          {null}
        </RadioGroup>,
      );

      expect(screen.getByLabelText("Color")).toHaveClass("--is-optional");
    });

    it("should have neither --is-required nor --is-optional when unset", () => {
      render(
        <RadioGroup label="Color">
          <Radio value="red">Red</Radio>
          {null}
        </RadioGroup>,
      );

      expect(screen.getByLabelText("Color")).not.toHaveClass("--is-required");
      expect(screen.getByLabelText("Color")).not.toHaveClass("--is-optional");
    });
  });

  describe("uses correct class names for atoms", () => {
    it("uses Mobius class", () => {
      const { container } = render(
        <RadioGroup label="Color">
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveClass(RADIO_GROUP_CLASS);
    });

    it("uses base Mobius class", () => {
      const labelText = "Color";

      const { container } = render(
        <RadioGroup label={labelText}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const containerElement = container.firstChild;
      const label = screen.getByText(labelText);
      const inputs = screen.queryAllByRole("radio");

      expect(containerElement).toHaveClass(RADIO_GROUP_CLASS);
      expect(label).toHaveClass(LABEL_CLASS);
      expect(label.nextElementSibling).toHaveClass(RADIO_WRAPPER_CLASS);
      inputs.forEach(input => expect(input).toHaveClass(RADIO_INPUT_CLASS));
    });

    it("includes custom class names", () => {
      const customContainerClass = "custom-container-class";
      const customRedClass = "custom-red-class";
      const customBlueClass = "custom-blue-class";
      const redText = "Red";
      const blueText = "Blue";

      const { container } = render(
        <RadioGroup label="Color" className={customContainerClass}>
          <Radio value="red" className={customRedClass}>
            {redText}
          </Radio>
          <Radio value="blue" className={customBlueClass}>
            {blueText}
          </Radio>
        </RadioGroup>,
      );

      const redOption = screen.getByLabelText(redText);
      const blueOption = screen.getByLabelText(blueText);

      expect(container.firstChild).toHaveClass(customContainerClass);
      expect(redOption.parentElement).toHaveClass(customRedClass);
      expect(blueOption.parentElement).toHaveClass(customBlueClass);
    });

    it("sets classes for interaction states", async () => {
      const callback = vi.fn();
      render(
        <RadioGroup label="Color" onChange={callback}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const redOption = screen.getByLabelText("Red");
      const blueOption = screen.getByLabelText("Blue");

      await userEvent.tab();
      await userEvent.keyboard("[Space]");

      expect(redOption).toHaveClass("--is-selected");

      await userEvent.keyboard("[ArrowDown]");

      expect(redOption).not.toHaveClass("--is-selected");
      expect(blueOption).toHaveClass("--is-selected");
    });

    it("sets classes for disabled state", () => {
      const { container } = render(
        <RadioGroup label="Color" isDisabled>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );
      const redOption = screen.getByLabelText("Red");
      const blueOption = screen.getByLabelText("Blue");

      expect(container.firstChild).toHaveClass("--is-disabled");
      expect(redOption).toHaveClass("--is-disabled");
      expect(blueOption).toHaveClass("--is-disabled");
    });

    it("sets classes for valid state", () => {
      const { container } = render(
        <RadioGroup label="Color" isInvalid={false}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveClass("--is-valid");
    });

    it("sets classes for invalid state", () => {
      const { container } = render(
        <RadioGroup label="Color" isInvalid>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveClass("--is-invalid");
    });
  });

  describe("when disabled state is set on RadioGroup", () => {
    it("renders aria-disabled attribute on container; disabled attributes on inputs", () => {
      const { container } = render(
        <RadioGroup label="Color" isDisabled>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const inputs = screen.queryAllByRole("radio");

      expect(container.firstChild).toHaveAttribute("aria-disabled", "true");
      inputs.forEach(input => expect(input).toHaveAttribute("disabled"));
    });
  });

  describe("aria-errormessage", () => {
    describe("when radio is accompanied by an error message", () => {
      it("renders aria-erromessage with an id that matches error message id", () => {
        const { container, getByTestId } = render(
          <RadioGroup label="Color" errorMessage="This is an error">
            <Radio value="red">Red</Radio>
            <Radio value="blue">Blue</Radio>
          </RadioGroup>,
        );

        const errorMessageId = getByTestId("ErrorMessage");

        expect(container.firstChild).toHaveAttribute(
          "aria-errormessage",
          errorMessageId.id,
        );
      });
    });

    describe("when radio is not accompanied by an error message", () => {
      it("does not render aria-erromessage", () => {
        const { container } = render(
          <RadioGroup label="Color">
            <Radio value="red">Red</Radio>
            <Radio value="blue">Blue</Radio>
          </RadioGroup>,
        );

        expect(container.firstChild).not.toHaveAttribute("aria-errormessage");
      });
    });
  });

  describe("given an invalid state", () => {
    it("renders aria-invalid attribute on container", () => {
      const { container } = render(
        <RadioGroup label="Color" isInvalid>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute("aria-invalid", "true");
    });
  });

  describe("given an aria-label", () => {
    it("renders the label on the container", () => {
      const ariaLabel = "My label";

      const { container } = render(
        <RadioGroup label="Color" aria-label={ariaLabel}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute("aria-label", ariaLabel);
    });
  });

  describe("given an aria-labelledby", () => {
    it("renders the id on the container", () => {
      const ariaLabelledby = "id123";

      const { container } = render(
        <RadioGroup label="Color" aria-labelledby={ariaLabelledby}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute(
        "aria-labelledby",
        ariaLabelledby,
      );
    });
  });

  describe("given an orientation value", () => {
    it("renders horizontal orientation value on the container", () => {
      const ariaOrientation = "horizontal";

      const { container } = render(
        <RadioGroup
          label="Color"
          orientation={ariaOrientation}
          aria-orientation={ariaOrientation}
        >
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute(
        "aria-orientation",
        ariaOrientation,
      );
    });

    it("renders vertical orientation value on the container", () => {
      const ariaOrientation = "vertical";

      const { container } = render(
        <RadioGroup
          label="Color"
          orientation={ariaOrientation}
          aria-orientation={ariaOrientation}
        >
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute(
        "aria-orientation",
        ariaOrientation,
      );
    });
  });

  describe("given the component is read only", () => {
    it("renders aria-readonly attribute on the container", () => {
      const { container } = render(
        <RadioGroup label="Color" isReadOnly>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute("aria-readonly", "true");
    });
  });

  describe("given an additional prop", () => {
    it("renders additional container prop on the container", () => {
      const additionalProp = "additional-prop";

      const { container } = render(
        <RadioGroup label="Color" data-testid={additionalProp}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      expect(container.firstChild).toHaveAttribute(
        "data-testid",
        additionalProp,
      );
    });

    it("renders additional child prop on the child", () => {
      const additionalProp = "additional-prop";

      render(
        <RadioGroup label="Color">
          <Radio value="red" data-testid={additionalProp}>
            Red
          </Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const [firstInput] = screen.getAllByRole("radio");

      expect(firstInput).toHaveAttribute("data-testid", additionalProp);
    });
  });
});

describe("when first child is an Icon", () => {
  it("should add --has-icon-first class to the label", () => {
    render(
      <RadioGroup label="Vehicle">
        <Radio value="truck">
          <Icon icon={truck} size="sm" />
          Truck
        </Radio>
      </RadioGroup>,
    );

    const radioInput = screen.getByDisplayValue("truck");

    expect(radioInput.parentElement).toHaveClass("--has-icon-first");
  });
});

describe("when first child is not an Icon", () => {
  it("should not add --has-icon-first class to the label", () => {
    render(
      <RadioGroup label="Vehicle">
        <Radio value="truck">
          Truck
          <Icon icon={truck} size="sm" />
        </Radio>
      </RadioGroup>,
    );

    const radioInput = screen.getByDisplayValue("truck");

    expect(radioInput.parentElement).not.toHaveClass("--has-icon-first");
  });

  it("should not add --has-icon-first class to the label when there is no Icon", () => {
    render(
      <RadioGroup label="Vehicle">
        <Radio value="truck">Truck</Radio>
      </RadioGroup>,
    );

    const radioInput = screen.getByDisplayValue("truck");

    expect(radioInput.parentElement).not.toHaveClass("--has-icon-first");
  });

  it("should not add --has-icon-first class to the label when Icon is passed in via label prop rather than child", () => {
    render(
      <RadioGroup label="Vehicle">
        <Radio
          value="truck"
          label={
            <div>
              <Icon icon={truck} />
              <span>Truck</span>
            </div>
          }
        />
      </RadioGroup>,
    );

    const radioInput = screen.getByDisplayValue("truck");

    expect(radioInput.parentElement).not.toHaveClass("--has-icon-first");
  });

  it("should not add --has-icon-first class when children are mixed with Icon not first", () => {
    render(
      <RadioGroup label="Vehicle">
        <Radio value="truck">
          <span>Heavy</span>
          <Icon icon={truck} size="sm" />
          Truck
        </Radio>
      </RadioGroup>,
    );

    const radioInput = screen.getByDisplayValue("truck");

    expect(radioInput.parentElement).not.toHaveClass("--has-icon-first");
  });

  it("should not add --has-icon-first class when children are empty", () => {
    render(
      <RadioGroup label="Vehicle">
        <Radio value="truck">{null}</Radio>
      </RadioGroup>,
    );

    const radioInput = screen.getByDisplayValue("truck");

    expect(radioInput.parentElement).not.toHaveClass("--has-icon-first");
  });
});

describe("controlled vs uncontrolled RadioGroup onChange behavior", () => {
  it("should call onChange exactly once when a radio button is clicked in controlled mode", async () => {
    const onChange = vi.fn();
    const redValue = "red";
    const blueValue = "blue";

    render(
      <RadioGroup label="Color" value={redValue} onChange={onChange}>
        <Radio value={redValue}>Red</Radio>
        <Radio value={blueValue}>Blue</Radio>
      </RadioGroup>,
    );

    const blueOption = screen.getByLabelText("Blue");

    // Clear any previous calls
    onChange.mockClear();

    // Click the blue option
    await userEvent.click(blueOption);

    // Verify onChange was called exactly once
    expect(onChange).toHaveBeenCalledTimes(1);
    expect(onChange).toHaveBeenCalledWith(
      expect.objectContaining({
        target: expect.objectContaining({
          value: blueValue,
        }),
      }),
    );
  });

  it("should call onChange exactly once when a radio button is clicked in uncontrolled mode", async () => {
    const onChange = vi.fn();
    const redValue = "red";
    const blueValue = "blue";

    render(
      <RadioGroup label="Color" defaultValue={redValue} onChange={onChange}>
        <Radio value={redValue}>Red</Radio>
        <Radio value={blueValue}>Blue</Radio>
      </RadioGroup>,
    );

    const blueOption = screen.getByLabelText("Blue");

    // Clear any previous calls
    onChange.mockClear();

    // Click the blue option
    await userEvent.click(blueOption);

    // Verify onChange was called exactly once
    expect(onChange).toHaveBeenCalledTimes(1);
    expect(onChange).toHaveBeenCalledWith(
      expect.objectContaining({
        target: expect.objectContaining({
          value: blueValue,
        }),
      }),
    );
  });
});

describe.skip("focus behavior", () => {
  it("should focus the selected radio option when value changes", () => {
    const redValue = "red";
    const blueValue = "blue";

    const { rerender } = render(
      <RadioGroup label="Color" value={redValue}>
        <Radio value={redValue}>Red</Radio>
        <Radio value={blueValue}>Blue</Radio>
      </RadioGroup>,
    );

    // Check initial focus on red option
    const redOption = screen.getByDisplayValue(redValue);
    expect(redOption).toHaveFocus();

    // Change selected value to blue
    rerender(
      <RadioGroup label="Color" value={blueValue}>
        <Radio value={redValue}>Red</Radio>
        <Radio value={blueValue}>Blue</Radio>
      </RadioGroup>,
    );

    // Verify focus moved to blue option
    const blueOption = screen.getByDisplayValue(blueValue);
    expect(blueOption).toHaveFocus();
  });

  it("should focus the selected radio option on initial render", () => {
    const selectedValue = "blue";

    render(
      <RadioGroup label="Color" value={selectedValue}>
        <Radio value="red">Red</Radio>
        <Radio value={selectedValue}>Blue</Radio>
      </RadioGroup>,
    );

    // Verify the selected radio has focus
    const selectedOption = screen.getByDisplayValue(selectedValue);
    expect(selectedOption).toHaveFocus();
  });
});

describe("overflow detection", () => {
  describe("Radio onOverflow callback", () => {
    it("should call onOverflow with vertical overflow when content height exceeds container", () => {
      const onOverflow = vi.fn();

      const { container, rerender } = render(
        <Radio value="test" label="Test Label" onOverflow={onOverflow} />,
      );

      const contentElement = container.querySelector(
        ".mobius-radio__content",
      ) as HTMLElement;

      // Mock overflow: scrollHeight > clientHeight
      mockOverflow(contentElement);

      // Trigger useLayoutEffect by re-rendering
      rerender(
        <Radio
          value="test"
          label="Test Label Updated"
          onOverflow={onOverflow}
        />,
      );

      expect(onOverflow).toHaveBeenCalledWith({
        vertical: true,
        horizontal: false,
      });
    });

    it("should call onOverflow with horizontal overflow when content width exceeds container", () => {
      const onOverflow = vi.fn();

      const { container, rerender } = render(
        <Radio value="test" label="Test Label" onOverflow={onOverflow} />,
      );

      const contentElement = container.querySelector(
        ".mobius-radio__content",
      ) as HTMLElement;

      // Mock overflow: scrollWidth > clientWidth
      mockElementDimensions(contentElement, {
        scrollHeight: 50,
        clientHeight: 50,
        scrollWidth: 200,
        clientWidth: 100,
      });

      // Trigger useLayoutEffect by re-rendering
      rerender(
        <Radio
          value="test"
          label="Test Label Updated"
          onOverflow={onOverflow}
        />,
      );

      expect(onOverflow).toHaveBeenCalledWith({
        vertical: false,
        horizontal: true,
      });
    });

    it("should call onOverflow with both overflow types when content exceeds in both dimensions", () => {
      const onOverflow = vi.fn();

      const { container, rerender } = render(
        <Radio value="test" label="Test Label" onOverflow={onOverflow} />,
      );

      const contentElement = container.querySelector(
        ".mobius-radio__content",
      ) as HTMLElement;

      // Mock overflow in both dimensions
      mockElementDimensions(contentElement, {
        scrollHeight: 100,
        clientHeight: 50,
        scrollWidth: 200,
        clientWidth: 100,
      });

      // Trigger useLayoutEffect by re-rendering
      rerender(
        <Radio
          value="test"
          label="Test Label Updated"
          onOverflow={onOverflow}
        />,
      );

      expect(onOverflow).toHaveBeenCalledWith({
        vertical: true,
        horizontal: true,
      });
    });

    it("should not call onOverflow when content fits within container and state has not changed", () => {
      const onOverflow = vi.fn();

      const { container, rerender } = render(
        <Radio value="test" label="Test Label" onOverflow={onOverflow} />,
      );

      const contentElement = container.querySelector(
        ".mobius-radio__content",
      ) as HTMLElement;

      mockNoOverflow(contentElement);

      // Trigger useLayoutEffect by re-rendering
      rerender(
        <Radio
          value="test"
          label="Test Label Updated"
          onOverflow={onOverflow}
        />,
      );

      // Should not be called because overflow state didn't change (was false, still false)
      expect(onOverflow).not.toHaveBeenCalled();
    });

    it("should not call onOverflow when callback is not provided", () => {
      const { container } = render(<Radio value="test" label="Test Label" />);

      const contentElement = container.querySelector(
        ".mobius-radio__content",
      ) as HTMLElement;

      // Mock overflow
      Object.defineProperty(contentElement, "scrollHeight", {
        configurable: true,
        value: 100,
      });
      Object.defineProperty(contentElement, "clientHeight", {
        configurable: true,
        value: 50,
      });

      // Should not throw
      expect(() => {
        render(<Radio value="test" label="Test Label Updated" />);
      }).not.toThrow();
    });
  });

  describe("RadioGroup autoStack", () => {
    it("should change orientation from horizontal to vertical when overflow detected and autoStack is true", () => {
      const { container, rerender } = render(
        <RadioGroup label="Color" orientation="horizontal" autoStack>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      // Initially should be horizontal
      expect(container.firstChild).toHaveClass("--is-horizontal");
      expect(container.firstChild).toHaveAttribute(
        "aria-orientation",
        "horizontal",
      );

      const radioContents = container.querySelectorAll(
        ".mobius-radio__content",
      );

      mockOverflow(radioContents[0]);
      mockNoOverflow(radioContents[1]);

      // Trigger overflow detection by re-rendering
      rerender(
        <RadioGroup label="Color Updated" orientation="horizontal" autoStack>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      // Should now be vertical
      expect(container.firstChild).toHaveClass("--is-vertical");
      expect(container.firstChild).toHaveAttribute(
        "aria-orientation",
        "vertical",
      );
    });

    it("should not change orientation when autoStack is false", () => {
      const { container, rerender } = render(
        <RadioGroup label="Color" orientation="horizontal" autoStack={false}>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const radioContents = container.querySelectorAll(
        ".mobius-radio__content",
      );

      mockOverflow(radioContents[0]);

      // Trigger overflow detection
      rerender(
        <RadioGroup
          label="Color Updated"
          orientation="horizontal"
          autoStack={false}
        >
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      // Should still be horizontal
      expect(container.firstChild).toHaveClass("--is-horizontal");
      expect(container.firstChild).toHaveAttribute(
        "aria-orientation",
        "horizontal",
      );
    });

    it("should not change orientation when initial orientation is vertical", () => {
      const { container, rerender } = render(
        <RadioGroup label="Color" orientation="vertical" autoStack>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      const radioContents = container.querySelectorAll(
        ".mobius-radio__content",
      );

      mockOverflow(radioContents[0]);

      // Trigger overflow detection
      rerender(
        <RadioGroup label="Color Updated" orientation="vertical" autoStack>
          <Radio value="red">Red</Radio>
          <Radio value="blue">Blue</Radio>
        </RadioGroup>,
      );

      // Should remain vertical (no change)
      expect(container.firstChild).toHaveClass("--is-vertical");
      expect(container.firstChild).toHaveAttribute(
        "aria-orientation",
        "vertical",
      );
    });
  });
});
