import arrayDedupe from 'array-dedupe';
import lodash from 'lodash';
import { v4 as uuid } from 'uuid';
import axios from 'axios';
import fetchAdapter from '@vespaiach/axios-fetch-adapter';
import { browser } from 'wxt/browser';
import { onMessage } from 'webext-bridge/background';
import {
  EVENT_GET_SCRIPT_URL,
  EVENT_OPEN_POPUP,
  EVENT_GET_USER_INFO,
  EVENT_GET_AFFILIATE_PLATFORM,
  EVENT_GET_LOCAL_SETTING,
  EVENT_SHOPEE_SAVE_PRODUCT,
  EVENT_SHOPEE_LISTEN_FETCH,
  EVENT_SHOPEE_GET_HEADER_SHOPEE,
  EVENT_SHOPEE_GET_AFFILIATE_CHAT,
  EVENT_SHOPEE_GET_PRODUCT,
  EVENT_FETCH_API_AUTOSHOPEE,
  EVENT_TIKTOK_DOWNLOAD_VIDEO_CHECK,
  EVENT_TIKTOK_DOWNLOAD_VIDEO_INC,
  EVENT_VIDEO_BLOB_STORE,
  EVENT_VIDEO_BLOB_GET,
} from '@/bridge/config/event';
import { TIKTOK_USAGE_LIMITS, TIKTOK_USAGE_TYPE } from '@/constant/tiktok';
import { UsageTiktok } from '@/models/usage';
import { openPopupUrl, tabOnUpdate, getTabLastest } from '@/browser/tab';
import { getUserInfo, getAffiliateUrl } from '../service/index';
import { allSetting } from '@/plugins/setting';
import { CacheShopeeProduct, CacheShopeeStock } from '@/plugins/store/cache';
import {
  RequestProductPayload, RequestSearchPayload, FetchListenerBucketShopee, ShopeeProductStock,
} from '@background/store/index';
import { renderContentChat } from '@/adapter/shopee/affiliate';
import { bridgeTabOnChange } from '@/bridge/background/content';
import { getConfigService } from '../get';
import { loggerBackground } from '@/plugins/logger';
import { KVShopeeProductStock } from '@/plugins/kv';

const autoshopeeApi = axios.create({
  adapter: fetchAdapter,
  responseType: 'json',
  timeout: 60000,
});

const listUrlBucketIgnore = [
  '/api/v1',
  '/api/v4/notification',
  'banhang.shopee.vn',
  '/api/v4/banner/',
  '/user',
  '/api/v4/cart/mini',
  '/api/v4/account',
  '/api/v4/abtest/traffic',
  '/api/v4/pages',
  '/api/v4/itemcard/set/elements',
  '/login',
];

getConfigService().then((getConfig) => {
  if (getConfig.fetchListenerLimit) {
    FetchListenerBucketShopee.setLimit(getConfig.fetchListenerLimit);
  }

  FetchListenerBucketShopee.setActive(getConfig.fetchListenerActive);
}).catch(() => {});

/**
 *
 * @param {string} url
 */
const filterFetchUrlPush = (url) => {
  if (listUrlBucketIgnore.some((item) => url.includes(item))) {
    return false;
  }

  return true;
};

/**
 *
 * @param {ShopeeProductData} productData
 * @returns
 */
const setCacheProductShopee = (productData) => {
  const keyCache = `${productData.shop_id}-${productData.item_id}`;
  const CacheProduct = new CacheShopeeProduct(keyCache);
  return CacheProduct.set(productData);
};

/**
 * @param {ShopeeProductBodyVariation} bodyJson
 * @param {ShopeeProductSelectVariation} jsonData
 * @returns {Promise<void>}
 */
