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 { 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 { storageShopeeConfigProduct } 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) => ({
        ...item,
        ...item.item_basic,
      }));
      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}`;

    if (productBlock.querySelector(`#${uniqueTrackerId}`)) {
      return false;
    }

    const userInfo = this.getUserInfo();
    const 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 {Promise<object>}
   */
  async getProductInSearch(productId, shopId) {
    const listProduct = this.searchData.list;

    let productInSearch = listProduct.find(
      (item) => item.itemid === Number(productId) && item.shopid === Number(shopId),
    );

    if (!productInSearch) {
      try {
        productInSearch = await asyncRetry(async () => {
          const product = this.searchData.list.find(
            (item) => item.itemid === Number(productId) && item.shopid === Number(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);

    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';
    }

    return [
      {
        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'};`,
      },
    ];
  }

  /**
   * @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 {
      this.createDataRow(rowDiv, item);
    }

    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
   */
  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 storageShopeeConfigProduct.getValue();
    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();
  }
}
