/* eslint-disable prefer-promise-reject-errors */
import delay from 'delay';
import { genUuid } from '@/lib/utils/utils';
import { CacheFetchUrl } from '@/plugins/store/cache';
import lodash from 'lodash';
import sha256 from 'sha256';
import { getKeyCookieNative } from '@/browser/cookies';

const waitForElement = async (selector, timeout = 5000) => {
  if (document.querySelector(selector)) {
    return document.querySelector(selector);
  }

  return new Promise((resolve, reject) => {
    setTimeout(() => reject('WAIT_ELEMENT_TIME_OUT'), timeout);

    const observer = new MutationObserver(() => {
      if (document.querySelector(selector)) {
        observer.disconnect();
        resolve(document.querySelector(selector));
      }
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true,
    });
  });
};

/**
 *
 * @param {string} fetchUrl
 * @param {RequestMethod} method
 * @param {object} postBody
 * @returns {Promise<object>}
 */
export const excuteFetchUrl = async (fetchUrl, method = 'GET', postBody = null) => {
  if (!fetchUrl) {
    throw 'MISSING_FETCH_URL';
  }

  const CacheUrl = new CacheFetchUrl(fetchUrl);

  if (method === 'GET') {
    const getCache = await CacheUrl.get();

    if (getCache) {
      return getCache;
    }
  }

  const isPostMethod = !!(method === 'POST' && postBody);

  const fetchId = isPostMethod ? genUuid() : sha256(fetchUrl).toString();

  const fetchElementId = `script-fetch-${fetchId}`;
  const contentElementId = `script-content-${fetchId}`;
  const contentElementQuery = `#${contentElementId}`;

  const delayTime = lodash.random(100, 500, false);
  const delayFetch = isPostMethod ? 2000 : 500;

  let scriptContent = document.querySelector(contentElementQuery);

  if (!scriptContent) {
    const csrftoken = getKeyCookieNative('csrftoken');

    const payloadHeader = {
      accept: 'application/json',
      'af-ac-enc-dat': null,
      'af-ac-enc-sz-token': null,
      'content-type': 'application/json',
      'cache-control': 'no-cache',
      priority: 'u=1, i',
      'sec-ch-ua-mobile': '?0',
      'sec-ch-ua-platform': '"Windows"',
      'sec-fetch-dest': 'empty',
      'sec-fetch-mode': 'cors',
      'sec-fetch-site': 'same-origin',
      'x-api-source': 'pc',
      'x-requested-with': 'XMLHttpRequest',
      'x-shopbff-version': '2',
      'x-shopee-language': 'vi',
      'x-sz-sdk-version': '1.12.15',
    };

    if (csrftoken) {
      payloadHeader['x-csrftoken'] = csrftoken;
    }

    const payloadFetch = {
      headers: payloadHeader,
      method: 'GET',
    };

    if (isPostMethod) {
      payloadFetch.method = 'POST';
      payloadFetch.body = JSON.stringify(postBody);
    }

    const fetchScript = `
        fetch('${fetchUrl}', ${JSON.stringify(payloadFetch)})
          .then((res) => res.json())
          .then((value) => {
              const script = document.createElement('script');
              script.type = type="application/json";
              script.id = '${contentElementId}';
              script.textContent = JSON.stringify(value);
              document.head.appendChild(script);
          })
          .catch(() => {
              const script = document.createElement('script');
              script.type = type="application/json";
              script.id = '${contentElementId}';
              script.textContent = JSON.stringify(null);
              document.head.appendChild(script);
          });

    `;

    const excuteScript = !isPostMethod
      ? fetchScript
      : `
      setTimeout(() => {
          ${fetchScript}
      }, ${delayTime})
    `;

    const scriptFetch = document.createElement('script');

    scriptFetch.type = 'application/javascript';
    scriptFetch.id = fetchElementId;
    scriptFetch.textContent = excuteScript;
    document.head.appendChild(scriptFetch);

    await delay(delayFetch);

    scriptFetch.remove();

    await waitForElement(contentElementQuery, 5000).catch(() => {});
  }

  scriptContent = document.querySelector(contentElementQuery);

  if (!scriptContent) {
    return null;
  }

  const fetchJson = JSON.parse(scriptContent.textContent);

  if (method === 'GET') {
    await CacheUrl.set(fetchJson);
  }

  return fetchJson;
};

export const fetchJson = async (url, headers = {}) => {
  const res = await fetch(url, {
    headers,
  });

  return res.json();
};

export const fetchHtml = async (url, headers = {}) => {
  const res = await fetch(url, {
    headers,
  });

  return res.text();
};
