<script setup lang="ts">
import { computed, nextTick, onUnmounted, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { Marked } from 'marked';
import hljs from 'highlight.js';
import DOMPurify from 'dompurify';
import { ElDrawer } from 'element-plus';
import { useDesignStore } from '@/stores';

interface Props {
  content: string;
  theme?: 'light' | 'dark' | 'auto';
}

const props = withDefaults(defineProps<Props>(), {
  content: '',
  theme: 'auto',
});

const designStore = useDesignStore();
const { darkMode } = storeToRefs(designStore);
const containerRef = ref<HTMLElement | null>(null);
const renderedHtml = ref('');

// 抽屉相关状态
const drawerVisible = ref(false);
const previewHtml = ref('');
const iframeRef = ref<HTMLIFrameElement | null>(null);

// 创建 marked 实例
const marked = new Marked();

// 配置 marked
marked.setOptions({
  gfm: true,
  breaks: true,
});

// 自定义渲染器
const renderer = {
  // 代码块渲染
  code(token: { text: string; lang?: string }) {
    const { text, lang } = token;
    const language = lang && hljs.getLanguage(lang) ? lang : 'plaintext';
    const validLanguage = hljs.getLanguage(language) ? language : 'plaintext';

    let highlighted: string;
    try {
      highlighted = hljs.highlight(text, { language: validLanguage, ignoreIllegals: true }).value;
    } catch {
      highlighted = hljs.highlightAuto(text).value;
    }

    const langLabel = lang || 'code';

    // 生成行号
    const lines = text.split('\n');
    const lineNumbers = lines.map((_, i) => `<span class="line-number">${i + 1}</span>`).join('');

    // 判断是否为HTML代码
    const isHtml = lang?.toLowerCase() === 'html' || lang?.toLowerCase() === 'htm';

    // 预览按钮（仅HTML显示）
    const previewBtn = isHtml ? `
      <button class="preview-btn" data-html="${encodeURIComponent(text)}">
        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
          <circle cx="12" cy="12" r="3"></circle>
        </svg>
        <span>预览</span>
      </button>
    ` : '';

    return `<div class="code-block-wrapper${isHtml ? ' is-html' : ''}">
      <div class="code-block-header">
        <span class="code-lang">${langLabel}</span>
        <div class="code-block-actions">
          ${previewBtn}
          <button class="copy-btn" data-code="${encodeURIComponent(text)}">
            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
              <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
            </svg>
            <span>复制</span>
          </button>
        </div>
      </div>
      <div class="code-block-body">
        <div class="line-numbers">${lineNumbers}</div>
        <pre class="hljs"><code class="language-${validLanguage}">${highlighted}</code></pre>
      </div>
    </div>`;
  },

  // 行内代码
  codespan(token: { text: string }) {
    return `<code class="inline-code">${token.text}</code>`;
  },

  // 链接
  link(token: { href: string; title?: string; text: string }) {
    const { href, title, text } = token;
    const titleAttr = title ? ` title="${title}"` : '';
    return `<a href="${href}"${titleAttr} target="_blank" rel="noopener noreferrer">${text}</a>`;
  },

  // 图片
  image(token: { href: string; title?: string; text: string }) {
    const { href, title, text } = token;
    const titleAttr = title ? ` title="${title}"` : '';
    return `<img src="${href}" alt="${text}"${titleAttr} loading="lazy" class="markdown-image" />`;
  },
};

marked.use({ renderer });

// 防抖渲染，优化流式性能
let renderTimer: ReturnType<typeof setTimeout> | null = null;
let lastContent = '';
const RENDER_DELAY = 16; // 约60fps

function scheduleRender(content: string) {
  if (renderTimer) {
    clearTimeout(renderTimer);
  }

  renderTimer = setTimeout(() => {
    renderContent(content);
    renderTimer = null;
  }, RENDER_DELAY);
}

// 渲染内容
async function renderContent(content: string) {
  if (!content) {
    renderedHtml.value = '';
    return;
  }

  // 如果内容没变化，跳过渲染
  if (content === lastContent) {
    return;
  }
  lastContent = content;

  try {
    let rawHtml = await marked.parse(content);
    // 包装表格，添加 table-wrapper 以支持横向滚动
    rawHtml = rawHtml.replace(/<table>/g, '<div class="table-wrapper"><table>');
    rawHtml = rawHtml.replace(/<\/table>/g, '</table></div>');
    // 使用 DOMPurify 清理 HTML，防止 XSS
    renderedHtml.value = DOMPurify.sanitize(rawHtml, {
      ADD_TAGS: ['iframe'],
      ADD_ATTR: ['target', 'data-code', 'data-html'],
    });

    // 渲染后绑定按钮事件
    nextTick(() => {
      bindButtons();
    });
  } catch (error) {
    console.error('Markdown 渲染错误:', error);
    renderedHtml.value = `<pre>${content}</pre>`;
  }
}

// 绑定按钮事件
function bindButtons() {
  if (!containerRef.value) return;

  // 绑定复制按钮
  const copyButtons = containerRef.value.querySelectorAll('.copy-btn');
  copyButtons.forEach((btn) => {
    const newBtn = btn.cloneNode(true) as HTMLElement;
    btn.parentNode?.replaceChild(newBtn, btn);

    newBtn.addEventListener('click', async (e) => {
      e.preventDefault();
      e.stopPropagation();

      const code = decodeURIComponent(newBtn.getAttribute('data-code') || '');
      try {
        await navigator.clipboard.writeText(code);
        const spanEl = newBtn.querySelector('span');
        if (spanEl) {
          const originalText = spanEl.textContent;
          spanEl.textContent = '已复制';
          newBtn.classList.add('copied');
          setTimeout(() => {
            spanEl.textContent = originalText;
            newBtn.classList.remove('copied');
          }, 2000);
        }
      } catch (err) {
        console.error('复制失败:', err);
      }
    });
  });

  // 绑定预览按钮
  const previewButtons = containerRef.value.querySelectorAll('.preview-btn');
  previewButtons.forEach((btn) => {
    const newBtn = btn.cloneNode(true) as HTMLElement;
    btn.parentNode?.replaceChild(newBtn, btn);

    newBtn.addEventListener('click', (e) => {
      e.preventDefault();
      e.stopPropagation();

      const html = decodeURIComponent(newBtn.getAttribute('data-html') || '');
      openHtmlPreview(html);
    });
  });
}

// 打开HTML预览抽屉
function openHtmlPreview(html: string) {
  // 检查是否是完整的HTML文档，如果不是则包装一下
  let fullHtml = html;
  if (!html.toLowerCase().includes('<!doctype') && !html.toLowerCase().includes('<html')) {
    fullHtml = `<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>* { box-sizing: border-box; } body { margin: 0; padding: 16px; font-family: sans-serif; }</style>
</head>
<body>
${html}
</body>
</html>`;
  }
  previewHtml.value = fullHtml;
  drawerVisible.value = true;
}

// 监听主题变化
const resolvedTheme = computed(() => {
  if (props.theme === 'auto') {
    // 从全局状态获取主题
    return darkMode.value === 'light' ? 'light' : 'dark';
  }
  return props.theme;
});

// 监听内容变化
watch(
  () => props.content,
  (newContent) => {
    scheduleRender(newContent);
  },
  { immediate: true }
);

// 暴露方法供外部调用
defineExpose({
  refresh: () => renderContent(props.content),
});

// 清理定时器
onUnmounted(() => {
  if (renderTimer) {
    clearTimeout(renderTimer);
  }
});
</script>

<template>
  <div
    ref="containerRef"
    class="marked-markdown"
    :class="[`theme-${resolvedTheme}`]"
    v-html="renderedHtml"
  />

  <!-- HTML预览抽屉 -->
  <ElDrawer
    v-model="drawerVisible"
    title="HTML 预览"
    direction="rtl"
    size="50%"
    :append-to-body="true"
    class="html-preview-drawer"
  >
    <div class="preview-container">
      <iframe
        ref="iframeRef"
        class="preview-iframe"
        :srcdoc="previewHtml"
        sandbox="allow-scripts allow-modals allow-forms allow-popups allow-same-origin"
      />
    </div>
  </ElDrawer>
</template>

<style lang="scss">
.marked-markdown {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
  font-size: 15px;
  line-height: 1.7;
  word-wrap: break-word;
  overflow-wrap: break-word;

  // 深色主题
  &.theme-dark {
    color: #e6edf3;

    a {
      color: #58a6ff;
      &:hover {
        text-decoration: underline;
      }
    }

    h1, h2, h3, h4, h5, h6 {
      color: #e6edf3;
      border-bottom-color: #30363d;
    }

    hr {
      background-color: #30363d;
    }

    blockquote {
      color: #8b949e;
      border-left-color: #3b434b;
    }

    code.inline-code {
      background-color: rgba(110, 118, 129, 0.4);
      color: #e6edf3;
    }

    .code-block-wrapper {
      background-color: #161b22;
      border: 1px solid #30363d;

      .code-block-header {
        background-color: #21262d;
        border-bottom-color: #30363d;

        .code-lang {
          color: #8b949e;
        }

        .copy-btn,
        .preview-btn {
          color: #8b949e;
          &:hover {
            color: #e6edf3;
            background-color: #30363d;
          }
          &.copied {
            color: #3fb950;
          }
        }
      }

      .code-block-body {
        .line-numbers {
          background-color: #161b22;
          border-right: 1px solid #30363d;

          .line-number {
            color: #6e7681;
          }
        }
      }

      pre.hljs {
        background-color: #161b22;
      }
    }

    table {
      th {
        background-color: #21262d;
      }
      td, th {
        border-color: #30363d;
      }
      tr:nth-child(2n) {
        background-color: #161b22;
      }
    }

    .markdown-image {
      background-color: transparent;
    }
  }

  // 浅色主题
  &.theme-light {
    color: #24292f;

    a {
      color: #0969da;
      &:hover {
        text-decoration: underline;
      }
    }

    h1, h2, h3, h4, h5, h6 {
      color: #24292f;
      border-bottom-color: #d0d7de;
    }

    hr {
      background-color: #d0d7de;
    }

    blockquote {
      color: #57606a;
      border-left-color: #d0d7de;
    }

    code.inline-code {
      background-color: rgba(175, 184, 193, 0.2);
      color: #24292f;
    }

    .code-block-wrapper {
      background-color: #f6f8fa;
      border: 1px solid #d0d7de;

      .code-block-header {
        background-color: #f6f8fa;
        border-bottom-color: #d0d7de;

        .code-lang {
          color: #57606a;
        }

        .copy-btn,
        .preview-btn {
          color: #57606a;
          &:hover {
            color: #24292f;
            background-color: #d0d7de;
          }
          &.copied {
            color: #1a7f37;
          }
        }
      }

      .code-block-body {
        .line-numbers {
          background-color: #f6f8fa;
          border-right: 1px solid #d0d7de;

          .line-number {
            color: #8c959f;
          }
        }
      }

      pre.hljs {
        background-color: #f6f8fa;
      }
    }

    table {
      th {
        background-color: #f6f8fa;
      }
      td, th {
        border-color: #d0d7de;
      }
      tr:nth-child(2n) {
        background-color: #f6f8fa;
      }
    }
  }

  // 通用样式
  > *:first-child {
    margin-top: 0 !important;
  }

  > *:last-child {
    margin-bottom: 0 !important;
  }

  // 标题
  h1, h2, h3, h4, h5, h6 {
    margin-top: 24px;
    margin-bottom: 16px;
    font-weight: 600;
    line-height: 1.25;
  }

  h1 {
    font-size: 2em;
    padding-bottom: 0.3em;
    border-bottom: 1px solid;
  }

  h2 {
    font-size: 1.5em;
    padding-bottom: 0.3em;
    border-bottom: 1px solid;
  }

  h3 {
    font-size: 1.25em;
  }

  h4 {
    font-size: 1em;
  }

  h5 {
    font-size: 0.875em;
  }

  h6 {
    font-size: 0.85em;
  }

  // 段落
  p {
    margin-top: 0;
    margin-bottom: 16px;
  }

  // 列表
  ul, ol {
    padding-left: 2em;
    margin-top: 0;
    margin-bottom: 16px;
  }

  li {
    margin-top: 0.25em;
  }

  li + li {
    margin-top: 0.25em;
  }

  // 引用
  blockquote {
    margin: 0 0 16px 0;
    padding: 0 1em;
    border-left: 0.25em solid;

    > :first-child {
      margin-top: 0;
    }

    > :last-child {
      margin-bottom: 0;
    }
  }

  // 分割线
  hr {
    height: 0.25em;
    padding: 0;
    margin: 24px 0;
    border: 0;
  }

  // 行内代码
  code.inline-code {
    padding: 0.2em 0.4em;
    margin: 0;
    font-size: 85%;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    border-radius: 6px;
  }

  // 代码块
  .code-block-wrapper {
    margin: 16px 0;
    border-radius: 8px;
    overflow: hidden;

    .code-block-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 8px 16px;
      border-bottom: 1px solid;

      .code-lang {
        font-size: 12px;
        font-weight: 500;
        text-transform: uppercase;
      }

      .code-block-actions {
        display: flex;
        align-items: center;
        gap: 8px;
      }

      .copy-btn,
      .preview-btn {
        display: flex;
        align-items: center;
        gap: 4px;
        padding: 4px 8px;
        font-size: 12px;
        background: transparent;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        transition: all 0.2s ease;

        svg {
          flex-shrink: 0;
        }
      }
    }

    .code-block-body {
      display: flex;
      overflow-x: auto;

      // 自定义滚动条样式
      &::-webkit-scrollbar {
        height: 6px;
      }
      &::-webkit-scrollbar-track {
        background: transparent;
      }
      &::-webkit-scrollbar-thumb {
        background-color: rgba(128, 128, 128, 0.4);
        border-radius: 3px;
        &:hover {
          background-color: rgba(128, 128, 128, 0.6);
        }
      }

      .line-numbers {
        display: flex;
        flex-direction: column;
        padding: 16px 0;
        text-align: right;
        user-select: none;
        flex-shrink: 0;

        .line-number {
          padding: 0 12px;
          font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
          font-size: 14px;
          //line-height: 21px;
          height: 22px;
          min-width: 40px;
        }
      }
    }

    pre.hljs {
      margin: 0;
      padding: 16px;
      padding-left: 12px;
      overflow-x: auto;
      font-size: 14px;
      line-height: 21px;
      flex: 1;
      white-space: pre;

      code {
        font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
        background: transparent;
        padding: 0;
        white-space: pre;
      }
    }
  }

  // 表格
  .table-wrapper {
    overflow-x: auto;
    margin: 16px 0;
  }

  table {
    border-spacing: 0;
    border-collapse: collapse;
    width: 100%;

    th, td {
      padding: 8px 16px;
      border: 1px solid;
    }

    th {
      font-weight: 600;
      text-align: left;
    }
  }

  // 图片
  .markdown-image {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
    margin: 8px 0;
  }

  // 强调
  strong {
    font-weight: 600;
  }

  em {
    font-style: italic;
  }

  // 删除线
  del {
    text-decoration: line-through;
  }

  // 任务列表
  input[type="checkbox"] {
    margin-right: 0.5em;
  }
}

