import React from "react";
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
import { renderHook } from "@testing-library/react-hooks";
import { isNavBarVisible, useRoute } from "../";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";

const plugins = [];

const rivers = {
  "river-player": {
    id: "river-player",
    plugin_type: "player",
  },
  "river-general": {
    id: "river-general",
    plugin_type: "general",
  },
};

const contentTypes = {
  video: { screen_id: "river-player" },
  link: { screen_id: "river-general" },
};

const screen = {
  id: "123",
};

const entry = { id: "abc" };

const homeStack = {
  route: "/home",
  state: {
    screen,
    entry,
  },
};

const videoItem = {
  id: "video-1",
  type: { value: "video" },
};

const mockGetStackForPathname = jest.fn().mockReturnValue(homeStack);

const mainStackNavigator = {
  getStackForPathname: mockGetStackForPathname,
  getModalState: () => {},
  videoModalState: {},
  canGoBack: jest.fn(),
};

const _createWrapper = (Wrapper, props) => {
  return function CreatedWrapper({ children }: any) {
    return <Wrapper {...props}>{children}</Wrapper>;
  };
};

const videoModalNavigator = {
  ...mainStackNavigator,
  videoModalState: { item: videoItem },
};

const hookModalNavigator = {
  ...mainStackNavigator,
};

const hookModalContextState = {
  isRunningInBackground: false,
  setIsRunningInBackground: jest.fn(),
  setIsPresentingFullScreen: jest.fn(),
  isPresentationFullScreen: true,
  isHooksExecutionInProgress: true,
  setIsHooksExecutionInProgress: jest.fn(),
  state: {
    path: "/home",
    screenData: { payload: { id: "hookExecutedInModal" } },
  },
  setState: jest.fn(),
  resetState: jest.fn(),
};

const hooksModalPathname = `${ROUTE_TYPES.HOOKS_MODAL}/${hookModalContextState.state.screenData.payload.id}`;
const videoModalPathname = `${ROUTE_TYPES.VIDEO_MODAL}/${videoModalNavigator.videoModalState.item.id}`;
const mockStore = configureMockStore();

const store = mockStore({
  plugins,
  rivers,
  contentTypes,
});

const mainStackWrapper = ({
  children,
  navigator = {},
  pathname = homeStack.route,
}) => (
  <Provider store={store}>
    <ScreenDataContext.Provider value={homeStack.state}>
      <NavigationContext.Provider
        value={{ ...mainStackNavigator, ...navigator, currentRoute: pathname }}
      >
        <PathnameContext.Provider value={pathname}>
          {children}
        </PathnameContext.Provider>
      </NavigationContext.Provider>
    </ScreenDataContext.Provider>
  </Provider>
);

const videoModalWrapper = ({ children }) => (
  <Provider store={store}>
    <NavigationContext.Provider value={videoModalNavigator}>
      <PathnameContext.Provider value={videoModalPathname}>
        {children}
      </PathnameContext.Provider>
    </NavigationContext.Provider>
  </Provider>
);

const hookModalWrapper = ({ children }) => (
  <Provider store={store}>
    <ZappHookModalContext.ReactContext.Provider value={hookModalContextState}>
      <NavigationContext.Provider value={hookModalNavigator}>
        <PathnameContext.Provider value={hooksModalPathname}>
          {children}
        </PathnameContext.Provider>
      </NavigationContext.Provider>
    </ZappHookModalContext.ReactContext.Provider>
  </Provider>
);

jest.mock("../../../modalState", () => ({
  useModalStore: jest.fn(),
}));

