import { act, renderHook } from "@testing-library/react";
import "@testing-library/jest-dom";

import { useModal, useModals } from "@ax/hooks";

describe("useModal hook", () => {
	beforeEach(() => {
		document.body.classList.remove("modal-open");
	});

	afterEach(() => {
		document.body.classList.remove("modal-open");
	});

	it("should initialize with false when no initialState provided", () => {
		const { result } = renderHook(() => useModal());
		expect(result.current.isOpen).toBe(false);
	});

	it("should initialize with provided initialState", () => {
		const { result } = renderHook(() => useModal(true));
		expect(result.current.isOpen).toBe(true);
	});

	it("should toggle modal state when toggleModal is called", () => {
		const { result } = renderHook(() => useModal(false));
		expect(result.current.isOpen).toBe(false);

		act(() => {
			result.current.toggleModal();
		});

		expect(result.current.isOpen).toBe(true);

		act(() => {
			result.current.toggleModal();
		});

		expect(result.current.isOpen).toBe(false);
	});

	it("should add modal-open class to body when modal opens and bodyBlock is true", () => {
		const { result } = renderHook(() => useModal(false, true));
		expect(document.body.classList.contains("modal-open")).toBe(false);

		act(() => {
			result.current.toggleModal();
		});

		expect(document.body.classList.contains("modal-open")).toBe(true);
	});

	it("should not add modal-open class to body when bodyBlock is false", () => {
		const { result } = renderHook(() => useModal(false, false));

		act(() => {
			result.current.toggleModal();
		});

		expect(document.body.classList.contains("modal-open")).toBe(false);
	});

	it("should check if modal-open class already exists before adding", () => {
		document.body.classList.add("modal-open");

		const { result } = renderHook(() => useModal(false, true));

		act(() => {
			result.current.toggleModal();
		});

		// Class should still be present
		expect(document.body.classList.contains("modal-open")).toBe(true);

		// Count of modal-open should be 1
		const classList = [...document.body.classList];
		const count = classList.filter((c) => c === "modal-open").length;
		expect(count).toBe(1);
	});
});