// highlight.js 深色主题样式
.marked-markdown.theme-dark {
  .hljs {
    color: #c9d1d9;
  }
  .hljs-comment,
  .hljs-quote {
    color: #8b949e;
    font-style: italic;
  }
  .hljs-keyword,
  .hljs-selector-tag,
  .hljs-addition {
    color: #ff7b72;
  }
  .hljs-number,
  .hljs-string,
  .hljs-meta .hljs-meta-string,
  .hljs-literal,
  .hljs-doctag,
  .hljs-regexp {
    color: #a5d6ff;
  }
  .hljs-title,
  .hljs-section,
  .hljs-name,
  .hljs-selector-id,
  .hljs-selector-class {
    color: #d2a8ff;
  }
  .hljs-attribute,
  .hljs-attr,
  .hljs-variable,
  .hljs-template-variable,
  .hljs-class .hljs-title,
  .hljs-type {
    color: #79c0ff;
  }
  .hljs-symbol,
  .hljs-bullet,
  .hljs-subst,
  .hljs-meta,
  .hljs-meta .hljs-keyword,
  .hljs-selector-attr,
  .hljs-selector-pseudo,
  .hljs-link {
    color: #ffa657;
  }
  .hljs-built_in,
  .hljs-deletion {
    color: #ffa198;
  }
  .hljs-formula {
    background-color: #21262d;
  }
  .hljs-emphasis {
    font-style: italic;
  }
  .hljs-strong {
    font-weight: bold;
  }
}

