const JSZip = require('jszip');

window.ExportHtml = Popup => {
  const saveAs = function(blob, filename) {
    const dl = document.createElement('a');
    dl.href = window.URL.createObjectURL(blob);
    dl.onclick = event => document.body.removeChild(event.target);
    dl.style.display = 'none';
    dl.target = '_blank';
    dl.download = filename;
    document.body.appendChild(dl);
    dl.click();
  };

  const asyncForEach = async function(array, callback) {
    for (let index = 0; index < array.length; index++) {
      await callback(array[index], index, array);
    }
  };

  const getPageHtmlString = () => {
    return `<!doctype html>${window.document.querySelector('html').outerHTML}`;
  };

  const removeAnchors = htmlString => {
    const replaceOpenAnchor = htmlString.replace(
      new RegExp('<a ', 'gim'),
      '<span ',
    );
    return replaceOpenAnchor.replace(new RegExp('</a', 'gim'), '</span');
  };

  const ensureSidebarRemoved = () => {
    document.querySelector('.board-sidebar.sidebar').remove();
  };

  const addJsonExportToZip = async (zip, boardSlug) => {
    const downloadJSONLink = document.querySelector('.download-json-link');
    const downloadJSONURL = downloadJSONLink.href;
    const response = await fetch(downloadJSONURL);
    const responseBody = await response.text();
    zip.file(`data/${boardSlug}.json`, responseBody);
  };

  const closeSidebar = () => {
    document.querySelector('.board-header-btn.js-toggle-sidebar').click();
  };

  const cleanBoardHtml = () => {
    Array.from(document.querySelectorAll('script')).forEach(elem =>
      elem.remove(),
    );
    Array.from(
      document.querySelectorAll('link:not([rel="stylesheet"])'),
    ).forEach(elem => elem.remove());
    document.querySelector('#header-quick-access').remove();
    Array.from(
      document.querySelectorAll('#header-main-bar .board-header-btns'),
    ).forEach(elem => elem.remove());
    Array.from(
      document.querySelectorAll('.js-pop-over, .pop-over'),
    ).forEach(elem => elem.remove());
    Array.from(document.querySelectorAll('.list-composer')).forEach(elem =>
      elem.remove(),
    );
    Array.from(
      document.querySelectorAll(
        '.list-composer,.js-card-composer, .js-add-card',
      ),
    ).forEach(elem => elem.remove());
    Array.from(document.querySelectorAll('[href]:not(link)')).forEach(elem =>
      elem.attributes.removeNamedItem('href'),
    );
    Array.from(document.querySelectorAll('[href]')).forEach(elem => {
      // eslint-disable-next-line no-self-assign
      elem.href = elem.href;
      // eslint-disable-next-line no-self-assign
      elem.src = elem.src;
    });
    Array.from(document.querySelectorAll('.is-editable')).forEach(elem => {
      elem.classList.remove('is-editable');
    });
  };

  const getBoardSlug = () => {
    return window.location.href.split('/').pop();
  };

  const getStylesheetList = () => {
    return Array.from(
      document.querySelectorAll('link[href][rel="stylesheet"]'),
    );
  };

  const downloadStylesheets = async (stylesheets, zip) => {
    await asyncForEach(stylesheets, async elem => {
      const response = await fetch(elem.href);
      const responseBody = await response.text();

      const finalResponse = responseBody.replace(
        new RegExp('packages/[^/]+/upstream/', 'gim'),
        '../',
      );

      const filename = elem.href
        .split('/')
        .pop()
        .split('?')
        .shift();
      const fileFullPath = `style/${filename}`;
      zip.file(fileFullPath, finalResponse);
      elem.href = `../${fileFullPath}`;
    });
  };

  const getSrcAttached = () => {
    return Array.from(document.querySelectorAll('[src]'));
  };

  const downloadSrcAttached = async (elements, zip, boardSlug) => {
    await asyncForEach(elements, async elem => {
      const response = await fetch(elem.src);
      const responseBody = await response.blob();
      const filename = elem.src
        .split('/')
        .pop()
        .split('?')
        .shift();
      const fileFullPath = `${boardSlug}/${elem.tagName.toLowerCase()}/${filename}`;
      zip.file(fileFullPath, responseBody);
      elem.src = `./${elem.tagName.toLowerCase()}/${filename}`;
    });
  };

  const removeCssUrlSurround = url => {
    const working = url || '';
    return working
      .split('url(')
      .join('')
      .split('")')
      .join('')
      .split('"')
      .join('')
      .split("')")
      .join('')
      .split("'")
      .join('')
      .split(')')
      .join('');
  };

  const getCardCovers = () => {
    return Array.from(document.querySelectorAll('.minicard-cover')).filter(
      elem => elem.style['background-image'],
    );
  };

  const getWebFonts = () => {
    fontUrls = [];

    for (let sheet of document.styleSheets) {
      // Get the base URL of the stylesheet
      let baseUrl = sheet.href ? new URL(sheet.href).origin : window.location.origin;

      try {
        for (let rule of sheet.cssRules) {
          if (rule.type === CSSRule.FONT_FACE_RULE) {
            let src = rule.style.getPropertyValue('src');
            let urlMatch = src.match(/url\(["']?(.+?)["']?\)/);
            if (urlMatch) {
              let fontUrl = urlMatch[1];

              // Resolve the URL relative to the stylesheet's base URL
              let resolvedUrl = new URL(fontUrl, baseUrl);
              fontUrls.push(resolvedUrl.href); // Using .href to get the absolute URL
            }
          }
        }
      } catch (e) {
          console.log('Access to stylesheet blocked:', e);
      }
    }

    return fontUrls;
  };

  const downloadFonts = async(elements, zip) => {
    await asyncForEach(elements, async elem => {
      const response = await fetch(elem);
      const responseBody = await response.blob();
      const filename = elem.split('/')
        .pop()
        .split('?')
        .shift()
        .split('#')
        .shift();
      const fileFullPath = `webfonts/${filename}`;
        zip.file(fileFullPath, responseBody);
    });
  }

  const downloadCardCovers = async (elements, zip, boardSlug) => {
    await asyncForEach(elements, async elem => {
      const response = await fetch(
        removeCssUrlSurround(elem.style['background-image']),
      );
      const responseBody = await response.blob();
      const filename = removeCssUrlSurround(elem.style['background-image'])
        .split('/')
        .pop()
        .split('?')
        .shift()
        .split('#')
        .shift();
      const fileFullPath = `${boardSlug}/covers/${filename}`;
      zip.file(fileFullPath, responseBody);
      elem.style = "background-image: url('" + `covers/${filename}` + "')";
    });
  };

  const addBoardHTMLToZip = (boardSlug, zip) => {
    ensureSidebarRemoved();
    const htmlOutputPath = `${boardSlug}/index.html`;
    zip.file(
      htmlOutputPath,
      new Blob([removeAnchors(getPageHtmlString())], {
        type: 'application/html',
      }),
    );
  };

  return async () => {
    const zip = new JSZip();
    const boardSlug = getBoardSlug();

    await addJsonExportToZip(zip, boardSlug);
    Popup.back();
    closeSidebar();
    cleanBoardHtml();

    await downloadStylesheets(getStylesheetList(), zip);
    await downloadSrcAttached(getSrcAttached(), zip, boardSlug);
    await downloadCardCovers(getCardCovers(), zip, boardSlug);
    await downloadFonts(getWebFonts(), zip);

    addBoardHTMLToZip(boardSlug, zip);

    const content = await zip.generateAsync({ type: 'blob' });
    saveAs(content, `${boardSlug}.zip`);
    window.location.reload();
  };
};
