/* eslint-disable max-len */
import * as R from "ramda";
import {
  ANALYTICS_CORE_EVENTS,
  GENERAL_PARAMETERS,
} from "@applicaster/zapp-react-native-utils/analyticsUtils/events";

import type { GeneralParameters } from "@applicaster/zapp-react-native-utils/analyticsUtils/events";
import {
  log_debug,
  log_error,
  log_warning,
} from "@applicaster/zapp-react-native-utils/analyticsUtils/logger";
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
import { QuickBrickCommunicationModule } from "../QuickBrickCommunicationModule";

export const getFromStorage = (key) => {
  const DEFAULT_NAMESPACE = "applicaster.v2";
  const NAMESPACE_SEPARATOR = "_::_";

  const namespace = `${DEFAULT_NAMESPACE}${NAMESPACE_SEPARATOR}`;
  const storageKey = `${namespace}${key}`;

  // the browser storage API is synchronous vs our storage API which is async
  return sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey);
};

export const prepareEventPayload = (): GeneralParameters | {} => {
  if (!QuickBrickCommunicationModule) {
    log_warning(
      "Failed to prepare event payload, 'QuickBrickCommunicationModule' is missing"
    );

    return {};
  }

  const {
    buildVersion,
    bundleIdentifier,
    quickBrickVersion,
    riversConfigurationId,
    sdkVersion,
    versionName,
    platform,
  } = QuickBrickCommunicationModule as Partial<QBCommunicationModule>;

  const buildtimeData = {
    build_number: buildVersion,
    bundle_id: bundleIdentifier,
    quickbrick_version: quickBrickVersion,
    layout_id: riversConfigurationId,
    sdk_version: sdkVersion,
    version: versionName,
    zapp_platform: platform,
  };

  const runtimeData = {
    uuid: getFromStorage("uuid"),
    layout_id: getFromStorage("layoutId"),
  };

  const requiredKeys = Object.keys(GENERAL_PARAMETERS);

  const eventPayload: GeneralParameters | {} = {};
  const missingKeys: string[] = [];

  try {
    requiredKeys.forEach((key) => {
      const keyName = GENERAL_PARAMETERS[key];
      const value = runtimeData[keyName] || buildtimeData[keyName];

      if (value) {
        eventPayload[keyName] = value;
      } else {
        missingKeys.push(keyName);
      }
    });
  } catch (e) {
    log_error("There was an error preparing analytics event payload", e);
  }

  if (missingKeys.length > 0) {
    log_warning("Analytics event payload is missing required keys", {
      missingKeys,
    });
  }

  return eventPayload;
};

function isInvalidAnalyticsData(eventName, payload = null) {
  const isInvalid = isEmptyOrNil(eventName);

  if (isInvalid) {
    log_debug(
      "AnalyticsBridge received an event invalid data. Event will not be emitted",
      { eventName, payload }
    );

    return true;
  }

  return false;
}

export const AnalyticsBridge = (function () {
  let registeredAnalyticPlugins: {
    module: {
      sendEvent: Function;
      initialize?: Function;
      getPlayerConfiguration?: Function;
    };
    configuration?: any;
  }[] = [];

  const startTime = {};
  const endTime = {};

  return {
    postEvent: function (eventName, payload) {
      if (isInvalidAnalyticsData(eventName, payload)) {
        return;
      }

      const updatedPayload = {
        ...prepareEventPayload(),
        ...payload,
      };

      registeredAnalyticPlugins.forEach((plugin) => {
        plugin.module.sendEvent(eventName, updatedPayload);
      });
    },
    endTimedEvent: function (eventName, payload) {
      endTime[eventName] = new Date();
      const toSeconds = (ms) => ms / 1000;

      const duration = startTime[eventName]
        ? toSeconds(endTime[eventName] - startTime[eventName])
        : "N/A";

      if (isInvalidAnalyticsData(eventName, payload)) {
        return;
      }

      const updatedPayload = {
        duration,
        ...prepareEventPayload(),
        ...payload,
      };

      registeredAnalyticPlugins.forEach((plugin) => {
        plugin.module.sendEvent(
          ANALYTICS_CORE_EVENTS.TIME_ON_SCREEN,
          updatedPayload
        );
      });
    },
    postTimedEvent: function (eventName) {
      startTime[eventName] = new Date();
    },
    setPlugins: function (plugins, configs, callbackAfterInitilaize) {
      registeredAnalyticPlugins = plugins;

      plugins.forEach((plugin) => {
        return R.path(["module", "initialize"], plugin)
          ? plugin.module.initialize(plugin.configuration || {})
          : null;
      });

      callbackAfterInitilaize();
    },
  };
})();
