import * as React from "react";
import { renderHook } from "@testing-library/react-hooks";
import * as URLHandlersMap from "..";

import { Provider } from "react-redux";
import configureStore from "redux-mock-store";

const { log_warning } = require("../../../logger");

const mockStore = configureStore();

jest.mock("../../../logger", () => ({
  __esModule: true,
  log_warning: jest.fn(),
}));

const lambdaPlugin = {
  module: jest.fn() as ZappPlugin,
  name: "Lambda plugin",
  identifier: "someplugin",
  type: "general" as PluginType,
};

const pluginWithHandler = {
  name: "Plugin handling scheme",
  identifier: "plugin-with-handler",
  type: "general" as PluginType,
  module: {
    urlScheme: {
      host: "foo",
      handler: jest.fn(({ onFinish }) => {
        onFinish(() => {});
      }),
    },
  } as ZappPlugin,
};

const plugins: QuickBrickPlugin[] = [lambdaPlugin, pluginWithHandler];

const { useUrlSchemeHandler } = require("../useUrlSchemeHandler");

describe("useUrlSchemeHandler", () => {
  // beforeEach(() => {
  //   log_warning.mockClear();
  // });

  const store = mockStore({ test: "test", plugins });

  const wrapper: React.FC<any> = ({ children }) => (
    <Provider store={store}>{children}</Provider>
  );

  it("calls correct urlScheme handler with query params", () => {
    const presentSpy = jest.fn();
    const onFinish = jest.fn();
    const url = "test://present?foo=bar";

    URLHandlersMap.schemeHandlerHooks.present = presentSpy;

    renderHook(
      () =>
        useUrlSchemeHandler({
          url,
          onFinish,
        }),
      { wrapper }
    );

    expect(presentSpy).toBeCalledWith({ query: { foo: "bar" }, url, onFinish });
  });

  it("not throws an error and calls onFinish if correct url scheme handler can not be found", () => {
    const url = "test://nonExistingHost?foo=bar";

    const onFinish = jest.fn((cb) => {
      cb();
    });

    renderHook(
      () =>
        useUrlSchemeHandler({
          url,
          onFinish,
        }),
      { wrapper }
    );

    expect(onFinish).toBeCalled();

    expect(log_warning).toHaveBeenCalledWith(
      `unable to resolve ${url}: Non of the installed plugins knows how to handle this urlScheme ${url}`
    );
  });

  it("calls onFinish when the handler does", () => {
    const url = "test://present?foo=bar";
    const onFinish = jest.fn();

    const presentSpy = jest.fn(() => {
      onFinish();
    });

    URLHandlersMap.schemeHandlerHooks.present = presentSpy;

    renderHook(
      () =>
        useUrlSchemeHandler({
          url,
          onFinish,
        }),
      { wrapper }
    );

    expect(onFinish).toBeCalled();
  });

  it("calls onFinish if handler returns an error", () => {
    const url = "test://present?foo=bar";

    const onFinish = jest.fn((cb) => {
      cb();
    });

    const presentSpy = jest.fn(() => {
      throw new Error("error");
    });

    URLHandlersMap.schemeHandlerHooks.present = presentSpy;

    renderHook(
      () =>
        useUrlSchemeHandler({
          url,
          onFinish,
        }),
      { wrapper }
    );

    expect(onFinish).toBeCalled();

    expect(log_warning).toHaveBeenCalledWith(`unable to resolve ${url}: error`);
  });

  it("finds the plugin for the host", () => {
    const url = "scheme://foo?whatever=bar";

    const onFinish = jest.fn((cb) => {
      cb();
    });

    renderHook(
      () => {
        useUrlSchemeHandler({ url, onFinish });
      },
      { wrapper }
    );

    expect(pluginWithHandler.module.urlScheme.handler).toBeCalledWith({
      url,
      onFinish,
      query: { whatever: "bar" },
    });

    expect(onFinish).toBeCalled();
  });
});
