import { renderHook } from "@testing-library/react-hooks";
import { allFeedsIsReady, useBatchLoading } from "../useBatchLoading";
import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
import { waitFor } from "@testing-library/react-native";

jest.mock("../../navigation");

jest.mock(
  "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext",
  () => ({
    ...jest.requireActual(
      "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext"
    ),
    useScreenContext: jest.fn().mockReturnValue({ screen: {}, entry: {} }),
  })
);

const wrapper = WrappedWithProviders;

describe("useBatchLoading", () => {
  const data = [
    { data: { source: "url1" }, component_type: "any" },
    { data: { source: "url2" }, component_type: "any" },
    { data: { source: "url3" }, component_type: "any" },
    { data: { source: "url4" }, component_type: "any" },
    { data: { source: "url5" }, component_type: "any" },
    { data: { source: "url6" }, component_type: "any" },
    // ... more items
  ];

  beforeAll(() => {
    jest.useFakeTimers();
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  it("loadPipesData start loading not started requests", async () => {
    const store = {
      zappPipes: {
        url1: {
          loading: true,
          error: false,
          data: null,
        },
        url2: {
          loading: false,
          error: false,
          data: null,
        },
        url3: {
          loading: false,
          error: false,
          data: null,
        },
      },
      test: "true",
    };

    const initialBatchSize = 3;
    const riverId = "123";

    renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
      wrapper,
      initialProps: { store },
    });

    const actions = (appStore.getStore() as any).getActions();

    await waitFor(() => {
      expect(actions).toHaveLength(2);
    });

    expect(actions[0]).toMatchObject({
      type: "ZAPP_PIPES_REQUEST_START",
      payload: { dataSourceUrl: "url2" },
    });

    expect(actions[1]).toMatchObject({
      type: "ZAPP_PIPES_REQUEST_START",
      payload: { dataSourceUrl: "url3" },
    });
  });

  it("loadPipesData start loading new feed when 1 feed is done loading and 1 is in loading state", () => {
    const store = {
      zappPipes: {
        url1: {
          loading: false,
          error: false,
          data: { someData: true },
        },
        url2: {
          loading: false,
          error: false,
          data: null,
        },
        url3: {
          loading: true,
          error: false,
          data: null,
        },
      },
      test: "true",
    };

    const initialBatchSize = 3;
    const riverId = "123";

    renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
      wrapper,
      initialProps: { store },
    });

    const actions = (appStore.getStore() as any).getActions();

    expect(actions).toHaveLength(1);

    expect(actions[0]).toMatchObject({
      type: "ZAPP_PIPES_REQUEST_START",
      payload: { dataSourceUrl: "url2" },
    });
  });

  it("loadPipesData has been called when no data cached", () => {
    const store = {
      zappPipes: {},
      test: "true",
    };

    const initialBatchSize = 3;
    const riverId = "123";

    renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
      wrapper,
      initialProps: { store },
    });

    const actions = (appStore.getStore() as any).getActions();

    expect(actions).toHaveLength(3);
  });

  it("initial batch ready when all initial items loaded", () => {
    const store = {
      zappPipes: {
        url1: {
          loading: false,
          error: false,
          data: {},
        },
        url2: {
          loading: false,
          error: false,
          data: {},
        },
        url3: {
          loading: false,
          error: false,
          data: {},
        },
      },
    };

    const initialBatchSize = 3;
    const riverId = "123";

    const { result } = renderHook(
      () => useBatchLoading(data, { initialBatchSize, riverId }),
      { wrapper, initialProps: { store } }
    );

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

  it("gallery-qb: loadPipesData should be called only once for first component in the gallery", () => {
    const store = {
      zappPipes: {},
      test: "true",
    };

    const initialBatchSize = 3;
    const riverId = "123";

    const data = [
      {
        component_type: "gallery-qb",
        ui_components: [{ data: { source: "url1" } }],
      },
      { data: { source: "url2" }, component_type: "any" },
      { data: { source: "url3" }, component_type: "any" },
      { data: { source: "url4" }, component_type: "any" },
      { data: { source: "url5" }, component_type: "any" },
      { data: { source: "url6" }, component_type: "any" },
      // ... more items
    ];

    renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
      wrapper,
      initialProps: { store },
    });

    const actions = (appStore.getStore() as any).getActions();

    expect(actions).toHaveLength(1);
  });

  it("gallery-qb: initial batch ready when all initial items loaded", () => {
    const store = {
      zappPipes: {
        url1: {
          loading: false,
          error: false,
          data: {},
        },
      },
    };

    const initialBatchSize = 3;
    const riverId = "123";

    const data = [
      {
        component_type: "gallery-qb",
        data: {},
        ui_components: [{ data: { source: "url1" } }] as any,
      },
      { data: { source: "url2" }, component_type: "any" },
      { data: { source: "url3" }, component_type: "any" },
    ];

    const { result } = renderHook(
      () => useBatchLoading(data, { initialBatchSize, riverId }),
      { wrapper, initialProps: { store } }
    );

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

describe("allFeedsIsReady", () => {
  it("should filter empty urls", () => {
    expect(
      allFeedsIsReady(
        {
          feed1: {
            url: "feed1",
            loading: false,
            error: undefined,
            data: {} as ZappPipesData["data"],
          },
        },
        ["feed1", null, undefined]
      )
    ).toBe(true);

    expect(
      allFeedsIsReady(
        {
          feed1: {
            url: "feed1",
            loading: false,
            error: undefined,
            data: {} as ZappPipesData["data"],
          },
        },
        ["feed1", "feed2", null, undefined]
      )
    ).toBe(false);

    expect(allFeedsIsReady({}, ["feed1", "feed2", null, undefined])).toBe(
      false
    );
  });
});