describe("useModals hook", () => {
	beforeEach(() => {
		document.body.classList.remove("modal-open");
	});

	afterEach(() => {
		document.body.classList.remove("modal-open");
	});

	it("should initialize all modals as closed", () => {
		const { result } = renderHook(() => useModals(["modal1", "modal2", "modal3"]));

		expect(result.current.isOpen("modal1")).toBe(false);
		expect(result.current.isOpen("modal2")).toBe(false);
		expect(result.current.isOpen("modal3")).toBe(false);
	});

	it("should open a modal with openModal", () => {
		const { result } = renderHook(() => useModals(["modal1", "modal2"]));

		act(() => {
			result.current.openModal("modal1");
		});

		expect(result.current.isOpen("modal1")).toBe(true);
		expect(result.current.isOpen("modal2")).toBe(false);
	});

	it("should close a modal with closeModal", () => {
		const { result } = renderHook(() => useModals(["modal1"]));

		act(() => {
			result.current.openModal("modal1");
		});

		expect(result.current.isOpen("modal1")).toBe(true);

		act(() => {
			result.current.closeModal("modal1");
		});

		expect(result.current.isOpen("modal1")).toBe(false);
	});

	it("should toggle a modal with toggleModal", () => {
		const { result } = renderHook(() => useModals(["modal1"]));

		expect(result.current.isOpen("modal1")).toBe(false);

		act(() => {
			result.current.toggleModal("modal1");
		});

		expect(result.current.isOpen("modal1")).toBe(true);

		act(() => {
			result.current.toggleModal("modal1");
		});

		expect(result.current.isOpen("modal1")).toBe(false);
	});

	it("should handle multiple modals independently", () => {
		const { result } = renderHook(() => useModals(["modal1", "modal2", "modal3"]));

		act(() => {
			result.current.openModal("modal1");
		});

		expect(result.current.isOpen("modal1")).toBe(true);
		expect(result.current.isOpen("modal2")).toBe(false);
		expect(result.current.isOpen("modal3")).toBe(false);

		act(() => {
			result.current.openModal("modal2");
		});

		expect(result.current.isOpen("modal1")).toBe(true);
		expect(result.current.isOpen("modal2")).toBe(true);
		expect(result.current.isOpen("modal3")).toBe(false);
	});

	it("should add modal-open class when a modal is opened", () => {
		const { result } = renderHook(() => useModals(["modal1"], true));

		expect(document.body.classList.contains("modal-open")).toBe(false);

		act(() => {
			result.current.openModal("modal1");
		});

		expect(document.body.classList.contains("modal-open")).toBe(true);
	});

	it("should remove modal-open class when all modals are closed", () => {
		const { result } = renderHook(() => useModals(["modal1", "modal2"], true));

		act(() => {
			result.current.openModal("modal1");
			result.current.openModal("modal2");
		});

		expect(document.body.classList.contains("modal-open")).toBe(true);

		act(() => {
			result.current.closeModal("modal1");
		});

		expect(document.body.classList.contains("modal-open")).toBe(true);

		act(() => {
			result.current.closeModal("modal2");
		});

		expect(document.body.classList.contains("modal-open")).toBe(false);
	});

	it("should close multiple modals individually", () => {
		const { result } = renderHook(() => useModals(["modal1", "modal2", "modal3"]));

		act(() => {
			result.current.openModal("modal1");
			result.current.openModal("modal2");
			result.current.openModal("modal3");
		});

		expect(result.current.isOpen("modal1")).toBe(true);
		expect(result.current.isOpen("modal2")).toBe(true);
		expect(result.current.isOpen("modal3")).toBe(true);

		act(() => {
			result.current.closeModal("modal1");
			result.current.closeModal("modal2");
			result.current.closeModal("modal3");
		});

		expect(result.current.isOpen("modal1")).toBe(false);
		expect(result.current.isOpen("modal2")).toBe(false);
		expect(result.current.isOpen("modal3")).toBe(false);
	});

	it("should not add modal-open class if bodyBlock is false", () => {
		const { result } = renderHook(() => useModals(["modal1"], false));

		act(() => {
			result.current.openModal("modal1");
		});

		expect(document.body.classList.contains("modal-open")).toBe(false);
	});

	it("should not duplicate modal-open class when multiple modals are open", () => {
		const { result } = renderHook(() => useModals(["modal1", "modal2"], true));

		act(() => {
			result.current.openModal("modal1");
		});

		const classList1 = [...document.body.classList];
		const count1 = classList1.filter((c) => c === "modal-open").length;

		act(() => {
			result.current.openModal("modal2");
		});

		const classList2 = [...document.body.classList];
		const count2 = classList2.filter((c) => c === "modal-open").length;

		expect(count1).toBe(1);
		expect(count2).toBe(1);
	});

	it("should handle isOpen callback correctly", () => {
		const { result } = renderHook(() => useModals(["modal1"]));

		act(() => {
			result.current.openModal("modal1");
		});

		const isOpenResult = result.current.isOpen("modal1");
		expect(isOpenResult).toBe(true);
	});
});

describe("useModal and useModals working together", () => {
	beforeEach(() => {
		document.body.classList.remove("modal-open");
	});

	afterEach(() => {
		document.body.classList.remove("modal-open");
	});

	it("should verify both hooks add modal-open class independently", () => {
		const { result: modalResult } = renderHook(() => useModal(false, true));
		const { result: modalsResult } = renderHook(() => useModals(["modal1"], true));

		// useModal should add class
		act(() => {
			modalResult.current.toggleModal();
		});
		expect(document.body.classList.contains("modal-open")).toBe(true);

		// useModals should keep class
		act(() => {
			modalsResult.current.openModal("modal1");
		});
		expect(document.body.classList.contains("modal-open")).toBe(true);

		// Closing useModal should keep class (useModals still open)
		act(() => {
			modalResult.current.toggleModal();
		});
		// Note: This depends on DOM check in useModal

		// Closing useModals should remove class
		act(() => {
			modalsResult.current.closeModal("modal1");
		});
		expect(document.body.classList.contains("modal-open")).toBe(false);
	});
});
