/* global React */
const { useState, useRef, useEffect, useCallback } = React;

const DEFAULT_HTML = `<p style="font-size:16px;line-height:1.75;margin-bottom:16px;text-indent:2em;text-align:justify;">欢迎使用在线排版工具</p>
<p style="font-size:16px;line-height:1.75;margin-bottom:16px;text-indent:2em;text-align:justify;">在这里直接输入或粘贴文字，所见即所得。点击工具栏按钮，可以实时调整字体、字号、行高、颜色等排版效果。</p>
<p style="font-size:16px;line-height:1.75;margin-bottom:16px;text-indent:2em;text-align:justify;">支持多种排版选项：字体选择、字号、行高、段落间距、首行缩进、对齐方式、文字颜色与背景色、标题样式、引用块、分割线。</p>
<p style="font-size:16px;line-height:1.75;margin-bottom:16px;text-indent:2em;text-align:justify;">点击"一键排版"可以快速应用公众号常用排版风格，排版完成后点击"复制"按钮，可以将排版好的内容直接粘贴到公众号、Word 等编辑器中，保留全部格式。</p>`;

function TypesettingPage() {
  const { navigate, showToast } = useApp();
  const editorRef = useRef(null);
  const lastSelectionRef = useRef(null);
  const [wordCount, setWordCount] = useState(0);

  // 排版设置（用于按钮高亮状态）
  const [fontFamily, setFontFamily] = useState('"Microsoft YaHei", "微软雅黑", sans-serif');
  const [fontSize, setFontSize] = useState(16);
  const [lineHeight, setLineHeight] = useState(1.75);
  const [paragraphSpacing, setParagraphSpacing] = useState(16);
  const [firstLineIndent, setFirstLineIndent] = useState(true);
  const [textAlign, setTextAlign] = useState('justify');
  const [textColor, setTextColor] = useState('#333333');
  const [bgColor, setBgColor] = useState('#ffffff');

  const fontOptions = [
    { label: '微软雅黑', value: '"Microsoft YaHei", "微软雅黑", sans-serif' },
    { label: '宋体', value: '"SimSun", "宋体", serif' },
    { label: '楷体', value: '"KaiTi", "楷体", serif' },
    { label: '黑体', value: '"SimHei", "黑体", sans-serif' },
  ];

  const fontSizeOptions = [14, 16, 18, 20];
  const lineHeightOptions = [1.5, 1.75, 2.0, 2.25];
  const paraSpacingOptions = [8, 12, 16, 20, 24];
  const alignOptions = [
    { label: '左对齐', value: 'left' },
    { label: '居中', value: 'center' },
    { label: '两端对齐', value: 'justify' },
  ];

  // 记录选区，避免点击工具栏后丢失焦点
  const saveSelection = useCallback(() => {
    const sel = window.getSelection();
    if (sel && sel.rangeCount > 0 && editorRef.current) {
      const range = sel.getRangeAt(0);
      if (editorRef.current.contains(range.commonAncestorContainer)) {
        lastSelectionRef.current = range.cloneRange();
      }
    }
  }, []);

  const restoreSelection = useCallback(() => {
    const sel = window.getSelection();
    if (lastSelectionRef.current && editorRef.current) {
      sel.removeAllRanges();
      sel.addRange(lastSelectionRef.current);
      return true;
    }
    return false;
  }, []);

  const focusEditor = useCallback(() => {
    if (editorRef.current) {
      editorRef.current.focus();
    }
  }, []);

  // 更新字数
  const updateWordCount = useCallback(() => {
    if (editorRef.current) {
      const text = editorRef.current.innerText || '';
      setWordCount(text.replace(/\s/g, '').length);
    }
  }, []);

  // 初始化编辑器内容
  useEffect(() => {
    if (editorRef.current && !editorRef.current.innerHTML.trim()) {
      editorRef.current.innerHTML = DEFAULT_HTML;
      updateWordCount();
    }
  }, [updateWordCount]);

  // 执行 document.execCommand 并更新选中节点样式
  const exec = (command, value = null) => {
    focusEditor();
    if (!restoreSelection()) {
      // 没有选区，全选后应用
      const range = document.createRange();
      range.selectNodeContents(editorRef.current);
      const sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(range);
    }
    document.execCommand(command, false, value);
    saveSelection();
    updateWordCount();
  };

  // 给所有段落应用样式
  const applyToAllParagraphs = (styleProp, styleValue) => {
    if (!editorRef.current) return;
    const paras = editorRef.current.querySelectorAll('p, h1, h2, blockquote');
    paras.forEach(el => {
      el.style[styleProp] = styleValue;
    });
    updateWordCount();
  };

  // 给选中内容的父段落应用样式（段落级属性）
  const applyParagraphStyle = (styleProp, styleValue) => {
    focusEditor();
    if (!restoreSelection()) return;
    const sel = window.getSelection();
    if (!sel.rangeCount) return;
    const range = sel.getRangeAt(0);
    // 找所有在选区内的段落
    let node = range.startContainer;
    const paras = new Set();
    // 起点往上找段落
    let p = node.nodeType === 1 ? node : node.parentElement;
    while (p && p !== editorRef.current) {
      if (/^(P|H1|H2|BLOCKQUOTE)$/.test(p.tagName)) {
        paras.add(p);
        break;
      }
      p = p.parentElement;
    }
    // 终点往上找段落
    node = range.endContainer;
    p = node.nodeType === 1 ? node : node.parentElement;
    while (p && p !== editorRef.current) {
      if (/^(P|H1|H2|BLOCKQUOTE)$/.test(p.tagName)) {
        paras.add(p);
        break;
      }
      p = p.parentElement;
    }
    // 如果选区只在文本节点中且没找到段落，找最近的块级父元素
    if (paras.size === 0) {
      let cur = range.commonAncestorContainer;
      if (cur.nodeType === 3) cur = cur.parentElement;
      while (cur && cur !== editorRef.current) {
        if (/^(P|H1|H2|BLOCKQUOTE|DIV)$/.test(cur.tagName)) {
          paras.add(cur);
          break;
        }
        cur = cur.parentElement;
      }
    }
    paras.forEach(el => {
      el.style[styleProp] = styleValue;
    });
    saveSelection();
    updateWordCount();
  };

  // === 工具栏处理函数 ===

  const handleFontFamily = (val) => {
    setFontFamily(val);
    exec('fontName', val);
    // fontName 对中文支持有限，额外用 span 包一层设 fontFamily
    applyInlineStyle('fontFamily', val);
  };

  // 给选中文字的每个文本节点包 span 并设样式
  const applyInlineStyle = (prop, value) => {
    focusEditor();
    if (!restoreSelection()) return;
    const sel = window.getSelection();
    if (!sel.rangeCount || sel.isCollapsed) {
      saveSelection();
      return;
    }
    const range = sel.getRangeAt(0);
    // 用 execCommand 'hiliteColor' 的思路不可行，用 surroundContents 对每个文本节点处理
    // 简化：使用 execCommand styleWithCSS + 自定义样式，通过 font 标签或 span 处理
    // 采用更可靠的方式：用 document.execCommand('insertHTML') 插入带样式的 span
    const span = document.createElement('span');
    span.style[prop] = value;
    const fragment = range.extractContents();
    span.appendChild(fragment);
    range.insertNode(span);
    // 恢复选区到新插入内容
    const newRange = document.createRange();
    newRange.selectNodeContents(span);
    sel.removeAllRanges();
    sel.addRange(newRange);
    saveSelection();
    updateWordCount();
  };

  const handleFontSize = (val) => {
    setFontSize(val);
    // 先尝试用 execCommand fontSize，然后再用 span 精确设 px
    exec('fontSize', '7'); // 最大号作为占位
    // 把刚插入的 font 标签替换为 span 带精确 px
    const fonts = editorRef.current.querySelectorAll('font[size="7"]');
    fonts.forEach(f => {
      const span = document.createElement('span');
      span.style.fontSize = `${val}px`;
      span.innerHTML = f.innerHTML;
      f.replaceWith(span);
    });
    updateWordCount();
  };

  const handleLineHeight = (val) => {
    setLineHeight(val);
    applyParagraphStyle('lineHeight', val);
  };

  const handleParaSpacing = (val) => {
    setParagraphSpacing(val);
    applyParagraphStyle('marginBottom', `${val}px`);
  };

  const handleFirstLineIndent = () => {
    const next = !firstLineIndent;
    setFirstLineIndent(next);
    applyParagraphStyle('textIndent', next ? '2em' : '0');
  };

  const handleAlign = (val) => {
    setTextAlign(val);
    exec('justify' + val.charAt(0).toUpperCase() + val.slice(1));
    // 同时给段落加 textAlign 样式（execCommand justify 在某些浏览器用 text-align 属性）
    applyParagraphStyle('textAlign', val);
  };

  const handleTextColor = (val) => {
    setTextColor(val);
    exec('foreColor', val);
  };

  const handleBgColor = (val) => {
    setBgColor(val);
    if (editorRef.current) {
      editorRef.current.style.background = val;
    }
  };

  // 插入元素（在光标位置）
  const insertElement = (el) => {
    focusEditor();
    restoreSelection();
    const sel = window.getSelection();
    if (!sel.rangeCount) return;
    const range = sel.getRangeAt(0);
    range.deleteContents();
    range.insertNode(el);
    // 光标移到插入元素后
    range.setStartAfter(el);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
    // 后面补一个空段落方便继续编辑
    const nextP = document.createElement('p');
    nextP.style.cssText = `font-size:${fontSize}px;line-height:${lineHeight};margin-bottom:${paragraphSpacing}px;text-indent:${firstLineIndent ? '2em' : '0'};text-align:${textAlign};`;
    nextP.innerHTML = '<br>';
    el.after(nextP);
    // 光标移到新段落
    const nr = document.createRange();
    nr.setStart(nextP, 0);
    nr.collapse(true);
    sel.removeAllRanges();
    sel.addRange(nr);
    saveSelection();
    updateWordCount();
  };

  const insertH1 = () => {
    const h1 = document.createElement('h1');
    h1.style.cssText = `font-size:${fontSize + 8}px;font-weight:700;line-height:1.4;margin-bottom:${paragraphSpacing + 4}px;color:${textColor};text-align:left;`;
    h1.textContent = '一级标题';
    insertElement(h1);
  };

  const insertH2 = () => {
    const h2 = document.createElement('h2');
    h2.style.cssText = `font-size:${fontSize + 4}px;font-weight:600;line-height:1.5;margin-bottom:${paragraphSpacing + 2}px;color:${textColor};text-align:left;border-left:3px solid var(--primary);padding-left:10px;`;
    h2.textContent = '二级标题';
    insertElement(h2);
  };

  const insertQuote = () => {
    const q = document.createElement('blockquote');
    q.style.cssText = `margin-bottom:${paragraphSpacing}px;padding:10px 14px;border-left:4px solid var(--primary);background:var(--primary-light);font-size:${fontSize}px;line-height:${lineHeight};color:${textColor};`;
    q.textContent = '引用文字';
    insertElement(q);
  };

  const insertHr = () => {
    const hr = document.createElement('hr');
    hr.style.cssText = `margin:${paragraphSpacing + 4}px 0;border:none;border-top:1px solid var(--border);`;
    insertElement(hr);
  };

  // 一键排版：给所有段落套公众号格式
  const handleAutoTypeset = () => {
    if (!editorRef.current) return;
    const targetFont = '"Microsoft YaHei", "微软雅黑", sans-serif';
    const targetSize = 16;
    const targetLH = 1.75;
    const targetPS = 16;
    const targetIndent = '2em';
    const targetAlign = 'justify';
    const targetColor = '#333333';
    const targetBg = '#ffffff';

    setFontFamily(targetFont);
    setFontSize(targetSize);
    setLineHeight(targetLH);
    setParagraphSpacing(targetPS);
    setFirstLineIndent(true);
    setTextAlign(targetAlign);
    setTextColor(targetColor);
    setBgColor(targetBg);

    // 编辑器背景
    editorRef.current.style.background = targetBg;
    editorRef.current.style.color = targetColor;
    editorRef.current.style.fontFamily = targetFont;
    editorRef.current.style.fontSize = `${targetSize}px`;
    editorRef.current.style.lineHeight = targetLH;

    // 所有段落
    const all = editorRef.current.querySelectorAll('p, h1, h2, blockquote, div, span');
    all.forEach(el => {
      if (el.tagName === 'H1' || el.tagName === 'H2') {
        el.style.textAlign = 'left';
        el.style.textIndent = '0';
        el.style.marginBottom = el.tagName === 'H1' ? `${targetPS + 4}px` : `${targetPS + 2}px`;
        el.style.color = targetColor;
      } else if (el.tagName === 'BLOCKQUOTE') {
        el.style.fontSize = `${targetSize}px`;
        el.style.lineHeight = targetLH;
        el.style.marginBottom = `${targetPS}px`;
      } else {
        el.style.fontSize = `${targetSize}px`;
        el.style.lineHeight = targetLH;
        el.style.marginBottom = `${targetPS}px`;
        el.style.textIndent = targetIndent;
        el.style.textAlign = targetAlign;
        el.style.color = targetColor;
      }
      el.style.fontFamily = targetFont;
    });

    updateWordCount();
    showToast('已应用一键排版');
  };

  // 粘贴：从剪贴板读取文字插入
  const handlePaste = async () => {
    focusEditor();
    try {
      if (navigator.clipboard && navigator.clipboard.readText) {
        const clipText = await navigator.clipboard.readText();
        if (clipText != null) {
          // 按行分段，每个段落套 p 标签
          const lines = clipText.split('\n');
          const paras = lines.filter(l => l.trim()).map(line =>
            `<p style="font-size:${fontSize}px;line-height:${lineHeight};margin-bottom:${paragraphSpacing}px;text-indent:${firstLineIndent ? '2em' : '0'};text-align:${textAlign};color:${textColor};">${line.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</p>`
          ).join('');
          exec('insertHTML', paras || '<br>');
          showToast('已从剪贴板粘贴');
        }
      } else {
        showToast('请按 Ctrl+V / Cmd+V 手动粘贴');
      }
    } catch (e) {
      console.warn('clipboard read error', e);
      showToast('请按 Ctrl+V / Cmd+V 手动粘贴');
    }
  };

  // 复制富文本
  const handleCopyRich = async () => {
    if (!editorRef.current) return;
    try {
      // 构造完整 HTML（包含编辑器背景和基础样式）
      const inner = editorRef.current.innerHTML;
      const html = `<div style="font-family:${fontFamily};font-size:${fontSize}px;line-height:${lineHeight};color:${textColor};background:${bgColor};padding:20px;">${inner}</div>`;
      const plain = editorRef.current.innerText;
      if (navigator.clipboard && window.ClipboardItem) {
        const blobHtml = new Blob([html], { type: 'text/html' });
        const blobText = new Blob([plain], { type: 'text/plain' });
        await navigator.clipboard.write([
          new window.ClipboardItem({
            'text/html': blobHtml,
            'text/plain': blobText,
          }),
        ]);
      } else {
        const range = document.createRange();
        range.selectNodeContents(editorRef.current);
        const sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
        document.execCommand('copy');
        sel.removeAllRanges();
      }
      showToast('已复制，可直接粘贴到公众号/Word');
    } catch (e) {
      console.error('copy error', e);
      showToast('复制失败，请手动选择复制');
    }
  };

  // 工具栏按钮/分组样式
  const sectionGap = 10;
  const btnBase = {
    padding: '6px 10px',
    fontSize: 12,
    border: '1px solid var(--border)',
    borderRadius: 6,
    background: 'var(--bg-card)',
    color: 'var(--text-primary)',
    cursor: 'pointer',
    whiteSpace: 'nowrap',
  };
  const btnActive = {
    ...btnBase,
    borderColor: 'var(--primary)',
    color: 'var(--primary)',
    background: 'var(--primary-light)',
    fontWeight: 500,
  };

  const ToolGroup = ({ label, children }) => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      <div style={{ fontSize: 11, color: 'var(--text-tertiary)', fontWeight: 500 }}>{label}</div>
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>{children}</div>
    </div>
  );

  const colorPresets = ['#333333', '#1f2937', '#dc2626', '#d97706', '#16a34a', '#2563eb', '#7c3aed', '#db2777'];
  const bgPresets = ['#ffffff', '#fafafa', '#fef3c7', '#dbeafe', '#dcfce7', '#f3e8ff', '#fce7f3', '#fee2e2'];

  // 工具栏按钮点击时先保存选区再执行
  const wrapAction = (fn) => (e) => {
    e.preventDefault();
    saveSelection();
    fn();
  };

  return (
    <PageWrapper className="typesetting-page">
      <AppHeader
        title="在线排版工具"
        subtitle="所见即所得 · 直接排版"
        showBack={true}
      />

      {/* 格式工具栏 */}
      <div className="ts-toolbar" style={{
        flexShrink: 0,
        background: 'var(--bg-card)',
        borderBottom: '1px solid var(--border)',
        padding: '10px 12px',
        display: 'flex',
        flexDirection: 'column',
        gap: sectionGap,
        overflowY: 'auto',
        maxHeight: '38vh',
        WebkitOverflowScrolling: 'touch',
      }}
        onMouseDown={saveSelection}
      >
        {/* 第一行：字体 + 字号 + 行高 */}
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-start' }}>
          <ToolGroup label="字体">
            {fontOptions.map(f => (
              <button key={f.value} style={fontFamily === f.value ? btnActive : btnBase} onClick={wrapAction(() => handleFontFamily(f.value))}>
                {f.label}
              </button>
            ))}
          </ToolGroup>
          <ToolGroup label="字号">
            {fontSizeOptions.map(s => (
              <button key={s} style={fontSize === s ? btnActive : btnBase} onClick={wrapAction(() => handleFontSize(s))}>
                {s}px
              </button>
            ))}
          </ToolGroup>
          <ToolGroup label="行高">
            {lineHeightOptions.map(l => (
              <button key={l} style={lineHeight === l ? btnActive : btnBase} onClick={wrapAction(() => handleLineHeight(l))}>
                {l}
              </button>
            ))}
          </ToolGroup>
        </div>

        {/* 第二行：段落间距 + 首行缩进 + 对齐 */}
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-start' }}>
          <ToolGroup label="段落间距">
            {paraSpacingOptions.map(p => (
              <button key={p} style={paragraphSpacing === p ? btnActive : btnBase} onClick={wrapAction(() => handleParaSpacing(p))}>
                {p}px
              </button>
            ))}
          </ToolGroup>
          <ToolGroup label="首行缩进">
            <button style={firstLineIndent ? btnActive : btnBase} onClick={wrapAction(handleFirstLineIndent)}>
              {firstLineIndent ? '已开启' : '已关闭'}
            </button>
          </ToolGroup>
          <ToolGroup label="对齐方式">
            {alignOptions.map(a => (
              <button key={a.value} style={textAlign === a.value ? btnActive : btnBase} onClick={wrapAction(() => handleAlign(a.value))}>
                {a.label}
              </button>
            ))}
          </ToolGroup>
        </div>

        {/* 第三行：颜色 + 快捷插入 */}
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-start' }}>
          <ToolGroup label="文字颜色">
            {colorPresets.map(c => (
              <button
                key={c}
                onClick={wrapAction(() => handleTextColor(c))}
                title={c}
                style={{
                  width: 24, height: 24, borderRadius: 4,
                  border: textColor === c ? '2px solid var(--primary)' : '1px solid var(--border)',
                  background: c, cursor: 'pointer', padding: 0,
                }}
              />
            ))}
            <input
              type="color"
              value={textColor}
              onChange={(e) => { saveSelection(); handleTextColor(e.target.value); }}
              style={{ width: 24, height: 24, border: 'none', padding: 0, background: 'transparent', cursor: 'pointer' }}
            />
          </ToolGroup>
          <ToolGroup label="背景色">
            {bgPresets.map(c => (
              <button
                key={c}
                onClick={wrapAction(() => handleBgColor(c))}
                title={c}
                style={{
                  width: 24, height: 24, borderRadius: 4,
                  border: bgColor === c ? '2px solid var(--primary)' : '1px solid var(--border)',
                  background: c, cursor: 'pointer', padding: 0,
                }}
              />
            ))}
            <input
              type="color"
              value={bgColor}
              onChange={(e) => { saveSelection(); handleBgColor(e.target.value); }}
              style={{ width: 24, height: 24, border: 'none', padding: 0, background: 'transparent', cursor: 'pointer' }}
            />
          </ToolGroup>
          <ToolGroup label="快捷插入">
            <button style={btnBase} onClick={wrapAction(insertH1)}>H1 标题</button>
            <button style={btnBase} onClick={wrapAction(insertH2)}>H2 标题</button>
            <button style={btnBase} onClick={wrapAction(insertQuote)}>引用块</button>
            <button style={btnBase} onClick={wrapAction(insertHr)}>分割线</button>
          </ToolGroup>
        </div>
      </div>

      {/* 操作按钮行：编辑框正上方，居中排列 */}
      <div className="ts-action-row" style={{
        flexShrink: 0,
        padding: '10px 12px',
        background: 'var(--bg-card)',
        borderBottom: '1px solid var(--border)',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        gap: 10,
      }}>
        <button
          className="btn btn-outline"
          onClick={handlePaste}
          style={{
            fontSize: 13,
            padding: '6px 18px',
            borderRadius: 6,
            minWidth: 72,
          }}
        >
          粘贴
        </button>
        <button
          className="btn btn-primary"
          onClick={handleAutoTypeset}
          style={{
            fontSize: 13,
            padding: '6px 22px',
            borderRadius: 6,
            minWidth: 96,
          }}
        >
          一键排版
        </button>
        <button
          className="btn btn-outline"
          onClick={handleCopyRich}
          style={{
            fontSize: 13,
            padding: '6px 18px',
            borderRadius: 6,
            minWidth: 72,
          }}
        >
          复制
        </button>
      </div>

      {/* 编辑区 */}
      <div style={{
        flex: 1,
        minHeight: 0,
        display: 'flex',
        flexDirection: 'column',
        overflow: 'hidden',
      }}>
        <div style={{
          flexShrink: 0,
          padding: '6px 12px',
          fontSize: 12,
          color: 'var(--text-tertiary)',
          background: 'var(--bg-card)',
          borderBottom: '1px solid var(--border)',
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
        }}>
          <span>在此输入或粘贴文字，直接排版</span>
          <span style={{ fontSize: 11 }}>{wordCount} 字</span>
        </div>
        <div
          ref={editorRef}
          contentEditable
          suppressContentEditableWarning
          onInput={updateWordCount}
          onBlur={saveSelection}
          onKeyUp={saveSelection}
          onMouseUp={saveSelection}
          style={{
            flex: 1,
            minHeight: 0,
            padding: 20,
            background: bgColor,
            color: textColor,
            fontFamily,
            fontSize: `${fontSize}px`,
            lineHeight,
            overflowY: 'auto',
            WebkitOverflowScrolling: 'touch',
            outline: 'none',
            wordBreak: 'break-word',
            userSelect: 'text',
            WebkitUserSelect: 'text',
            pointerEvents: 'auto',
            touchAction: 'auto',
          }}
        />
      </div>

      {/* 布局样式 */}
      <style>{`
        .typesetting-page {
          display: flex !important;
          flex-direction: column !important;
          height: 100dvh !important;
          height: 100vh !important;
          overflow: hidden !important;
          padding-bottom: 0 !important;
        }
        .typesetting-page > .app-header {
          flex-shrink: 0;
        }
        [contenteditable] h1,
        [contenteditable] h2,
        [contenteditable] p,
        [contenteditable] blockquote {
          margin: 0;
        }
        @media (max-width: 480px) {
          .ts-action-row {
            gap: 8px;
            padding: 8px 10px;
          }
          .ts-action-row .btn {
            font-size: 12px !important;
            padding: 5px 14px !important;
            min-width: auto !important;
          }
        }
      `}</style>
    </PageWrapper>
  );
}

Object.assign(window, { TypesettingPage });
