<template>
  <div>
    <USlideover v-model="isOpen" :ui="{ width: 'max-w-[720px]' }">
      <HtmlRenderer :html="articleHtml" v-model:show="isOpen" />
    </USlideover>
  </div>
</template>

<script setup lang="ts">
import { parseCgiDataNew } from '#shared/utils/html';
import { renderHTMLFromCgiDataNew } from '#shared/utils/renderer';
import HtmlRenderer from '~/components/preview/HtmlRenderer.vue';
import toastFactory from '~/composables/toast';
import usePreferences from '~/composables/usePreferences';
import { getHtmlCache, type HtmlAsset } from '~/store/v2/html';
import { getMetadataCache } from '~/store/v2/metadata';
import type { Preferences } from '~/types/preferences';
import type { AppMsgEx } from '~/types/types';
import { renderComments } from '~/utils/comment';

defineExpose({
  open: open,
});

const toast = toastFactory();

const isOpen = ref(false);
const articleHtml = ref('');

async function open(article: AppMsgEx) {
  const htmlAsset = await getHtmlCache(article.link);
  if (htmlAsset) {
    isOpen.value = true;
    const rawHtml = await htmlAsset.file.text();
    const cgiData = await parseCgiDataNew(rawHtml);
    console.log(cgiData);

    // articleHtml.value = await normalizeHtmlForPreview(htmlAsset, rawHtml);
    articleHtml.value = await renderHTMLFromCgiDataNew(
      cgiData,
      (preferences.value as Preferences).exportConfig.exportHtmlIncludeComments
    );
  } else {
    toast.warning('文章预览失败', `文章【${article.title}】还未拉取文章内容`);
  }
}

const preferences: Ref<Preferences> = usePreferences() as unknown as Ref<Preferences>;

