import { renderHook } from "@testing-library/react-hooks";
import { Dimensions, StatusBar } from "react-native";

const mockUsePickFromState = jest.fn();
const mockUseIsScreenActive = jest.fn();
const mockGetInitialDimensions = jest.fn();
const mockGetDeviceInfo = jest.fn();

jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
  ...(jest.requireActual("@applicaster/zapp-react-native-redux/hooks") as {}),
  usePickFromState: mockUsePickFromState,
}));

jest.mock("../../../navigation", () => ({
  useIsScreenActive: mockUseIsScreenActive,
}));

jest.mock("../helpers", () => ({
  getInitialDimensions: mockGetInitialDimensions,
}));

jest.mock("../../getDeviceInfo", () => ({
  getDeviceInfo: mockGetDeviceInfo,
}));

const { useDimensions } = require("../useDimensions");

describe("useDimensions", () => {
  const mockDimensions = { width: 100, height: 200, scale: 1, fontScale: 1 };
  const mockAppData = { someData: "test" };

  beforeEach(() => {
    jest.clearAllMocks();
    Dimensions.get = jest.fn().mockReturnValue(mockDimensions);

    Dimensions.addEventListener = jest.fn().mockReturnValue({
      remove: jest.fn(),
    });

    mockUsePickFromState.mockReturnValue({ appData: mockAppData });
    mockUseIsScreenActive.mockReturnValue(true);
    mockGetInitialDimensions.mockReturnValue(mockDimensions);
    mockGetDeviceInfo.mockReturnValue({ deviceInfo: "testDeviceInfo" });
  });

  it("returns correct initial dimensions", () => {
    const { result } = renderHook(() =>
      useDimensions("window", { fullDimensions: false })
    );

    expect(result.current).toEqual({
      ...mockDimensions,
      statusBarHeight: StatusBar.currentHeight,
    });

    expect(mockGetInitialDimensions).toHaveBeenCalledWith("window");
  });

  it("calls handler on mount", () => {
    renderHook(() => useDimensions("window", { fullDimensions: false }));

    expect(Dimensions.addEventListener).toHaveBeenCalledWith(
      "change",
      expect.any(Function)
    );
  });

  it("calls handler on isActive change", () => {
    const { rerender } = renderHook(() =>
      useDimensions("window", { fullDimensions: false })
    );

    mockUseIsScreenActive.mockReturnValue(false);
    rerender();

    expect(Dimensions.addEventListener).toHaveBeenCalledWith(
      "change",
      expect.any(Function)
    );
  });

  it("handles fullDimensions option", () => {
    const { result } = renderHook(() =>
      useDimensions("window", { fullDimensions: true })
    );

    expect(result.current).toEqual({
      ...mockDimensions,
      scale: 1,
      fontScale: 1,
      statusBarHeight: StatusBar.currentHeight,
    });
  });

  it("handles excludeStatusBar option", () => {
    const { result } = renderHook(() =>
      useDimensions("window", { excludeStatusBar: true })
    );

    expect(result.current.height).toBe(
      mockDimensions.height - StatusBar.currentHeight ?? 0
    );
  });

  it("handles rounded option", () => {
    const { result } = renderHook(() =>
      useDimensions("window", { rounded: true })
    );

    expect(result.current.width).toBe(Math.ceil(mockDimensions.width));
    expect(result.current.height).toBe(Math.ceil(mockDimensions.height));
  });

  it("handles deviceInfo option", () => {
    const { result } = renderHook(() =>
      useDimensions("window", { deviceInfo: true })
    );

    expect(result.current.deviceInfo).toMatchObject({
      deviceInfo: "testDeviceInfo",
    });
  });

  it("logs deprecation warning when fullDimensions is boolean", () => {
    const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation();
    renderHook(() => useDimensions("window", true));

    expect(consoleWarnSpy).toHaveBeenCalledWith(
      "Deprecation Warning\nSecond argument is now the options object. {fullDimensions: boolean, ...}"
    );

    consoleWarnSpy.mockRestore();
  });
});
