import lodash from 'lodash';
import Promise from 'bluebird';
import asyncRetry from 'async-retry';
import unixTimestamp from 'unix-timestamp';
import delay from 'delay';
import { createIntegratedUi } from 'wxt/utils/content-script-ui/integrated';

import i18n from '@/plugins/i18n';

import { searchByKeyword as linkSearchByKeyword } from '@/adapter/shopee/render/index';
import { normalizeSearchItem } from '@/adapter/shopee/product';
import { getSearchKeywordProduct } from '@/api/shopee/client/product';
import { shopeeUrlMatchProductId } from '@/lib/match';
import { parseCurrentUrl, getCurrentUrl } from '@/lib/content';
import moment from '@/lib/utils/moment';
import { addCommas } from '@/lib/utils/str';

import { bridgeOpenPopupUrl, bridgeGetUserInfo } from '@/bridge/content/background';
import { getShopeeConfigProduct } from '@/plugins/storage/items';
import {
  ELEMENT_IDS,
  SELECTORS,
  CSS_CLASSES,
  SPY_BTN_BASE_STYLE,
  SPY_BTN_HOVER_STYLE,
  SPY_BTN_NORMAL_STYLE,
  CONTENT_OPTIONS,
} from '@content/shopee/client/constant';
import { getShopeeSellerId } from '@content/shopee/client/shop';
import { loggerContent } from '@/plugins/logger';

/**
 * @typedef {object} SearchProductData
 * @property {string} url
 * @property {string} keyword
 * @property {number} limit
 * @property {number} page
 * @property {Array} list
 * @property {number} total
 * @property {object} ads
 * @property {number} ads.total
 */

/**
 * @typedef {object} Styles
 * @property {object} ads
 * @property {object} button
 * @property {object} stats
 * @property {object} productInfo
 */

export class ProductSearchLoader {
  /**
   * @type {Styles}
   */
  static styles = {
    ads: {
      marginTop: '10px',
      marginBottom: '10px',
      padding: '8px 12px',
      color: '#fff',
      background: 'linear-gradient(45deg, #3c00b1, #6a00ff)',
      borderRadius: '4px',
      cursor: 'pointer',
      border: '0',
      boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
      transition: 'all 0.3s ease',
    },
    button: {
      padding: '3px 8px',
      color: '#fff',
      background: 'linear-gradient(45deg, #2c2c2c, #4a4a4a)',
      borderRadius: '4px',
      cursor: 'pointer',
      border: '0',
      boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
      transition: 'all 0.3s ease',
      fontSize: '12px',
    },
    stats: {
      padding: '8px 12px',
      color: '#f6402e',
      background: '#fff',
      borderRadius: '4px',
      boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
      marginLeft: '10px',
    },
    productInfo: {
      padding: '12px',
      fontSize: '14px',
      background: '#fff',
      borderRadius: '4px',
      boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
      marginTop: '4px',
    },
  };

  /**
   * @param {string} keyword
   * @param {number} max
   * @returns {string}
   */
  static maxString(keyword, max = 10) {
    if (keyword.length > max) {
      return `${keyword.substring(0, max)} ...`;
    }
    return keyword;
  }

  /**
   * @param {object} styleObj
   * @returns {string}
   */
  static getStyleString(styleObj) {
    return Object.entries(styleObj)
      .map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}:${value}`)
      .join('; ');
  }

  constructor(ctx) {
    this.ctx = ctx;

    /** @type {SearchProductData} */
    this.searchData = {
      url: '',
      keyword: '',
      limit: 60,
      page: 0,
      list: [],
      total: 0,
      ads: {
        total: 0,
      },
    };

    /** @type {BridgeGetUserData} */
    this.userInfo = null;
  }

  async fetchUserInfo() {
    if (!this.userInfo) {
      this.userInfo = await bridgeGetUserInfo();
    }
  }

  getUserInfo() {
    return this.userInfo;
  }

  /**
   * @returns {Promise<boolean>}
   */
  async statsSearchAppend() {
    await delay(1000);

    const elementSearch = {
      root: SELECTORS.SEARCH_HEADER,
      trackedId: ELEMENT_IDS.STATS_SEARCH,
    };

    if (!document.querySelector(elementSearch.root)) {
      return false;
    }

    const parentElement = document.querySelector(elementSearch.root);

    const statsText = [
      i18n.t('SEARCH_PRODUCT_META_ADS', { total: this.searchData.ads.total }),
      i18n.t('SEARCH_PRODUCT_META_TOTAL', { total: this.searchData.total }),
    ].join(', ');

    if (!parentElement.querySelector(`#${elementSearch.trackedId}`)) {
      const elementAdd = document.createElement('div');
      elementAdd.id = elementSearch.trackedId;
      elementAdd.style = ProductSearchLoader.getStyleString(ProductSearchLoader.styles.stats);
      elementAdd.title = i18n.t('AUTOSHOPEE_COPYRIGHT');

