import {
  ECommerceCatalogType,
  ECommerceTypes,
  ItemAction,
  ItemObject,
  ItemType,
} from "./typings";

import CfCore from "../../core/CfCore";
import { verifyItemObject } from "./validators";
import { logIngestEvent } from "./logIngestEvent";
import {
  validateAndSaveBloodCatalog,
  validateAndSaveDrugCatalog,
  validateAndSaveFacilityCatalog,
  validateAndSaveGroceryCatalog,
  validateAndSaveMedicalEquipmentCatalog,
  validateAndSaveOxygenCatalog,
} from "./validators/EComCatalogValidator";

import {
  logCancelCheckoutEvent,
  logCheckoutEvent,
  logCartEvent,
  logDeliveryEvent,
  logItemEvent,
} from "./legacyLoggerFunctions";

export const logCatalogEvent = (
  subjectId: string,
  catalogType: ECommerceCatalogType,
  catalogModel: any
) => {
  if (!catalogModel) {
    return;
  }

  switch (catalogType) {
    case ECommerceCatalogType.Drug:
      validateAndSaveDrugCatalog(subjectId, catalogModel);
      break;
    case ECommerceCatalogType.Grocery:
      validateAndSaveGroceryCatalog(subjectId, catalogModel);
      break;
    case ECommerceCatalogType.Blood:
      validateAndSaveBloodCatalog(subjectId, catalogModel);
      break;
    case ECommerceCatalogType.Oxygen:
      validateAndSaveOxygenCatalog(subjectId, catalogModel);
      break;
    case ECommerceCatalogType.MedicalEquipment:
      validateAndSaveMedicalEquipmentCatalog(subjectId, catalogModel);
      break;
    case ECommerceCatalogType.Facility:
      validateAndSaveFacilityCatalog(subjectId, catalogModel);
      break;
  }
};

/**
 * Start tracking impressions automatically for the items whose parent
 * is the element defined by the class `containerClassname`. A impression
 * is a visualization of an item for specific amount of time (i.e.: 1s)
 *
 * In addition, the items to track must include some metadata by using
 * the internal dataset of HTML elements, as shown in the next example.
 *
 * ```html
 *   <div
 *      data-log-id="0"
 *      data-log-quantity="9"
 *      data-log-price="426"
 *      data-log-currency="EUR"
 *      data-log-stock-status="in_stock"
 *      data-log-promo-id="your-promo-id"
 *      class="item-card"
 *   >
 * ```
 *
 * @param {string} containerClassname Represents the CSS classname of the
 * container to monitorize
 *
 * @param {string} itemClassname Any item within the indicated container must
 * also include a common classname to let the SDK monitorize it
 *
 * @throws Will throw the error 'container-does-not-exist'
 *         when `containerClassname` does not correspond to
 *         any DOM element
 */
const startTrackingImpressions = (
  containerClassname: string,
  itemClassname: string, searchId?: string
) => {
  const impressionHandler = ({ dataset, appData }) => {
    const {
      logId: id,
      logCurrency: currency,
      logType: type,
      logPrice: price,
      logQuantity: quantity,
      logStockStatus: stock_status,
      logPromoId: promo_id,
      logFacilityId: facility_id,
      logDrugCatalogObject: drug_catalog_object,
    } = dataset;

    const itemDetail: ItemObject = {
      id,
      type: type || ItemType.Drug,
      currency: currency,
      price: parseInt(price),
      quantity: parseInt(quantity),
      stock_status: stock_status,
      promo_id: promo_id || "",
      facility_id: facility_id || "",
    };

    let catalogObj;
    let catalogData;

    if (drug_catalog_object) {
      try {
        catalogObj = JSON.parse(drug_catalog_object);
        if (type === ItemType.Drug) {
          catalogData = {
            market_id: catalogObj.market_id,
            name: catalogObj.name,
            description: catalogObj.description,
            supplier_id: catalogObj.supplier_id,
            supplier_name: catalogObj.supplier_name,
            producer: catalogObj.producer || "",
            packaging: catalogObj.packaging || "",
            active_ingredients: catalogObj.active_ingredients,
            drug_form: catalogObj.drug_form || "",
            drug_strength: catalogObj.drug_strength || "",
            atc_anatomical_group: catalogObj.atc_anatomical_group || "",
            otc_or_ethical: catalogObj.otc_or_ethical || "",
          };
        } else if (type === ItemType.Blood) {
          catalogData = {
            market_id: catalogObj.market_id,
            blood_component: catalogObj.blood_component,
            blood_group: catalogObj.blood_group,
            packaging: catalogObj.packaging,
            packaging_size: catalogObj.packaging_size,
            supplier_id: catalogObj.supplier_id || "",
            supplier_name: catalogObj.supplier_name || "",
          };
        } else if (type === ItemType.MedicalEquipment) {
          catalogData = {
            name: catalogObj.name,
            market_id: catalogObj.market_id,
            description: catalogObj.description || "",
            supplier_id: catalogObj.supplier_id,
            supplier_name: catalogObj.supplier_name,
            producer: catalogObj.producer || "",
            packaging: catalogObj.packaging || "",
            category: catalogObj.category || "",
          };
        } else if (type === ItemType.Oxygen) {
          catalogData = {
            market_id: catalogObj.market_id,
            packaging: catalogObj.packaging,
            packaging_size: catalogObj.packaging_size,
            supplier_id: catalogObj.supplier_id || "",
            supplier_name: catalogObj.supplier_name || "",
          };
        }
      } catch (e) {
        console.log("Malformed catalog object");
      }
    }

    verifyItemObject(ECommerceTypes.Item, itemDetail);
    logIngestEvent(ECommerceTypes.Item, {
      action: ItemAction.Impression,
      item: itemDetail,
    });
  };

  CfCore.getInstance().startTrackingImpressions(
    impressionHandler,
    containerClassname,
    itemClassname
  );
};

/**
 * When the container indicated in `startTrackingImpressions` is no longer
 * available (i.e.: the user has jumped to another section), call this function
 * to stop monitoring those items inside the removed container
 *
 * @param {string} containerClassname The className that identifies the container
 * to stop tracking
 */
const stopTrackingImpressions = (containerClassname, searchId?: string) => {
  CfCore.getInstance().stopTrackingImpressions(containerClassname);
};

/**
 * When the search is updated, that is, the user introduced a new query
 * or a new attribute in the available selector, but the container does not
 * changed, call the this function. It may happen that some items are shared
 * with the previous search but, due searchId has changed, they will be already
 * logged
 *
 * @param {string} searchId
 *
 * @throws `unknown-container` when the `containerClassname` was not being already tracked
 */
const restartTrackingImpressions = (containerClassname: string, searchId?: string) => {
  CfCore.getInstance().restartTrackingImpressions(containerClassname);
};

export default {
  logIngestEvent,
  logCatalogEvent,
  restartTrackingImpressions,
  startTrackingImpressions,
  stopTrackingImpressions,

  // Legacy functions
  logCancelCheckoutEvent,
  logCheckoutEvent,
  logCartEvent,
  logDeliveryEvent,
  logItemEvent,
};
