import PromiseMap from 'p-map';
import queryString from 'query-string';
import lodash from 'lodash';
import { loggerShopee } from '@/plugins/logger';
import { getRequestProductId, checkCrawlerDetected } from '@/api/shopee/getter';
import { readyFetchUrlShopeeClient, readyPostUrlShopeeClient } from '@/bridge/shopee/api';
import { excuteFetchUrl, fetchJson } from '@/api/shopee/fetch';
import { SHOPEE_DOMAIN_HOME } from '@/config/api';
import { refactorProduct } from '@/adapter/shopee/product';
import { adapterDetailProduct } from '@/adapter/shopee/adapter';
import { CacheShopeeProduct, CacheShopeeStock } from '@/plugins/store/cache';
import { KVShopeeProductStock } from '@/plugins/kv';
import { getShopeeProductExtraInfo } from '@/api/autoshopee/public';
import '@/types/Shopee/Payload/Product';

const getProductApiUrl = (productId, shopId) => {
  return queryString.stringifyUrl({
    url: `${SHOPEE_DOMAIN_HOME}/api/v4/pdp/get_pc`,
    query: {
      shop_id: shopId,
      item_id: productId,
    },
  });
};

/**
 *
 * @param {Array} tierIndex
 * @returns {string}
 */
const modelTierStringify = (tierIndex) => {
  return JSON.stringify(Object.fromEntries(tierIndex.map((value, index) => [index, value])));
};

const requestProduct = async (productId, shopId) => {
  const { active, listPayload } = await getRequestProductId(productId, shopId);

  if (!(active && listPayload && listPayload.length)) {
    loggerShopee.error({
      msg: 'PRODUCT_GET_HEADER_ERROR',
      productId,
      shopId,
    });

    return null;
  }

  let result = null;

  await PromiseMap(
    listPayload.reverse(),
    async ({ uuid, url, headers }) => {
      if (!result) {
        const get = await fetchJson(url, headers);

        if (!checkCrawlerDetected(get)) {
          result = get;
        }

        loggerShopee.error({
          msg: 'PRODUCT_GET_BY_REQUEST',
          isCrawlered: checkCrawlerDetected(get),
          result,
          uuid,
          get,
        });
      }
    },
    {
      concurrency: 1, // Single Get
    },
  );

  if (!result?.data) {
    return null;
  }

  return result.data;
};

const runtimeProductId = async (productId, shopId) => {
  const url = getProductApiUrl(productId, shopId);
  const fetchProduct = await readyFetchUrlShopeeClient(url);

  if (!(fetchProduct && fetchProduct.data)) {
    return null;
  }

  return fetchProduct.data;
};

const fetchProductId = async (productId, shopId) => {
  const fetchUrl = getProductApiUrl(productId, shopId);
  const fetchProduct = await excuteFetchUrl(fetchUrl);

  if (!(fetchProduct && fetchProduct.data)) {
    return null;
  }

  return fetchProduct.data;
};

const productApiMethod = {
  request: requestProduct,
  popup: runtimeProductId,
  content: fetchProductId,
};

export const fetchShopeeProductStock = async (productId, shopId, tinerIndex = 0, tierValue = 1) => {
  const payload = {
    item_id: productId,
    shop_id: shopId,
    quantity: 1,
    tz_offset_in_minutes: 420,
    selected_tiers: { [tinerIndex]: tierValue },
    device_sz_fingerprint: '',
  };

  const result = await readyPostUrlShopeeClient('https://shopee.vn/api/v4/pdp/cart_panel/select_variation_pc', payload);

  if (!(result && result.data)) {
    return null;
  }

  return result;
};

/**
 *
 * @param {string} productId
 * @param {string} shopId
 * @returns {Array}
 */
export const getShopeeProductStock = async (productId, shopId) => {
  const keyStore = [productId, shopId].join('-');

  const CacheStock = new CacheShopeeStock(keyStore);

  const getCache = await CacheStock.get();

  if (getCache) {
    return getCache || [];
  }

  const KvStock = new KVShopeeProductStock(keyStore);

  const getKv = await KvStock.get();

  if (getKv) {
    CacheStock.set(getKv);
    return getKv || [];
  }

  return [];
};

/**
 *
 * @param {ShopeeProductData} productData
 */