// highlight.js 浅色主题样式
.marked-markdown.theme-light {
  .hljs {
    color: #24292f;
  }
  .hljs-comment,
  .hljs-quote {
    color: #6e7781;
    font-style: italic;
  }
  .hljs-keyword,
  .hljs-selector-tag,
  .hljs-addition {
    color: #cf222e;
  }
  .hljs-number,
  .hljs-string,
  .hljs-meta .hljs-meta-string,
  .hljs-literal,
  .hljs-doctag,
  .hljs-regexp {
    color: #0a3069;
  }
  .hljs-title,
  .hljs-section,
  .hljs-name,
  .hljs-selector-id,
  .hljs-selector-class {
    color: #8250df;
  }
  .hljs-attribute,
  .hljs-attr,
  .hljs-variable,
  .hljs-template-variable,
  .hljs-class .hljs-title,
  .hljs-type {
    color: #0550ae;
  }
  .hljs-symbol,
  .hljs-bullet,
  .hljs-subst,
  .hljs-meta,
  .hljs-meta .hljs-keyword,
  .hljs-selector-attr,
  .hljs-selector-pseudo,
  .hljs-link {
    color: #953800;
  }
  .hljs-built_in,
  .hljs-deletion {
    color: #82071e;
  }
  .hljs-formula {
    background-color: #f6f8fa;
  }
  .hljs-emphasis {
    font-style: italic;
  }
  .hljs-strong {
    font-weight: bold;
  }
}

// HTML预览抽屉样式
.html-preview-drawer {
  .el-drawer__header {
    margin-bottom: 0;
    padding: 16px 20px;
    border-bottom: 1px solid #e4e7ed;
  }

  .el-drawer__body {
    padding: 0;
    overflow: hidden;
  }

  .preview-container {
    width: 100%;
    height: 100%;
    background-color: #fff;
  }

  .preview-iframe {
    width: 100%;
    height: 100%;
    border: none;
    background-color: #fff;
  }

}
.marked-markdown .code-block-wrapper pre.hljs {
  padding-bottom: 4px;

  &::-webkit-scrollbar {
    height: 6px;
  }
  &::-webkit-scrollbar-track {
    background: transparent;
  }
  &::-webkit-scrollbar-thumb {
    background-color: rgba(128, 128, 128, 0.4);
    border-radius: 3px;
    &:hover {
      background-color: rgba(128, 128, 128, 0.6);
    }
  }
}
</style>
