import {
  ANALYTICS_CORE_EVENTS,
  GENERAL_PARAMETERS,
} from "@applicaster/zapp-react-native-utils/analyticsUtils/events";
const logger = require("@applicaster/zapp-react-native-utils/analyticsUtils/logger");

const mocked_storage = {
  layoutId: "layout_5678",
  uuid: "uuid_1234",
};

const mocked_qb_communication = {
  buildVersion: "12345",
  bundleIdentifier: "com.applicaster",
  quickBrickVersion: "1.0.0",
  riversConfigurationId: "layout_1234",
  sdkVersion: "1.0.0",
  uuid: null,
  versionName: "1.0.0",
  platform: "lg_tv",
  quickBrickEvent: jest.fn(),
  initialProps: {},
  languageLocale: "en-US",
  countryLocale: "US",
  setAppLanguage: jest.fn(),
  countryCode: "US",
};

const mocked_general_parameters = {
  [GENERAL_PARAMETERS.BUILD_NUMBER_KEY]: mocked_qb_communication.buildVersion,
  [GENERAL_PARAMETERS.BUNDLE_ID_KEY]: mocked_qb_communication.bundleIdentifier,
  [GENERAL_PARAMETERS.QUICKBRICK_VERSION_KEY]:
    mocked_qb_communication.quickBrickVersion,
  [GENERAL_PARAMETERS.LAYOUT_ID_KEY]: mocked_storage.layoutId,
  [GENERAL_PARAMETERS.SDK_VERSION_KEY]: mocked_qb_communication.sdkVersion,
  [GENERAL_PARAMETERS.UUID_KEY]: mocked_storage.uuid,
  [GENERAL_PARAMETERS.VERSION_KEY]: mocked_qb_communication.versionName,
  [GENERAL_PARAMETERS.ZAPP_PLATFORM]: mocked_qb_communication.platform,
};

const withoutNamespace = (key: string) => key.replace("applicaster.v2_::_", "");
const withNamespace = (key: string) => `applicaster.v2_::_${key}`;

global.sessionStorage = {
  getItem: jest.fn((key) => mocked_storage[withoutNamespace(key)]),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn(),
  length: 1,
  key: jest.fn(),
};

global.localStorage = {
  getItem: jest.fn((key) => mocked_storage[withoutNamespace(key)]),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn(),
  length: 1,
  key: jest.fn(),
};

const mocked_getItemSession = sessionStorage.getItem as jest.Mock;
const mocked_getItemLocal = localStorage.getItem as jest.Mock;

const mocked_module: any = {
  QuickBrickCommunicationModule: mocked_qb_communication,
};

jest.mock(
  "@applicaster/zapp-react-dom-app/Polyfills/QuickBrickCommunicationModule",
  () => mocked_module
);

const {
  getFromStorage,
  prepareEventPayload,
  AnalyticsBridge,
} = require("../index");

describe("zapp-react-dom-app analytics polyfill", () => {
  beforeEach(() => {
    jest.resetModules();
  });

  describe("getFromStorage", () => {
    it("should retrieve data from storage", () => {
      const key = GENERAL_PARAMETERS.UUID_KEY;
      const value = getFromStorage(key);

      expect(value).toBe(mocked_storage[key]);
      expect(sessionStorage.getItem).toHaveBeenCalledWith(withNamespace(key));
      expect(localStorage.getItem).not.toHaveBeenCalled();
    });

    it("should retrieve from localStorage if not found in sessionStorage", () => {
      const key = GENERAL_PARAMETERS.UUID_KEY;
      mocked_getItemSession.mockReturnValueOnce(null);
      const value = getFromStorage(key);

      expect(value).toBe(mocked_storage[key]);
      expect(sessionStorage.getItem).toHaveBeenCalledWith(withNamespace(key));
      expect(localStorage.getItem).toHaveBeenCalledWith(withNamespace(key));
    });

    it("should return null if data is not found in storage", () => {
      mocked_getItemSession.mockReturnValueOnce(null);
      mocked_getItemLocal.mockReturnValueOnce(null);

      const key = "nonexistentKey";
      const value = getFromStorage(key);

      expect(value).toBeNull();
      expect(sessionStorage.getItem).toHaveBeenCalledWith(withNamespace(key));
      expect(localStorage.getItem).toHaveBeenCalledWith(withNamespace(key));
    });
  });

  describe("prepareEventPayload", () => {
    const log_error = jest.spyOn(logger, "log_error");
    const log_warning = jest.spyOn(logger, "log_warning");

    it("prepares the event payload correctly with the general parameters", () => {
      const payload = prepareEventPayload();

      expect(log_warning).not.toHaveBeenCalled();
      expect(log_error).not.toHaveBeenCalled();
      expect(payload).toEqual(mocked_general_parameters);
    });
  });

  describe("AnalyticsBridge", () => {
    let googleAnalytics, youbora;

    beforeEach(() => {
      googleAnalytics = {
        module: {
          sendEvent: jest.fn(),
          initialize: jest.fn(),
        },
        configuration: {},
      };

      youbora = {
        module: {
          sendEvent: jest.fn(),
          initialize: jest.fn(),
        },
        configuration: {},
      };
    });

    it("sets and initializes plugins", () => {
      const configs = {};
      const callbackAfterInit = jest.fn();

      AnalyticsBridge.setPlugins(
        [googleAnalytics, youbora],
        configs,
        callbackAfterInit
      );

      expect(googleAnalytics.module.initialize).toHaveBeenCalled();
      expect(youbora.module.initialize).toHaveBeenCalled();
      expect(callbackAfterInit).toHaveBeenCalled();
    });

    it("postEvent sends an event to each registered plugin", () => {
      const configs = {};
      const callbackAfterInit = jest.fn();
      const eventName = ANALYTICS_CORE_EVENTS.LAUNCH_APP;
      const payload = {};

      AnalyticsBridge.setPlugins(
        [googleAnalytics, youbora],
        configs,
        callbackAfterInit
      );

      AnalyticsBridge.postEvent(eventName, payload);

      expect(googleAnalytics.module.sendEvent).toHaveBeenCalledWith(
        eventName,
        expect.any(Object)
      );

      expect(youbora.module.sendEvent).toHaveBeenCalledWith(
        eventName,
        expect.any(Object)
      );
    });

    it("postEvent sends an event to each registered plugin with the required params", () => {
      const configs = {};
      const callbackAfterInit = jest.fn();
      const eventName = ANALYTICS_CORE_EVENTS.LAUNCH_APP;
      const payload = {};

      AnalyticsBridge.setPlugins(
        [googleAnalytics, youbora],
        configs,
        callbackAfterInit
      );

      AnalyticsBridge.postEvent(eventName, payload);

      expect(googleAnalytics.module.sendEvent).toHaveBeenCalledWith(
        eventName,
        expect.objectContaining(mocked_general_parameters)
      );

      expect(youbora.module.sendEvent).toHaveBeenCalledWith(
        eventName,
        expect.objectContaining(mocked_general_parameters)
      );
    });
  });
});
