import { act, renderHook } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { atom } from "./atom";
import { useAtom, useAtomState, useSelector, useSetAtom, useTransitionAtom } from "./hook";
import { selector } from "./selector";
// Helper to wrap hooks with provider if needed, but useAtomStore provides a default store.
// However, for isolation, we might want a fresh store per test.
// But the default context creates one store.
// Let's rely on the default store for now, or create a wrapper if we need isolation.
// Since tests run sequentially in the same process, we should be careful about state pollution.
// But `atom()` creates a new atom key (object ref), so state is keyed by atom object.
// As long as we create new atoms inside each test, we are safe.
describe("hooks", () => {
    it("useAtomState should return current state and update", () => {
        let countAtom = atom({
            initialState: 0,
            reducers: { inc: (s, n) => s + n },
        });
        let { result } = renderHook(() => useAtomState(countAtom));
        expect(result.current).toBe(0);
        // We need to update the atom to see change.
        // We can use useSetAtom or store directly.
        // Let's use useSetAtom in another hook or just access store via useAtomStore?
        // Or use useAtom which gives both.
    });
    it("useSetAtom should update state", () => {
        let countAtom = atom({
            initialState: 0,
            reducers: { inc: (s, n) => s + n },
        });
        let { result } = renderHook(() => {
            let state = useAtomState(countAtom);
            let actions = useSetAtom(countAtom);
            return { state, actions };
        });
        expect(result.current.state).toBe(0);
        act(() => {
            result.current.actions.inc(1);
        });
        expect(result.current.state).toBe(1);
    });
    it("useAtom should return tuple of [state, actions]", () => {
        let countAtom = atom({
            initialState: 10,
            reducers: { dec: (s, n) => s - n },
        });
        let { result } = renderHook(() => useAtom(countAtom));
        expect(result.current[0]).toBe(10);
        act(() => {
            result.current[1].dec(5);
        });
        expect(result.current[0]).toBe(5);
    });
    it("useSelector should return derived state", () => {
        let atomA = atom({ initialState: 1, reducers: { set: (s, n) => n } });
        let atomB = atom({ initialState: 2, reducers: { set: (s, n) => n } });
        let sumSelector = selector([atomA, atomB], (a, b) => a + b);
        let { result } = renderHook(() => {
            let value = useSelector(sumSelector);
            let setA = useSetAtom(atomA);
            return { value, setA };
        });
        expect(result.current.value).toBe(3);
        act(() => {
            result.current.setA.set(5);
        });
        expect(result.current.value).toBe(7); // 5 + 2
    });
    it("useTransitionAtom should return [state, actions, isPending]", () => {
        let countAtom = atom({
            initialState: 0,
            reducers: { inc: (s, n) => s + n },
        });
        let { result } = renderHook(() => useTransitionAtom(countAtom));
        expect(result.current[0]).toBe(0);
        expect(typeof result.current[2]).toBe("boolean"); // isPending
        act(() => {
            result.current[1].inc(1);
        });
        expect(result.current[0]).toBe(1);
    });
});
