import { networkStatusReady } from "../networkStatusReady";
import * as reactUtils from "@applicaster/zapp-react-native-utils/reactUtils";
import NetInfo from "@react-native-community/netinfo";

const platformSelectSpy = jest.spyOn(reactUtils, "platformSelect");
let _listener;

const unsubscribe = jest.fn(() => {
  _listener = null;
});

const addEventListener = jest.fn((listener) => {
  _listener = jest.fn(listener);

  return unsubscribe;
});

const NetInfoSpy = jest
  .spyOn(NetInfo, "addEventListener")
  .mockImplementation(addEventListener);

const notReadyNetInfoState = {
  isConnected: null,
  isInternetReachable: null,
  details: null,
};

const readyNetInfoState = {
  isConnected: true,
  isInternetReachable: true,
  details: {},
};

function clearMocks() {
  platformSelectSpy.mockClear();
  _listener?.mockClear?.();
  NetInfoSpy.mockClear();
}

function resetMocks() {
  platformSelectSpy.mockReset();
  _listener?.mockReset?.();
  NetInfoSpy.mockReset();
}

// jest.mock("@react-native-community/netinfo", () => NetInfoMock);

describe("networkStatusReady", () => {
  beforeEach(clearMocks);

  describe("when running in test environment", () => {
    it("resolves to true right away", async () => {
      await expect(networkStatusReady()).resolves.toBe(undefined);
      expect(NetInfoSpy).not.toHaveBeenCalled();
    });
  });

  describe("when running on a web platform", () => {
    it("resolves to true right away", async () => {
      platformSelectSpy.mockImplementationOnce((specs) => specs.default);

      await expect(networkStatusReady("production")).resolves.toBe(undefined);
      expect(NetInfoSpy).not.toHaveBeenCalled();
    });
  });

  describe("when not in test environment and in mobile platforms", () => {
    it("resolves when netInfoState is ready", (done) => {
      expect.assertions(5);
      let promiseResolved = false;

      networkStatusReady("production").then((resolvedValue) => {
        promiseResolved = true;

        expect(promiseResolved).toBe(true);
        expect(resolvedValue).toEqual(readyNetInfoState);
        expect(unsubscribe).toHaveBeenCalled();
        done();
      });

      _listener?.(notReadyNetInfoState);

      setTimeout(() => {
        expect(promiseResolved).toBe(false);
        expect(NetInfoSpy).toHaveBeenCalled();

        setTimeout(() => {
          _listener?.(readyNetInfoState);
        }, 5);
      }, 5);
    });
  });

  afterAll(resetMocks);
});