const handleShopeeSelectVariation = async (bodyJson, jsonData) => {
  const productId = bodyJson.item_id || lodash.get(bodyJson, 'rsku_id.item_id', 0);
  const shopId = bodyJson.shop_id || lodash.get(bodyJson, 'rsku_id.shop_id', 0);

  if (!(productId && shopId)) {
    throw 'Shopee select variation error missing product_id or shop_id';
  }

  let modelId = lodash.get(bodyJson, 'rsku_id.model_id', 0) || lodash.get(jsonData, 'product_price.final_price_info.model_id', 0) || lodash.get(jsonData, 'ongoing_banner.deep_discount.model_id', 0);

  const modelTier = bodyJson.selected_tiers || null;

  if (!modelId && modelTier) {
    modelId = JSON.stringify(modelTier);
  }

  if (!modelId) {
    throw 'Shopee select variation error missing model_id';
  }

  const modelStock = lodash.get(jsonData, 'selected_variation.max_quantity', 0);

  if (!modelStock) {
    throw 'Shopee select variation error missing model_stock';
  }

  const storeKey = [
    productId,
    shopId,
  ].join('-');

  const CacheStock = new CacheShopeeStock(storeKey);
  const KvStock = new KVShopeeProductStock(storeKey);

  /** @type {Array<{modelId: number, stock: number}>} */
  let listStock = ShopeeProductStock.get(storeKey);

  if (!listStock) {
    const cachePayload = await CacheStock.get();

    if (cachePayload && cachePayload.length) {
      listStock = cachePayload;
      ShopeeProductStock.set(storeKey, listStock);
    }
  }

  if (!listStock) {
    const kvPayload = await KvStock.get();

    if (kvPayload && kvPayload.length) {
      listStock = kvPayload;
      ShopeeProductStock.set(storeKey, listStock);
    }
  }

  if (!listStock) {
    listStock = [];
    ShopeeProductStock.set(storeKey, listStock);
  }

  listStock.push({
    modelId,
    modelStock,
    stock: modelStock,
  });

  const payloadSet = arrayDedupe(listStock, ['modelId']);

  ShopeeProductStock.set(storeKey, payloadSet);

  await Promise.allSettled([
    CacheStock.set(payloadSet),
    KvStock.set(payloadSet),
  ]);

  return {
    productId,
    shopId,
    modelId,
    modelStock,
    payloadSet,
  };
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeShopeeListenFetch = async ({ data: request }) => {
  const { url, json } = request;

  if (filterFetchUrlPush(url)) {
    FetchListenerBucketShopee.pushData(url, json);
  }

  if (url.includes('pdp/cart_panel/select_variation_pc') || url.includes('pdp/get_pc_vsku')) {
    const body = JSON.parse(request.payload.body);

    await handleShopeeSelectVariation(body, json.data).then((result) => {
      loggerBackground.error({
        msg: 'SHOPEE_SELECT_VARIANT_SUCCESS',
        url,
        body,
        json: json.data,
        result,
      });
    }).catch((error) => {
      loggerBackground.error({
        msg: 'SHOPEE_SELECT_VARIANT_ERROR',
        url,
        body,
        json: json.data,
        error,
      });
    });
  }

  return true;
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeShopeeGetProduct = async ({ data }) => {
  const { productId, shopId } = data;
  const keyCache = `${shopId}-${productId}`;
  const CacheProduct = new CacheShopeeProduct(keyCache);
  return (await CacheProduct.get()) || null;
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeGetScriptUrl = async ({ data }) => ({
  scriptUrl: browser.runtime.getURL(data.scriptPath),
});

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeOpenPopup = async ({ data }) => {
  openPopupUrl(data.path, data.qs);
  return true;
};

const onBridgeGetUserInfo = async () => {
  return await getUserInfo();
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeGetAffiliatePlatform = async ({ data }) => {
  return await getAffiliateUrl(data.platform);
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeGetLocalSetting = async ({ data }) => {
  if (!allSetting[data.key]) {
    throw new Error(`Setting key not found: ${data.key}`);
  }

  return await allSetting[data.key].getSync();
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeShopeeSaveProduct = async ({ data }) => {
  setCacheProductShopee(data);
  return true;
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeShopeeGetHeaderShopee = async ({ data }) => {
  const getBy = data.by;
  if (getBy === 'product') {
    return RequestProductPayload.getList();
  }
  if (getBy === 'search') {
    return RequestSearchPayload.getList();
  }
  return [];
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns
 */
const onBridgeShopeeGetAffiliateChat = async ({ data }) => {
  try {
    const chatMessage = await renderContentChat(data);
    return chatMessage;
  } catch {
    return 'ERROR';
  }
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns {Promise<object>}
 */
const onBridgeFetchApiAutoshopee = async ({ data }) => {
  const response = await autoshopeeApi.request({
    ...data,
    data: data.body,
  });
  return response.data;
};

/**
 *
 * @param {string} planKey
 * @returns {number}
 */
const getTiktokDownloadDailyLimit = (planKey) => {
  const config = TIKTOK_USAGE_LIMITS.downloadVideo[planKey] || TIKTOK_USAGE_LIMITS.downloadVideo.Free;

  return config.dailyLimit;
};

const getTiktokDownloadUsed = async () => {
  const dayStart = new Date();
  dayStart.setHours(0, 0, 0, 0);

  return UsageTiktok.count({
    type: TIKTOK_USAGE_TYPE.downloadVideo,
    createdAt: {
      $gt: dayStart.toISOString(),
    },
  });
};

const onBridgeTiktokDownloadVideoCheck = async () => {
  const userInfo = await getUserInfo();

  if (!(userInfo && userInfo.isAuthed)) {
    return {
      allow: false, reason: 'login', used: 0, dailyLimit: 0,
    };
  }

  let planKey = 'Free';

  if (userInfo.extensionPlan) {
    planKey = userInfo.extensionPlan;
  }

  const dailyLimit = getTiktokDownloadDailyLimit(planKey);

  if (dailyLimit === Infinity) {
    return { allow: true, used: 0, dailyLimit };
  }

  const used = await getTiktokDownloadUsed();
  const allow = used < dailyLimit;

  if (allow) {
    return { allow: true, used, dailyLimit };
  }

  return {
    allow: false, reason: 'limit', used, dailyLimit,
  };
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns {Promise<{ok: boolean}>}
 */
const onBridgeTiktokDownloadVideoInc = async ({ data }) => {
  const awemeId = data && data.awemeId ? `${data.awemeId}` : '';
  const author = data && data.author ? `${data.author}` : '';

  let shopId = awemeId || author;

  if (!shopId) {
    shopId = 'tiktok';
  }

  await UsageTiktok.insert({
    type: TIKTOK_USAGE_TYPE.downloadVideo,
    shopId,
    payload: { awemeId, author },
  });

  return { ok: true };
};

const videoBlobStore = new Map();
const VIDEO_BLOB_KEY_PREFIX = 'videoblob_';

const videoBlobSession = browser.storage && browser.storage.session ? browser.storage.session : null;

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns {Promise<{blobId: string}>}
 */
const onBridgeVideoBlobStore = async ({ data }) => {
  const blobId = uuid();
  const entry = {
    base64: data.base64,
    contentType: data.contentType || 'video/mp4',
  };

  if (videoBlobSession) {
    const all = await videoBlobSession.get(null);
    const oldKeys = Object.keys(all).filter((key) => key.indexOf(VIDEO_BLOB_KEY_PREFIX) === 0);

    if (oldKeys.length) {
      await videoBlobSession.remove(oldKeys);
    }

    await videoBlobSession.set({
      [`${VIDEO_BLOB_KEY_PREFIX}${blobId}`]: entry,
    });
  } else {
    videoBlobStore.clear();
    videoBlobStore.set(blobId, entry);
  }

  return { blobId };
};

/**
 *
 * @param {BridgeParamBridgeMessage} param
 * @returns {Promise<{base64: string, contentType: string}|null>}
 */
const onBridgeVideoBlobGet = async ({ data }) => {
  if (videoBlobSession) {
    const key = `${VIDEO_BLOB_KEY_PREFIX}${data.blobId}`;
    const result = await videoBlobSession.get(key);

    return result[key] || null;
  }

  return videoBlobStore.get(data.blobId) || null;
};

const SHOPEE_TAB_URL_PATTERNS = ['shopee.vn', 'banhang.shopee.vn'];

const isShopeeTab = (tabData) => {
  if (!tabData || !tabData.url) {
    return false;
  }
  return SHOPEE_TAB_URL_PATTERNS.some((pattern) => tabData.url.includes(pattern));
};

const onBridgerTabChange = async () => {
  const tabData = await getTabLastest();

  if (!(tabData && tabData.id)) {
    return 0;
  }

  if (!isShopeeTab(tabData)) {
    return 0;
  }

  bridgeTabOnChange(tabData.id, tabData).catch(() => {});

  return tabData.id;
};

const startKeepAlive = () => browser.runtime.onConnect.addListener((port) => {
  if (port.name === 'keepAlive') {
    port.onMessage.addListener((data) => {
      if (data.ping) {
        if (false) {
          loggerBackground.log({
            msg: 'KeepAlive Connected',
            from: data.from,
          });
        }
      }
    });

    port.onDisconnect.addListener(() => {
      if (false) {
        loggerBackground.error({
          msg: 'KeepAlive Disconnected',
        });
      }
    });
  }
});

export const brideService = async () => {
  startKeepAlive();

  onMessage(EVENT_SHOPEE_LISTEN_FETCH, onBridgeShopeeListenFetch);
  onMessage(EVENT_SHOPEE_GET_PRODUCT, onBridgeShopeeGetProduct);
  onMessage(EVENT_GET_SCRIPT_URL, onBridgeGetScriptUrl);
  onMessage(EVENT_OPEN_POPUP, onBridgeOpenPopup);
  onMessage(EVENT_GET_USER_INFO, onBridgeGetUserInfo);
  onMessage(EVENT_GET_AFFILIATE_PLATFORM, onBridgeGetAffiliatePlatform);
  onMessage(EVENT_GET_LOCAL_SETTING, onBridgeGetLocalSetting);
  onMessage(EVENT_SHOPEE_SAVE_PRODUCT, onBridgeShopeeSaveProduct);
  onMessage(EVENT_SHOPEE_GET_HEADER_SHOPEE, onBridgeShopeeGetHeaderShopee);
  onMessage(EVENT_SHOPEE_GET_AFFILIATE_CHAT, onBridgeShopeeGetAffiliateChat);
  onMessage(EVENT_FETCH_API_AUTOSHOPEE, onBridgeFetchApiAutoshopee);
  onMessage(EVENT_TIKTOK_DOWNLOAD_VIDEO_CHECK, onBridgeTiktokDownloadVideoCheck);
  onMessage(EVENT_TIKTOK_DOWNLOAD_VIDEO_INC, onBridgeTiktokDownloadVideoInc);
  onMessage(EVENT_VIDEO_BLOB_STORE, onBridgeVideoBlobStore);
  onMessage(EVENT_VIDEO_BLOB_GET, onBridgeVideoBlobGet);

  tabOnUpdate(onBridgerTabChange);
};