      elementAdd.innerHTML = statsText;
      parentElement.append(elementAdd);
    } else {
      parentElement.querySelector(`#${elementSearch.trackedId}`).innerHTML = statsText;
    }

    if (!this._spySearchUi && CONTENT_OPTIONS.floatSpySearchBtn) {
      this._spySearchUi = createIntegratedUi(this.ctx, {
        position: 'overlay',
        zIndex: 9999,
        onMount: (container) => {
          const btnSpy = document.createElement('button');
          btnSpy.innerHTML = `<span style="font-size:14px;margin-right:6px">🔍</span><span style="font-size:13px;font-weight:600">${i18n.t('SPY_PRODUCT_DATA')}</span>`;

          Object.assign(btnSpy.style, SPY_BTN_BASE_STYLE);

          btnSpy.addEventListener('mouseenter', () => {
            Object.assign(btnSpy.style, SPY_BTN_HOVER_STYLE);
          });

          btnSpy.addEventListener('mouseleave', () => {
            Object.assign(btnSpy.style, SPY_BTN_NORMAL_STYLE);
          });

          btnSpy.addEventListener('click', () => {
            bridgeOpenPopupUrl({
              path: '/shopee/spy/search',
              qs: { keyword: this.searchData.keyword },
            });
          });

          container.append(btnSpy);
        },
      });

      this._spySearchUi.mount();
    }
  }

  /**
   * @returns {Promise<object | boolean>}
   */
  async updateSearchData() {
    await this.fetchUserInfo();

    const opts = {};
    const parseUrl = parseCurrentUrl();
    const url = getCurrentUrl();
    const { keyword } = parseUrl.query;

    if (!(keyword && url !== this.searchData.url)) {
      return false;
    }

    this.searchData.list = [];
    this.searchData.total = 0;
    this.searchData.url = url;
    this.searchData.keyword = keyword;
    this.searchData.page = Number(parseUrl.query.page) || 0;
    this.searchData.limit = 60;

    if (parseUrl.query.sortBy) {
      opts.by = parseUrl.query.sortBy;
    }

    await delay(1000);
    const getSearch = await getSearchKeywordProduct(
      this.searchData.keyword,
      this.searchData.page,
      this.searchData.limit,
      opts,
    );

    if (getSearch && getSearch.total_count) {
      this.searchData.list = getSearch.items.map((item, index) => {
        const normalized = normalizeSearchItem(item);
        normalized.search_rank = (this.searchData.page * this.searchData.limit) + index + 1;
        return normalized;
      });
      this.searchData.total = getSearch.total_count;
      this.searchData.ads.total = this.searchData.list.filter((item) => item.campaignid).length;

      this.statsSearchAppend().catch(() => {});
    }

    return getSearch;
  }

  /**
   * @param {HTMLElement} productBlock
   * @param {string} elementTrackerId
   * @param {object} settingConfig
   * @returns {Promise<boolean>}
   */
  async addBlockProduct(productBlock, elementTrackerId, settingConfig) {
    const { shopId, productId } = this.extractProductInfo(productBlock);

    if (!this.hasValidProductInfo(shopId, productId)) {
      return false;
    }

    const uniqueTrackerId = `${elementTrackerId}_${productId}_${shopId}`;

    const existingBox = productBlock.querySelector(`#${uniqueTrackerId}`);

    if (existingBox && !existingBox.dataset.autoshopeeEmpty) {
      return false;
    }

    const userInfo = this.getUserInfo();

    let productInfo = null;

    if (existingBox) {
      productInfo = this.findProductInList(productId, shopId);

      if (!productInfo) {
        return false;
      }

      this.removeSpyElements(productBlock, existingBox);
    } else {
      productInfo = await this.getProductInSearch(productId, shopId);
    }

    this.handleOwnerProduct(productBlock, shopId);

    if (settingConfig.addCloneBtn) {
      this.addCloneButton(productBlock, productId, shopId);
    }

    if (settingConfig.spySearch) {
      this.addSpySearchInfo(productBlock, uniqueTrackerId, productInfo, userInfo);
    }

    if (settingConfig.spyAds) {
      this.addSpyAdsInfo(productBlock, productInfo, userInfo);
    }
  }

  /**
   * @param {HTMLElement} productBlock
   * @returns {object}
   */
  extractProductInfo(productBlock) {
    const productUrl = productBlock.getAttribute('href');
    return shopeeUrlMatchProductId(productUrl);
  }

  /**
   * @param {string} shopId
   * @param {string} productId
   * @returns {boolean}
   */
  hasValidProductInfo(shopId, productId) {
    return !!(shopId && productId);
  }

  /**
   * @param {string} productId
   * @param {string} shopId
   * @returns {object | null}
   */
  findProductInList(productId, shopId) {
    const productInSearch = this.searchData.list.find(
      (item) => item.itemid === Number(productId) && item.shopid === Number(shopId),
    );

    if (!productInSearch) {
      return null;
    }

    return productInSearch;
  }

  /**
   * @param {HTMLElement} productBlock
   * @param {HTMLElement} existingBox
   */
  removeSpyElements(productBlock, existingBox) {
    existingBox.remove();

    const oldAdsBtn = productBlock.querySelector(`.${CSS_CLASSES.SPY_ADS_BTN}`);

    if (oldAdsBtn) {
      oldAdsBtn.remove();
    }

    const oldBidBtn = productBlock.querySelector(`.${CSS_CLASSES.BID_ADS_BTN}`);

    if (oldBidBtn) {
      oldBidBtn.remove();
    }
  }

  /**
   * @param {string} productId
   * @param {string} shopId
   * @returns {Promise<object>}
   */
  async getProductInSearch(productId, shopId) {
    let productInSearch = this.findProductInList(productId, shopId);

    if (!productInSearch) {
      try {
        productInSearch = await asyncRetry(async () => {
          const product = this.findProductInList(productId, shopId);

          if (!product) {
            throw new Error('Product not found');
          }

          return product;
        }, {
          retries: 15,
          minTimeout: 200,
          maxTimeout: 200,
        });
      } catch (error) {
        productInSearch = null;
      }
    }

    return productInSearch;
  }

  /**
   * @param {HTMLElement} productBlock
   * @param {string} shopId
   */
  handleOwnerProduct(productBlock, shopId) {
    const isOwnerProduct = Number(shopId) === getShopeeSellerId();

    if (isOwnerProduct) {
      productBlock.parentElement.style.background = 'rgb(122 0 255)';
      productBlock.parentElement.style.padding = '2px';
    }
  }

  /**
   * @param {HTMLElement} productBlock
   * @param {string} productId
   * @param {string} shopId
   */
  addCloneButton(productBlock, productId, shopId) {
    const imageWrapper = productBlock.querySelector(SELECTORS.IMAGE_WRAPPER);

    if (!imageWrapper) {
      return;
    }

    const mainImg = imageWrapper.querySelector('img');

    if (!mainImg || imageWrapper.querySelector(`.${CSS_CLASSES.COPY_BTN}`)) {
      return;
    }

    const btnCopy = this.createCloneButton(productId, shopId);

    imageWrapper.style.position = 'relative';
    imageWrapper.appendChild(btnCopy);

    this.addCloneButtonEvents(imageWrapper, btnCopy);
  }

  /**
   * @param {string} productId
   * @param {string} shopId
   * @returns {HTMLElement}
   */
  createCloneButton(productId, shopId) {
    const btnCopy = document.createElement('button');
    btnCopy.className = CSS_CLASSES.COPY_BTN;
    btnCopy.innerText = i18n.t('BTN_COPY');

    const buttonStyles = {
      position: 'absolute',
      top: '70px',
      left: '0',
      width: '100%',
      zIndex: '10',
      background: 'rgba(238,77,45,0.9)',
      color: '#fff',
      border: 'none',
      padding: '8px 16px',
      fontSize: '16px',
      cursor: 'pointer',
      boxShadow: '0 2px 4px rgba(0,0,0,0.15)',
      transition: 'all 0.2s',
      display: 'none',
    };

    Object.assign(btnCopy.style, buttonStyles);

    const onClick = (event) => {
      event.preventDefault();
      bridgeOpenPopupUrl({
        path: '/shopee/product/clone',
        qs: { productId, shopId },
      });
    };

    btnCopy.addEventListener('click', onClick);

    return btnCopy;
  }

  /**
   * @param {HTMLElement} imageWrapper
   * @param {HTMLElement} btnCopy
   */
  addCloneButtonEvents(imageWrapper, btnCopy) {
    imageWrapper.addEventListener('mouseenter', () => {
      btnCopy.style.display = 'block';
    });

    imageWrapper.addEventListener('mouseleave', () => {
      btnCopy.style.display = 'none';
    });
  }

  /**
   * @param {HTMLElement} productBlock
   * @param {string} elementTrackerId
   * @param {object} productInfo
   * @param {object} userInfo
   */
  addSpySearchInfo(productBlock, elementTrackerId, productInfo) {
    const productData = this.createProductData(productInfo);
    const elementProductExtra = this.createSpySearchElement(elementTrackerId, productData);

    if (!productInfo) {
      elementProductExtra.dataset.autoshopeeEmpty = '1';
    }

    const className = productBlock.getAttribute('class');
    const elementParent = !className ? 'div > div' : 'div';

    if (!productBlock.querySelector(`#${elementTrackerId}`)) {
      productBlock.querySelector(elementParent).append(elementProductExtra);
    }
  }

  /**
   * @param {object} productInfo
   * @param {object} userInfo
   * @returns {Array}
   */
  createProductData(productInfo) {
    if (!productInfo) {
      productInfo = this.getDefaultProductInfo();
    }

    const createdDate = productInfo.ctime ? unixTimestamp.toDate(productInfo.ctime) : null;
    const createdStr = createdDate ? moment(createdDate).format('DD/MM/YYYY') : '???';
    const timeAgo = createdDate ? moment(createdDate).fromNow() : '';
    const soldMonth = productInfo.sold || 0;
    const soldMonthValue = productInfo.price ? (soldMonth * productInfo.price) / 100000 : 0;
    const soldTotal = productInfo.historical_sold || 0;
    const soldTotalValue = productInfo.price ? (soldTotal * productInfo.price) / 100000 : 0;

    if (!productInfo.brand) {
      productInfo.brand = 'NoBrand';
    }

    const listData = [
      {
        type: 'date',
        label: createdStr,
        subLabel: timeAgo ? ` - ${timeAgo.replace(' trước', '')}` : '',
        style: 'font-weight:600;',
        subStyle: 'color:#888;font-size:10px;',
      },
      {
        type: 'sold-month',
        label: i18n.t('SPY_PRODUCT_SOLD_MONTH'),
        value: addCommas(soldMonth),
        style: 'margin-top:2px;',
      },
      {
        type: 'sold-month-value',
        label: i18n.t('SPY_PRODUCT_SALE'),
        value: addCommas(soldMonthValue),
        style: 'margin-bottom:2px;',
      },
      {
        type: 'sold-total',
        label: i18n.t('SPY_PRODUCT_SOLD_TOTAL'),
        value: addCommas(soldTotal),
        style: 'margin-top:2px;',
      },
      {
        type: 'sold-total-value',
        label: i18n.t('SPY_PRODUCT_SALE'),
        value: addCommas(soldTotalValue),
        style: '',
      },
      {
        type: 'brand',
        label: productInfo.brand,
        style: 'margin-top:2px;',
        labelStyle: `color:${productInfo.brand === 'NoBrand' ? '#000' : '#ff6600'};`,
      },
    ];

    if (productInfo.search_rank) {
      const rankItem = {
        type: 'rank',
        label: i18n.t('SPY_PRODUCT_RANK'),
        value: `#${productInfo.search_rank}`,
        style: 'margin-top:2px;',
      };

      if (productInfo.matched_keywords && productInfo.matched_keywords.length) {
        rankItem.title = productInfo.matched_keywords.join(', ');
      }

      listData.splice(1, 0, rankItem);
    }

    if (productInfo.shop_name) {
      const flagInfo = ProductSearchLoader.sellerFlagInfo(productInfo.seller_flag_name);

      listData.splice(listData.length - 1, 0, {
        type: 'shop',
        label: productInfo.shop_name,
        flag: flagInfo,
        style: 'margin-top:2px;',
      });
    }

    return listData;
  }

  /**
   * @param {string} flagName
   * @returns {object | null}
   */
  static sellerFlagInfo(flagName) {
    if (flagName === 'PREFERRED_PLUS') {
      return {
        text: i18n.t('SPY_SHOP_FLAG_PREFERRED_PLUS'),
        color: '#ee4d2d',
      };
    }

    if (flagName === 'PREFERRED') {
      return {
        text: i18n.t('SPY_SHOP_FLAG_PREFERRED'),
        color: '#ee4d2d',
      };
    }

    if (flagName === 'MALL' || flagName === 'OFFICIAL_SHOP') {
      return {
        text: i18n.t('SPY_SHOP_FLAG_MALL'),
        color: '#d0011b',
      };
    }

    return null;
  }

  /**
   * @returns {object}
   */
  getDefaultProductInfo() {
    return {
      itemid: 0,
      shopid: 0,
      ctime: 0,
      historical_sold: 0,
      sold: 0,
      price: 0,
      brand: 'NoBrand',
      name: 'NoName',
      label_ids: [],
      image: '',
      images: [],
      currency: 'VND',
    };
  }

  /**
   * @param {string} elementTrackerId
   * @param {Array} productData
   * @returns {HTMLElement}
   */
  createSpySearchElement(elementTrackerId, productData) {
    const elementProductExtra = document.createElement('div');
    elementProductExtra.id = elementTrackerId;
    elementProductExtra.style = ProductSearchLoader.getStyleString(ProductSearchLoader.styles.productInfo);

    const containerDiv = this.createProductDataContainer(productData);
    elementProductExtra.appendChild(containerDiv);

    return elementProductExtra;
  }

  /**
   * @param {Array} productData
   * @returns {HTMLElement}
   */
  createProductDataContainer(productData) {
    const containerDiv = document.createElement('div');

    containerDiv.style.cssText = `
      font-size:12px;
      line-height:1.6;
      padding:0;
      border-radius:0;
      box-shadow:none;
      border:none;
      background:none;
      min-width:0;
    `;

    productData.forEach((item, idx) => {
      const rowDiv = this.createProductDataRow(item, idx, productData.length);
      containerDiv.appendChild(rowDiv);
    });

    return containerDiv;
  }

  /**
   * @param {object} item
   * @param {number} idx
   * @param {number} totalLength
   * @returns {HTMLElement}
   */
  createProductDataRow(item, idx, totalLength) {
    const rowDiv = document.createElement('div');

    rowDiv.style.cssText = `
      display:flex;
      justify-content:space-between;
      align-items:flex-end;
      margin-bottom:${item.type === 'brand' ? '0' : '2px'};
      ${item.style || ''}
    `;

    if (item.type === 'date') {
      this.createDateRow(rowDiv, item);
    } else if (item.type === 'brand') {
      this.createBrandRow(rowDiv, item);
    } else if (item.type === 'shop') {
      this.createShopRow(rowDiv, item);
    } else {
      this.createDataRow(rowDiv, item);
    }

    if (item.title) {
      rowDiv.title = item.title;
    }

    if (this.shouldAddSeparator(item.type, idx, totalLength)) {
      const hr = document.createElement('div');
      hr.style.cssText = 'border-bottom:1px solid #e0e0e0;margin:4px 0;';
      rowDiv.appendChild(hr);
    }

    return rowDiv;
  }

  /**
   * @param {HTMLElement} rowDiv
   * @param {object} item
   */
  createDateRow(rowDiv, item) {
    const labelSpan = document.createElement('span');
    labelSpan.style.cssText = 'font-weight:600;color:#222;font-size:13px;';
    labelSpan.innerHTML = `<span>${item.label}</span>`;

    if (item.subLabel) {
      const subLabelSpan = document.createElement('span');
      subLabelSpan.style.cssText = 'color:#888;font-size:12px;margin-left:4px;';
      subLabelSpan.textContent = item.subLabel;
      labelSpan.appendChild(subLabelSpan);
    }

    rowDiv.appendChild(labelSpan);
  }

  /**
   * @param {HTMLElement} rowDiv
   * @param {object} item
   */
  createShopRow(rowDiv, item) {
    const labelSpan = document.createElement('span');
    labelSpan.style.cssText = 'color:#555;font-size:12px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
    labelSpan.textContent = item.label;
    labelSpan.title = item.label;
    rowDiv.appendChild(labelSpan);

    if (item.flag) {
      const flagSpan = document.createElement('span');
      flagSpan.style.cssText = `color:#fff;background:${item.flag.color};font-size:10px;line-height:16px;border-radius:2px;padding:0 4px;margin-left:4px;flex:none;`;
      flagSpan.textContent = item.flag.text;
      rowDiv.appendChild(flagSpan);
    }
  }

  /**
   * @param {HTMLElement} rowDiv
   * @param {object} item
   */
  createBrandRow(rowDiv, item) {
    const labelSpan = document.createElement('span');
    labelSpan.style.cssText = `${item.labelStyle || ''}font-size:14px`;
    labelSpan.textContent = item.label;
    rowDiv.appendChild(labelSpan);
  }

  /**
   * @param {HTMLElement} rowDiv
   * @param {object} item
   */
  createDataRow(rowDiv, item) {
    const labelSpan = document.createElement('span');
    labelSpan.style.cssText = 'color:#888;font-size:12px;';
    labelSpan.textContent = item.label;
    rowDiv.appendChild(labelSpan);

    const valueSpan = document.createElement('span');
    valueSpan.style.cssText = `
      color:#009900;
      font-weight:700;
      font-size:14px;
      min-width:44px;
      text-align:right;
      display:inline-block;
    `;
    valueSpan.textContent = item.value;
    rowDiv.appendChild(valueSpan);
  }

  /**
   * @param {string} type
   * @param {number} idx
   * @param {number} totalLength
   * @returns {boolean}
   */
  shouldAddSeparator(type, idx, totalLength) {
    return (type === 'date' || type === 'sold-month-value' || type === 'sold-total-value') && idx < totalLength - 1;
  }

  /**
   * @param {HTMLElement} productBlock
   * @param {object} productInfo
   * @param {object} userInfo
   */
  addSpyAdsInfo(productBlock, productInfo) {
    const imageWrapper = productBlock.querySelector(SELECTORS.IMAGE_WRAPPER);

    if (!imageWrapper) {
      return;
    }

    if (imageWrapper.querySelector(`.${CSS_CLASSES.SPY_ADS_BTN}`)) {
      return;
    }

    const btnSpyAds = this.createSpyAdsButton();

    if (productInfo && productInfo.campaignid) {
      this.handleAdsProduct(btnSpyAds, productInfo);
    } else {
      this.handleNonAdsProduct(btnSpyAds);
    }

    imageWrapper.style.position = 'relative';
    imageWrapper.appendChild(btnSpyAds);
  }

  /**
   * @returns {HTMLElement}
   */
  createSpyAdsButton() {
    const btnSpyAds = document.createElement('button');
    btnSpyAds.className = CSS_CLASSES.SPY_ADS_BTN;

    const buttonStyles = {
      position: 'absolute',
      top: '6px',
      left: '6px',
      zIndex: '10',
      background: 'linear-gradient(45deg, #3c00b1, #6a00ff)',
      color: '#fff',
      border: 'none',
      borderRadius: '4px',
      padding: '2px 8px',
      fontSize: '13px',
      cursor: 'pointer',
      boxShadow: '0 2px 4px rgba(0,0,0,0.15)',
      transition: 'all 0.2s',
      marginBottom: '0',
      marginTop: '0',
    };

    Object.assign(btnSpyAds.style, buttonStyles);

    return btnSpyAds;
  }

  /**
   * @param {HTMLElement} btnSpyAds
   * @param {object} productInfo
   * @param {object} userInfo
   */
  handleAdsProduct(btnSpyAds, productInfo) {
    try {
      productInfo.search_item_tracking = JSON.parse(productInfo.search_item_tracking);
    } catch (error) {
      // Ignore parsing error
    }

    const adsBid = lodash.get(productInfo, 'search_item_tracking.ads_rank_bid', 0) / 100000;

    if (productInfo.ads_keyword === 'wkdaelpmissisiht') {
      btnSpyAds.innerHTML = i18n.t('ADS_UNKNOWN');
    } else if (productInfo.ads_keyword) {
      btnSpyAds.innerHTML = ProductSearchLoader.maxString(productInfo.ads_keyword, 40);
      const urlSearch = linkSearchByKeyword(productInfo.ads_keyword);

      btnSpyAds.addEventListener('click', (event) => {
        event.preventDefault();
        window.open(urlSearch);
      });
    } else {
      btnSpyAds.innerHTML = i18n.t('ADS_AUTOMATION');
    }

    if (adsBid > 0) {
      this.addBidAdsButton(btnSpyAds, adsBid);
    }
  }

  /**
   * @param {HTMLElement} btnSpyAds
   */
  handleNonAdsProduct(btnSpyAds) {
    btnSpyAds.innerHTML = i18n.t('ADS_NO');
    btnSpyAds.style.background = 'rgb(149 95 255)';
    btnSpyAds.style.visibility = 'hidden';
  }

  /**
   * @param {HTMLElement} btnSpyAds
   * @param {number} adsBid
   */
  addBidAdsButton(btnSpyAds, adsBid) {
    const btnBidAds = document.createElement('button');
    btnBidAds.className = CSS_CLASSES.BID_ADS_BTN;

    const buttonStyles = {
      position: 'absolute',
      top: '30px',
      left: '6px',
      zIndex: '10',
      background: 'linear-gradient(45deg, #ff6600, #ff9900)',
      color: '#fff',
      border: 'none',
      borderRadius: '4px',
      padding: '2px 8px',
      fontSize: '12px',
      cursor: 'pointer',
      boxShadow: '0 2px 4px rgba(0,0,0,0.15)',
      transition: 'all 0.2s',
      marginBottom: '0',
      marginTop: '0',
    };

    Object.assign(btnBidAds.style, buttonStyles);

    btnBidAds.innerHTML = i18n.t('ADS_BID_LABEL', {
      value: `${addCommas(adsBid)} đ`,
    });

    btnSpyAds.parentElement.appendChild(btnBidAds);
  }

  /**
   * @returns {Promise<boolean>}
   */
  async renderSearchProduct() {
    const elementSearch = {
      root: SELECTORS.SEARCH_PRODUCT_LIST,
      trackedId: ELEMENT_IDS.PRODUCT_SEARCH,
    };

    if (!document.querySelector(elementSearch.root)) {
      return false;
    }

    const shopeeConfigProduct = await getShopeeConfigProduct();
    const listElement = [...document.querySelectorAll(elementSearch.root)];

    await Promise.map(listElement, async (blockElement) => {
      await this.addBlockProduct(blockElement, elementSearch.trackedId, shopeeConfigProduct).catch((error) => {
        loggerContent.error({
          msg: 'SHOPEE_SEARCH_RENDER_BLOCK_ERROR',
          error,
        });
      });
    }, { concurrency: 5 });
  }

  observeNewProducts() {
    const root = document.querySelector(SELECTORS.SEARCH_ITEM_RESULT);

    if (!root) {
      this.ctx.setTimeout(() => this.observeNewProducts(), 1000);
      return;
    }

    if (this._productListObserver) {
      this._productListObserver.disconnect();
    }

    this._productListObserver = new MutationObserver(() => {
      this.renderSearchProduct();
    });

    this._productListObserver.observe(root, { childList: true });

    this.ctx.onInvalidated(() => {
      if (this._productListObserver) {
        this._productListObserver.disconnect();
      }
    });
  }

  observeUrlChange() {
    let lastUrl = getCurrentUrl();

    this.ctx.setInterval(() => {
      const currentUrl = getCurrentUrl();

      if (currentUrl !== lastUrl) {
        lastUrl = currentUrl;
        this.updateSearchData().then(() => {
          this.renderSearchProduct();
          this.observeNewProducts();
        });
      }
    }, 1000);
  }

  async initialize() {
    await this.updateSearchData();
    this.renderSearchProduct();
    this.observeNewProducts();
    this.observeUrlChange();
  }
}