describe("navigation", () => {
  describe("useRoute", () => {
    describe("Main stack components", () => {
      it("should return a correct pathname", () => {
        const { result } = renderHook(() => useRoute(), {
          wrapper: mainStackWrapper,
        });

        expect(result.current.pathname).toEqual(homeStack.route);
      });

      it("should return correct screenData information", () => {
        const { result } = renderHook(() => useRoute(), {
          wrapper: mainStackWrapper,
        });

        expect(result.current.screenData.id).toEqual(entry.id);

        expect(result.current.screenData.targetScreen.id).toEqual(screen.id);
      });
    });

    describe("Hook modal components", () => {
      it("should return a correct pathname", () => {
        const { result } = renderHook(() => useRoute(), {
          wrapper: hookModalWrapper,
        });

        expect(result.current.pathname).toEqual(hooksModalPathname);
      });

      it("should return correct screenData information", () => {
        const { result } = renderHook(() => useRoute(), {
          wrapper: hookModalWrapper,
        });

        expect(result.current.screenData.id).toEqual(
          hookModalContextState.state.screenData.payload.id
        );
      });
    });

    describe("Video modal components", () => {
      it("should return a correct pathname", () => {
        const { result } = renderHook(() => useRoute(), {
          wrapper: videoModalWrapper,
        });

        expect(result.current.pathname).toEqual(videoModalPathname);
      });

      it("should return correct screenData information", () => {
        const { result } = renderHook(() => useRoute(), {
          wrapper: videoModalWrapper,
        });

        expect(result.current.screenData.id).toEqual(
          videoModalNavigator.videoModalState.item.id
        );

        expect(result.current.screenData.targetScreen.id).toEqual(
          rivers["river-player"].id
        );
      });
    });
  });

  describe("isNavBarVisible", () => {
    it("returns false when the route is a player route", () => {
      const navBarVisible = isNavBarVisible(
        "/playable/some_vod_item",
        {} as ZappRiver,
        false,
        false
      );

      expect(navBarVisible).toBe(false);
    });

    it("returns false when the next screen is the QB search screen", () => {
      const navBarVisible = isNavBarVisible(
        "/river/A1234",
        {
          type: "qb_search_screen",
        } as any,
        false,
        false
      );

      expect(navBarVisible).toBe(false);
    });

    describe("when screen is a hook", () => {
      it("returns true if the `showNavBar` flag is set to true", () => {
        const navBarVisible = isNavBarVisible(
          "",
          {
            hookPlugin: {
              module: {
                showNavBar: true,
              },
            },
          } as any,
          false,
          false
        );

        expect(navBarVisible).toBe(true);
      });

      it("returns true if presentFullScreen flag is set to false", () => {
        const navBarVisible = isNavBarVisible(
          "",
          {
            hookPlugin: {
              module: {
                presentFullScreen: false,
              },
            },
          } as any,
          false,
          false
        );

        expect(navBarVisible).toBe(true);
      });

      it("returns false if presentFullScreen flag is set to true", () => {
        const navBarVisible = isNavBarVisible(
          "",
          {
            hookPlugin: {
              module: {
                presentFullScreen: true,
              },
            },
          } as any,
          false,
          false
        );

        expect(navBarVisible).toBe(false);
      });
    });

    it("returns false if the screen's general settings allow screen presentation", () => {
      const navBarVisible = isNavBarVisible(
        "",
        {
          general: {
            allow_screen_plugin_presentation: true,
          },
        } as any,
        false,
        false
      );

      expect(navBarVisible).toBe(false);
    });

    it("returns false if the screen's general settings hide app nav bar", () => {
      const navBarVisible = isNavBarVisible(
        "",
        {
          general: {
            hide_app_nav_bar: true,
          },
        } as any,
        false,
        false
      );

      expect(navBarVisible).toBe(false);
    });

    it("returns false if it's secondary nav bar and hide_secondary_level_menu is true", () => {
      const navBarVisible = isNavBarVisible(
        "",
        {
          navigations: [
            {
              styles: {
                hide_secondary_level_menu: true,
              },
            },
          ],
        } as any,
        false,
        true
      );

      expect(navBarVisible).toBe(false);
    });

    it("returns true if it's secondary nav bar and hide_secondary_level_menu is false", () => {
      const navBarVisible = isNavBarVisible(
        "",
        {
          navigations: [
            {
              styles: {
                hide_secondary_level_menu: false,
              },
            },
          ],
        } as any,
        true,
        false
      );

      expect(navBarVisible).toBe(true);
    });

    it("returns true if it's first level menu and hide_secondary_level_menu is true", () => {
      const navBarVisible = isNavBarVisible(
        "",
        {
          navigations: [
            {
              styles: {
                hide_secondary_level_menu: true,
              },
            },
          ],
        } as any,
        true,
        false
      );

      expect(navBarVisible).toBe(true);
    });

    it("returns true otherwise", () => {
      const navBarVisible = isNavBarVisible(
        "",
        { navigations: [] } as any,
        true,
        true
      );

      expect(navBarVisible).toBe(true);
    });
  });
});
