import * as R from "ramda";

import {
  entryContext,
  river,
  riverDataSources,
  screenContext,
  screenData,
  searchContext,
} from "./fixtures";

jest.mock("@applicaster/zapp-react-native-redux/ZappPipes", () => ({
  loadPipesData: jest.fn((value) => Promise.resolve(value)),
}));

const {
  DATASOURCE_CHUNKS,
  loadDatasources,
  riverIsCurrentRoute,
  getDatasourceUrl,
  ignoreComponentsWithClearCacheFlag,
} = require("../utils");

const {
  loadPipesData,
} = require("@applicaster/zapp-react-native-redux/ZappPipes");

const dispatch = (value) => Promise.resolve(value);

describe("DATASOURCE_CHUNKS", () => {
  const DEFAULT_DATASOURCE_CHUNKS = 10;

  it("has the correct value", () => {
    expect(DATASOURCE_CHUNKS).toBe(DEFAULT_DATASOURCE_CHUNKS);
  });
});

describe("loadDataSource", () => {
  it("calls loadPipesData for each provided urls", async () => {
    const urls = [
      ["http://datasource1", "http://datasource2"],
      ["http://datasource3", "http://datasource4"],
    ];

    await loadDatasources(urls, river.id, dispatch);

    expect(loadPipesData).toHaveBeenCalledTimes(R.flatten(urls).length);
  });
});

describe("riverIsCurrentRoute", () => {
  const route = "/river/homeId/river/screenId";
  const riverId = "screenId";

  it("returns true if the riverId is the current active route", () => {
    expect(riverIsCurrentRoute(riverId, route)).toBe(true);
  });

  it("returns false otherwise", () => {
    expect(riverIsCurrentRoute("someId", route)).toBe(false);
  });

  it("returns false if riverId is undefined", () => {
    expect(riverIsCurrentRoute(undefined, route));
  });
});

describe("ignoreComponentsWithClearCacheFlag", () => {
  it("rejects the components which have the clear_cache_on_reload flag set to true", () => {
    expect(ignoreComponentsWithClearCacheFlag(river.ui_components).length).toBe(
      R.flatten(riverDataSources).length
    );
  });
});

describe("getDatasourceUrl", () => {
  const defaultArgs = (args = {}) =>
    R.mergeRight(
      { screenData, entryContext, screenContext, searchContext },
      args
    );

  it("is a curried function", () => {
    const fn = getDatasourceUrl(defaultArgs());
    expect(typeof fn).toBe("function");
  });

  it("returns the url", () => {
    const datasourceUrl = "http://api.com/path";

    const component = {
      data: { source: datasourceUrl },
    };

    expect(getDatasourceUrl(defaultArgs(), component)).toEqual(datasourceUrl);
  });

  it("returns the url with mapped params if defined", () => {
    const datasourceUrl = `http://api.com/path?id=${entryContext.id}&screen=${
      screenContext.id
    }&query=${encodeURIComponent(searchContext)}&ext=${
      entryContext.extensions.prop
    }`;

    const component = {
      data: {
        source:
          "http://api.com/path?id={{entryId}}&screen={{screenId}}&query={{searchQ}}&ext={{extensionProp}}",
        mapping: {
          entryId: {
            source: "entry",
            property: "id",
          },
          extensionProp: {
            source: "entry",
            property: "extensions.prop",
          },
          screenId: {
            source: "screen",
            property: "id",
          },
          searchQ: {
            source: "search",
            property: "query",
          },
        },
      },
    };

    expect(getDatasourceUrl(defaultArgs(), component)).toBe(datasourceUrl);
  });

  it("uses screenData from route provider if screenContext is undefined", () => {
    const datasourceUrl = `http://api.com/path?id=${entryContext.id}&screen=${
      screenData.id
    }&query=${encodeURIComponent(searchContext)}&ext=${
      entryContext.extensions.prop
    }`;

    const component = {
      data: {
        source:
          "http://api.com/path?id={{entryId}}&screen={{screenId}}&query={{searchQ}}&ext={{extensionProp}}",
        mapping: {
          entryId: {
            source: "entry",
            property: "id",
          },
          extensionProp: {
            source: "entry",
            property: "extensions.prop",
          },
          screenId: {
            source: "screen",
            property: "id",
          },
          searchQ: {
            source: "search",
            property: "query",
          },
        },
      },
    };

    expect(
      getDatasourceUrl(defaultArgs({ screenContext: undefined }), component)
    ).toBe(datasourceUrl);
  });
});
