import { renderHook } from "@testing-library/react";
import { useButton } from "./useButton";

const mockClickEvent = {} as React.MouseEvent<HTMLButtonElement>;

describe("useButton", () => {
  it("should return an object", () => {
    const { result } = renderHook(() => useButton({}));
    expect(result.current).toBeInstanceOf(Object);
  });

  it("should return an object with buttonProps", () => {
    const { result } = renderHook(() => useButton({}));
    expect(result.current).toHaveProperty("buttonProps");
  });

  describe("type", () => {
    it("should return an object with buttonProps with type property", () => {
      const { result } = renderHook(() => useButton({}));
      expect(result.current.buttonProps).toHaveProperty("type");
    });

    it("should return an object with buttonProps with type set to button when elementType is button", () => {
      const { result } = renderHook(() => useButton({ elementType: "button" }));
      expect(result.current.buttonProps).toHaveProperty("type", "button");
    });

    it("should return an object with buttonProps with type set to passed in type when elementType is button", () => {
      const { result } = renderHook(() => useButton({ type: "submit" }));
      expect(result.current.buttonProps).toHaveProperty("type", "submit");
    });

    it("should return an object without buttonProps with type property when elementType is not button", () => {
      const { result } = renderHook(() => useButton({ elementType: "a" }));
      expect(result.current.buttonProps).not.toHaveProperty("type");
    });
  });

  describe("isDisabled", () => {
    it("should return an object with buttonProps with disabled property set to undefined", () => {
      const { result } = renderHook(() => useButton({}));
      expect(result.current.buttonProps).toHaveProperty("disabled", undefined);
    });

    it("should return an object with buttonProps with disabled set to true when isDisabled is set to true", () => {
      const { result } = renderHook(() => useButton({ isDisabled: true }));
      expect(result.current.buttonProps).toHaveProperty("disabled", true);
    });

    it("should return an object with buttonProps with aria-disabled property set to undefined", () => {
      const { result } = renderHook(() => useButton({}));
      expect(result.current.buttonProps).toHaveProperty(
        "aria-disabled",
        undefined,
      );
    });

    it("should return an object with buttonProps with aria-disabled property set to true when isDisabled is set to true", () => {
      const { result } = renderHook(() => useButton({ isDisabled: true }));
      expect(result.current.buttonProps).toHaveProperty("aria-disabled", true);
    });
  });

  describe("href", () => {
    describe("when elementType is a", () => {
      it("should return an object with buttonProps with href property set to undefined", () => {
        const { result } = renderHook(() => useButton({}));
        expect(result.current.buttonProps).toHaveProperty("href", undefined);
      });

      it("should return an object with buttonProps with href property set to passed in href", () => {
        const { result } = renderHook(() =>
          useButton({ elementType: "a", href: "test" }),
        );
        expect(result.current.buttonProps).toHaveProperty("href", "test");
      });
    });

    describe("when elementType is not a", () => {
      it("should return an object with buttonProps with href property set to undefined", () => {
        const { result } = renderHook(() =>
          useButton({ elementType: "button" }),
        );
        expect(result.current.buttonProps).toHaveProperty("href", undefined);
      });
    });
  });

  describe("target", () => {
    describe("when elementType is a", () => {
      it("should return an object with buttonProps with target property set to undefined", () => {
        const { result } = renderHook(() => useButton({}));
        expect(result.current.buttonProps).toHaveProperty("target", undefined);
      });

      it("should return an object with buttonProps with target property set to passed in target", () => {
        const { result } = renderHook(() =>
          useButton({ elementType: "a", target: "test" }),
        );
        expect(result.current.buttonProps).toHaveProperty("target", "test");
      });
    });

    describe("when elementType is not a", () => {
      it("should return an object with buttonProps with target property set to undefined", () => {
        const { result } = renderHook(() =>
          useButton({ elementType: "button" }),
        );
        expect(result.current.buttonProps).toHaveProperty("target", undefined);
      });
    });
  });

  describe("rel", () => {
    describe("when elementType is a", () => {
      it("should return an object with buttonProps with rel property set to undefined", () => {
        const { result } = renderHook(() => useButton({}));
        expect(result.current.buttonProps).toHaveProperty("rel", undefined);
      });

      it("should return an object with buttonProps with rel property set to passed in rel", () => {
        const { result } = renderHook(() =>
          useButton({ elementType: "a", rel: "test" }),
        );
        expect(result.current.buttonProps).toHaveProperty("rel", "test");
      });
    });

    describe("when elementType is not a", () => {
      it("should return an object with buttonProps with rel property set to undefined", () => {
        const { result } = renderHook(() =>
          useButton({ elementType: "button" }),
        );
        expect(result.current.buttonProps).toHaveProperty("rel", undefined);
      });
    });
  });

  describe("events", () => {
    it("should return an object with buttonProps with onClick property", () => {
      const { result } = renderHook(() => useButton({}));
      expect(result.current.buttonProps).toHaveProperty("onClick");
    });

    describe("onClick", () => {
      it("should call onClick when buttonProps onClick is called", () => {
        const onClick = vi.fn();
        const { result } = renderHook(() => useButton({ onClick }));
        result.current.buttonProps.onClick(mockClickEvent);
        expect(onClick).toHaveBeenCalled();
      });

      it("should not call onClick when buttonProps onClick is called and isDisabled is true", () => {
        const onClick = vi.fn();
        const { result } = renderHook(() =>
          useButton({ onClick, isDisabled: true }),
        );
        result.current.buttonProps.onClick(mockClickEvent);
        expect(onClick).not.toHaveBeenCalled();
      });
    });

    describe("onPress", () => {
      it("should call onPress when buttonProps onClick is called", () => {
        const onPress = vi.fn();
        const { result } = renderHook(() => useButton({ onPress }));
        result.current.buttonProps.onClick(mockClickEvent);
        expect(onPress).toHaveBeenCalled();
      });

      it("should not call onPress when buttonProps onClick is called and isDisabled is true", () => {
        const onPress = vi.fn();
        const { result } = renderHook(() =>
          useButton({ onPress, isDisabled: true }),
        );
        result.current.buttonProps.onClick(mockClickEvent);
        expect(onPress).not.toHaveBeenCalled();
      });
    });
  });
});