// 调整最终的 html
async function normalizeHtmlForPreview(cachedHtml: HtmlAsset, html: string): Promise<string> {
  const parser = new DOMParser();
  const document = parser.parseFromString(html, 'text/html');
  const $jsArticleContent = document.querySelector('#js_article')!;

  // #js_content 默认是不可见的(通过js修改为可见)，需要移除该样式
  $jsArticleContent.querySelector('#js_content')?.removeAttribute('style');

  // 删除无用dom元素
  $jsArticleContent.querySelector('#js_top_ad_area')?.remove();
  $jsArticleContent.querySelector('#js_tags_preview_toast')?.remove();
  $jsArticleContent.querySelector('#content_bottom_area')?.remove();
  $jsArticleContent.querySelectorAll('script').forEach(el => {
    el.remove();
  });
  $jsArticleContent.querySelector('#js_pc_qr_code')?.remove();
  $jsArticleContent.querySelector('#wx_stream_article_slide_tip')?.remove();

  let bodyCls = document.body.className;

  // 渲染发布时间
  function __setPubTime(oriTimestamp: number, dom: HTMLElement) {
    const dateObj = new Date(oriTimestamp * 1000);
    const padStart = function padStart(v: number) {
      return '0'.concat(v.toString()).slice(-2);
    };
    const year = dateObj.getFullYear().toString();
    const month = padStart(dateObj.getMonth() + 1);
    const date = padStart(dateObj.getDate());
    const hour = padStart(dateObj.getHours());
    const minute = padStart(dateObj.getMinutes());
    const timeString = ''.concat(hour, ':').concat(minute);
    const dateString = ''.concat(year, '年').concat(month, '月').concat(date, '日');
    const showDate = ''.concat(dateString, ' ').concat(timeString);

    if (dom) {
      dom.innerText = showDate;
    }
  }
  const pubTimeMatchResult = html.match(/var oriCreateTime = '(?<date>\d+)'/);
  if (pubTimeMatchResult && pubTimeMatchResult.groups && pubTimeMatchResult.groups.date) {
    __setPubTime(parseInt(pubTimeMatchResult.groups.date), document.getElementById('publish_time')!);
  }

  // 渲染ip属地
  function getIpWoridng(ipConfig: any) {
    let ipWording = '';
    if (parseInt(ipConfig.countryId, 10) === 156) {
      ipWording = ipConfig.provinceName;
    } else if (ipConfig.countryId) {
      ipWording = ipConfig.countryName;
    }
    return ipWording;
  }
  const ipWrp = document.getElementById('js_ip_wording_wrp')!;
  const ipWording = document.getElementById('js_ip_wording')!;
  const ipWordingMatchResult = html.match(/window\.ip_wording = (?<data>{\s+countryName: '[^']+',[^}]+})/s);
  if (ipWrp && ipWording && ipWordingMatchResult && ipWordingMatchResult.groups && ipWordingMatchResult.groups.data) {
    const json = ipWordingMatchResult.groups.data;
    eval('window.ip_wording = ' + json);
    const ipWordingDisplay = getIpWoridng((window as any).ip_wording);
    if (ipWordingDisplay !== '') {
      ipWording.innerHTML = ipWordingDisplay;
      ipWrp.style.display = 'inline-block';
    }
  }

  // 渲染 标题已修改
  function __setTitleModify(isTitleModified: boolean) {
    const wrp = document.getElementById('js_title_modify_wrp')!;
    const titleModifyNode = document.getElementById('js_title_modify')!;
    if (!wrp) return;
    if (isTitleModified) {
      titleModifyNode.innerHTML = '标题已修改';
      wrp.style.display = 'inline-block';
    } else {
      wrp.parentNode?.removeChild(wrp);
    }
  }
  const titleModifiedMatchResult = html.match(/window\.isTitleModified = "(?<data>\d*)" \* 1;/);
  if (titleModifiedMatchResult && titleModifiedMatchResult.groups && titleModifiedMatchResult.groups.data) {
    __setTitleModify(titleModifiedMatchResult.groups.data === '1');
  }

  // 文章引用
  const js_share_source = document.getElementById('js_share_source');
  const contentTpl = document.getElementById('content_tpl');
  if (js_share_source && contentTpl) {
    const html = contentTpl.innerHTML
      .replace(/<img[^>]*>/g, '<p>[图片]</p>')
      .replace(
        /<iframe [^>]*?class=\"res_iframe card_iframe js_editor_card\"[^>]*?data-cardid=[\'\"][^\'\"]*[^>]*?><\/iframe>/gi,
        '<p>[卡券]</p>'
      )
      .replace(/<mpvoice([^>]*?)js_editor_audio([^>]*?)><\/mpvoice>/g, '<p>[语音]</p>')
      .replace(/<mpgongyi([^>]*?)js_editor_gy([^>]*?)><\/mpgongyi>/g, '<p>[公益]</p>')
      .replace(/<qqmusic([^>]*?)js_editor_qqmusic([^>]*?)><\/qqmusic>/g, '<p>[音乐]</p>')
      .replace(/<mpshop([^>]*?)js_editor_shop([^>]*?)><\/mpshop>/g, '<p>[小店]</p>')
      .replace(/<iframe([^>]*?)class=[\'\"][^\'\"]*video_iframe([^>]*?)><\/iframe>/g, '<p>[视频]</p>')
      .replace(/(<iframe[^>]*?js_editor_vote_card[^<]*?<\/iframe>)/gi, '<p>[投票]</p>')
      .replace(/<mp-weapp([^>]*?)weapp_element([^>]*?)><\/mp-weapp>/g, '<p>[小程序]</p>')
      .replace(/<mp-miniprogram([^>]*?)><\/mp-miniprogram>/g, '<p>[小程序]</p>')
      .replace(/<mpproduct([^>]*?)><\/mpproduct>/g, '<p>[商品]</p>')
      .replace(/<mpcps([^>]*?)><\/mpcps>/g, '<p>[商品]</p>');
    const div = document.createElement('div');
    div.innerHTML = html;
    let content = div.innerText;
    content = content.replace(/</g, '&lt;').replace(/>/g, '&gt;').trim();
    if (content.length > 140) {
      content = content.substr(0, 140) + '...';
    }
    const digest = content.split('\n').map(function (line) {
      return '<p>' + line + '</p>';
    });
    document.getElementById('js_content')!.innerHTML = digest.join('');

    // 替换url
    const sourceURL = js_share_source.getAttribute('data-url');
    if (sourceURL) {
      const link = document.createElement('a');
      link.href = sourceURL;
      link.className = js_share_source.className;
      link.innerHTML = js_share_source.innerHTML;
      js_share_source.replaceWith(link);
    }
  }

  // 渲染阅读量
  const metadata = await getMetadataCache(cachedHtml.url);
  const $interaction_bar = document.querySelector('#js_article_bottom_bar .interaction_bar');
  if ($interaction_bar) {
    $interaction_bar.insertAdjacentHTML(
      'afterbegin',
      '<button id="js_temp_sns_sc_readnum_btn" aria-labelledby="js_a11y_zan_btn_txt readNum" style="-webkit-text-size-adjust:  100% ;" class="sns_opr_btn sns_view_btn weui-wa-hotarea js_wx_tap_highlight wx_tap_link">' +
        `<span class="sns_opr_gap" aria-hidden="true" id="js_bar_readnum_btn">${metadata?.readNum}</span></button>`
    );
  }

  // 渲染留言
  let commentHTML = '';
  if ((preferences.value as Preferences).exportConfig.exportHtmlIncludeComments) {
    commentHTML = await renderComments(cachedHtml.url);
  }

  // 文本分享消息
  const $js_text_desc = $jsArticleContent.querySelector('#js_text_desc') as HTMLElement | null;
  if ($js_text_desc) {
    // 文本分享页面的 body 额外样式
    bodyCls += ' page_share_text';

    // 顶部作者栏
    const qmtplTextMatchResult = html.match(/(?<code>window\.__QMTPL_SSR_DATA__\s*=\s*\{.+?};)/s);
    if (qmtplTextMatchResult && qmtplTextMatchResult.groups && qmtplTextMatchResult.groups.code) {
      const code = qmtplTextMatchResult.groups.code;
      // eslint-disable-next-line no-eval
      eval(code);
      const data = (window as any).__QMTPL_SSR_DATA__;
      if (data && typeof data.title === 'string' && !$js_text_desc.innerHTML.trim()) {
        let text = data.title as string;
        text = text.replace(/\r/g, '').replace(/\n/g, '<br>');
        $js_text_desc.innerHTML = text;
      }
      $jsArticleContent.querySelector('#js_top_profile')?.classList.remove('profile_area_hide');
    }

    // 正文内容
    if (!$js_text_desc.innerHTML.trim()) {
      const textContentMatch = html.match(
        /var\s+TextContentNoEncode\s*=\s*window\.a_value_which_never_exists\s*\|\|\s*(?<value>'[^']*')/s
      );
      const contentMatch = html.match(
        /var\s+ContentNoEncode\s*=\s*window\.a_value_which_never_exists\s*\|\|\s*(?<value>'[^']*')/s
      );

      let desc: string | null = null;
      const assignFromMatch = (match: RegExpMatchArray | null, key: string) => {
        if (match && match.groups && match.groups.value) {
          const code = `window.${key} = ${match.groups.value}`;
          // eslint-disable-next-line no-eval
          eval(code);
          // @ts-ignore
          return (window as any)[key] as string;
        }
        return null;
      };

      desc = assignFromMatch(textContentMatch, '__WX_TEXT_NO_ENCODE__');
      if (!desc) {
        desc = assignFromMatch(contentMatch, '__WX_CONTENT_NO_ENCODE__');
      }

      if (desc) {
        desc = desc.replace(/\r/g, '').replace(/\n/g, '<br>');
        $js_text_desc.innerHTML = desc;
      }
    }
  }

  // 图片分享消息
  const $js_image_desc = $jsArticleContent.querySelector('#js_image_desc');
  if ($js_image_desc) {
    bodyCls += 'pages_skin_pc page_share_img';

    function decode_html(data: string, encode: boolean) {
      const replace = [
        '&#39;',
        "'",
        '&quot;',
        '"',
        '&nbsp;',
        ' ',
        '&gt;',
        '>',
        '&lt;',
        '<',
        '&yen;',
        '¥',
        '&amp;',
        '&',
      ];
      const replaceReverse = [
        '&',
        '&amp;',
        '¥',
        '&yen;',
        '<',
        '&lt;',
        '>',
        '&gt;',
        ' ',
        '&nbsp;',
        '"',
        '&quot;',
        "'",
        '&#39;',
      ];

      let target = encode ? replaceReverse : replace;
      let str = data;
      for (let i = 0; i < target.length; i += 2) {
        str = str.replace(new RegExp(target[i], 'g'), target[i + 1]);
      }
      return str;
    }

    const qmtplMatchResult = html.match(/(?<code>window\.__QMTPL_SSR_DATA__\s*=\s*\{.+?)<\/script>/s);
    if (qmtplMatchResult && qmtplMatchResult.groups && qmtplMatchResult.groups.code) {
      const code = qmtplMatchResult.groups.code;
      eval(code);
      const data = (window as any).__QMTPL_SSR_DATA__;
      let desc = data.desc.replace(/\r/g, '').replace(/\n/g, '<br>').replace(/\s/g, '&nbsp;');
      desc = decode_html(desc, false);
      $js_image_desc.innerHTML = desc;

      $jsArticleContent.querySelector('#js_top_profile')!.classList.remove('profile_area_hide');
    }
    const pictureMatchResult = html.match(/(?<code>window\.picture_page_info_list\s*=.+\.slice\(0,\s*20\);)/s);
    if (pictureMatchResult && pictureMatchResult.groups && pictureMatchResult.groups.code) {
      const code = pictureMatchResult.groups.code;
      eval(code);
      const picture_page_info_list = (window as any).picture_page_info_list;
      const containerEl = $jsArticleContent.querySelector('#js_share_content_page_hd')!;
      let innerHTML =
        '<div style="display: flex;flex-direction: column;align-items: center;gap: 10px;padding-block: 20px;">';
      for (const picture of picture_page_info_list) {
        innerHTML += `<img src="${picture.cdn_url}" alt="" style="display: block;border: 1px solid gray;border-radius: 5px;max-width: 90%;" onclick="window.open(this.src, '_blank', 'popup')" />`;
      }
      innerHTML += '</div>';
      containerEl.innerHTML = innerHTML;
    }
  }

  // 去除图片的懒加载
  const imgs = document.querySelectorAll<HTMLImageElement>('img');
  for (const img of imgs) {
    const imgUrl = img.getAttribute('src') || img.getAttribute('data-src');
    if (imgUrl) {
      img.src = imgUrl;
    }
  }

  // 所有图片都替换完成后，重新解析得到最终的主内容和bottom内容
  const newDocument = parser.parseFromString(document.documentElement.outerHTML, 'text/html');
  const pageContentHTML = newDocument.querySelector('#js_article')!.outerHTML;
  const jsArticleBottomBarHTML = newDocument.querySelector('#js_article_bottom_bar')?.outerHTML;

  return `<!DOCTYPE html>
<html lang="zh_CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0,viewport-fit=cover">
    <meta name="referrer" content="no-referrer">
    <title>${cachedHtml.title}</title>
    <style>
        #page-content,
        #js_article_bottom_bar,
        .__page_content__ {
            max-width: 667px;
            margin: 0 auto;
        }
        img {
            max-width: 100%;
        }
        .sns_opr_btn::before {
            width: 16px;
            height: 16px;
            margin-right: 3px;
        }
    </style>
</head>
<body class="${bodyCls}">
${pageContentHTML}
${jsArticleBottomBarHTML}

<!-- 评论数据 -->
${commentHTML}
</body>
</html>`;
}
</script>