const fetchStockProduct = async (productData) => {
  try {
    const { item_id: productId, shop_id: shopId } = productData;

    /** @type {Array<{modelId: number, stock: number}>} */
    const getListStock = await getShopeeProductStock(productId, shopId);

    productData.models = productData.models.map((model) => {
      const isHasStock = lodash.get(model, 'has_stock', true);

      const modelId = model.modelid || model.model_id || model.id;
      const modelTier = modelTierStringify(model.extinfo.tier_index);

      const matchStock = getListStock.find((item) => item.modelId === modelId || item.modelId === modelTier);

      if (matchStock && matchStock.stock) {
        model.model_stock = matchStock.stock;
        model.real_stock = matchStock.stock;
        model.stock = matchStock.stock;
        model.fetched_stock = true;
      }

      if (!isHasStock) {
        model.model_stock = 0;
        model.real_stock = 0;
        model.stock = 0;
        model.fetched_stock = true;
        return model;
      }

      return model;
    });
  } catch (error) {
    loggerShopee.error({
      msg: 'FETCH_STOCK_PRODUCT_ERROR',
      error,
      productData,
    });
  }

  return productData;
};
  /**
   *
   * @param {ShopeeProductData} productData
   */
const pullProductExtraInfo = async (productData) => {
  try {
    const { item_id: productId, shop_id: shopId } = productData;

    /** @type {ShopeeProductGetExtra} */
    const result = await getShopeeProductExtraInfo(shopId, productId);

    const { listModelSku, listModelDimension } = result;

    const primaryDimension = listModelDimension[0] || null;

    productData.models = productData.models.map((model) => {
      const modelId = model.modelid || model.model_id || model.id;
      const isHasStock = lodash.get(model, 'has_stock', true);
      const matchStock = listModelSku.find((item) => Number(item.modelId) === Number(modelId));

      if (matchStock && matchStock.stock) {
        model.fetched_stock = true;
        model.model_stock = matchStock.stock;
        model.real_stock = matchStock.stock;
        model.stock = matchStock.stock;
        model.sku = matchStock.modelSku;
        productData.sku = matchStock.productSku;
        productData.parent_sku = matchStock.productSku;
      }

      if (!isHasStock) {
        model.model_stock = 0;
        model.real_stock = 0;
        model.stock = 0;
        return model;
      }

      return model;
    });

    if (primaryDimension) {
      productData.dimension = {
        weight: primaryDimension.weight,
        width: primaryDimension.width,
        height: primaryDimension.height,
        length: primaryDimension.length,
      };
      productData.weight = primaryDimension.weight;
    }
  } catch (error) {
    loggerShopee.error({
      msg: 'PULL_PRODUCT_EXTRA_INFO_ERROR',
      error,
      productData,
    });
  }

  return productData;
};

/**
 *
 * @param {string} productId
 * @param {string} shopId
 * @param {ShopeeFetchMethod} method
 * @param {boolean} isFetchRealData
 * @returns  {Promise<ShopeeProductData>}
 */
export const getShopeeProductId = async (productId, shopId, method = '', isFetchRealData = false) => {
  const keyProduct = `${shopId}-${productId}`;
  const CacheProduct = new CacheShopeeProduct(keyProduct);

  const getCache = await CacheProduct.get();

  if (getCache) {
    loggerShopee.error({
      msg: 'GET_PRODUCT_DETAIL',
      by: 'cache',
      method,
      product: getCache,
    });

    if (!isFetchRealData) {
      return getCache;
    }

    return (
      await fetchStockProduct(
        await pullProductExtraInfo(getCache),
      )
    );
  }

  let productDetail = null;

  try {
    if (!productDetail) {
      productDetail = await productApiMethod.request(productId, shopId);
      if (productDetail) {
        loggerShopee.error({
          msg: 'GET_PRODUCT_DETAIL',
          by: 'request',
          method,
          product: productDetail,
        });
      }
    }

    if (!productDetail && method === 'content') {
      productDetail = await productApiMethod.content(productId, shopId);
      if (productDetail) {
        loggerShopee.error({
          msg: 'GET_PRODUCT_DETAIL',
          by: 'content',
          method,
          product: productDetail,
        });
      }
    }

    if (!productDetail && method === 'popup') {
      productDetail = await productApiMethod.popup(productId, shopId);
      if (productDetail) {
        loggerShopee.error({
          msg: 'GET_PRODUCT_DETAIL',
          by: 'popup',
          method,
          product: productDetail,
        });
      }
    }
  } catch (error) {
    loggerShopee.error({
      msg: 'GET_PRODUCT_ERROR',
      type: method,
      error,
    });
  }

  if (!productDetail) {
    loggerShopee.error({
      msg: 'ERROR_PRODUCT_DETAIL',
      method,
    });

    return null;
  }

  const productRender = await adapterDetailProduct(productDetail);

  const productData = refactorProduct(productRender);

  if (!isFetchRealData) {
    await CacheProduct.set(productData);

    return getCache;
  }

  const productFetched = (
    await fetchStockProduct(
      await pullProductExtraInfo(refactorProduct(productRender)),
    )
  );

  await CacheProduct.set(productFetched);

  return productFetched;
};
