// rich-text.jsx — форматирование текста как в Word

window.RT_FONTS = [
  { id: 'Geist, sans-serif', name: 'Geist' },
  { id: 'Inter, sans-serif', name: 'Inter' },
  { id: 'Roboto, sans-serif', name: 'Roboto' },
  { id: 'Open Sans, sans-serif', name: 'Open Sans' },
  { id: 'Arial, sans-serif', name: 'Arial' },
  { id: 'Helvetica, sans-serif', name: 'Helvetica' },
  { id: 'Times New Roman, serif', name: 'Times New Roman' },
  { id: 'Georgia, serif', name: 'Georgia' },
  { id: 'Merriweather, serif', name: 'Merriweather' },
  { id: 'Instrument Serif, serif', name: 'Instrument Serif' },
  { id: 'Courier New, monospace', name: 'Courier New' },
  { id: 'JetBrains Mono, monospace', name: 'JetBrains Mono' },
];

window.RT_SIZES = [
  { id: '12px', name: '12' },
  { id: '14px', name: '14' },
  { id: '15px', name: '15' },
  { id: '16px', name: '16' },
  { id: '18px', name: '18' },
  { id: '20px', name: '20' },
  { id: '24px', name: '24' },
  { id: '28px', name: '28' },
  { id: '32px', name: '32' },
  { id: '36px', name: '36' },
  { id: '48px', name: '48' },
];

window.RT_COLORS = [
  '#1a1a18', '#374151', '#6b7280', '#dc2626', '#ea580c', '#ca8a04',
  '#16a34a', '#0891b2', '#2563eb', '#7c3aed', '#db2777', '#ffffff',
];

window.RT_HIGHLIGHTS = [
  '#fef08a', '#bbf7d0', '#bfdbfe', '#fbcfe8', '#fed7aa', '#e5e7eb', 'transparent',
];

window.RT_RICH_TYPES = new Set(['p', 'h1', 'h2', 'h3', 'quote', 'call']);

window.activeRichTextEl = null;

window.escapeHtml = (text) => (text || '')
  .replace(/&/g, '&amp;')
  .replace(/</g, '&lt;')
  .replace(/>/g, '&gt;')
  .replace(/"/g, '&quot;');

window.isRichHtml = (text) => /<[a-z][\s\S]*>/i.test(text || '');

window.stripRichText = (html) => {
  if (!html) return '';
  if (!window.isRichHtml(html)) return html;
  const tmp = document.createElement('div');
  tmp.innerHTML = window.sanitizeRichHtml(html);
  return tmp.textContent || '';
};

window.plainToRichHtml = (text, mode = 'block') => {
  if (!text) return '';
  if (window.isRichHtml(text)) return text;
  if (mode === 'inline') {
    return window.escapeHtml(text).replace(/\n/g, '<br>');
  }
  return text
    .split('\n')
    .map((line) => `<p>${line ? window.escapeHtml(line) : '<br>'}</p>`)
    .join('');
};

window.sanitizeRichHtml = (html) => {
  const raw = html || '';
  if (!raw.trim()) return '';
  if (typeof DOMPurify !== 'undefined') {
    return DOMPurify.sanitize(raw, {
      ALLOWED_TAGS: [
        'p', 'br', 'strong', 'b', 'em', 'i', 'u', 's', 'strike', 'del',
        'span', 'a', 'ul', 'ol', 'li', 'div', 'blockquote', 'font',
      ],
      ALLOWED_ATTR: ['style', 'href', 'target', 'rel', 'class', 'color', 'face', 'size'],
    });
  }
  return raw.replace(/<script[\s\S]*?<\/script>/gi, '');
};

window.rtSaveSelection = () => {
  const sel = window.getSelection();
  if (!sel || sel.rangeCount === 0) return null;
  return sel.getRangeAt(0).cloneRange();
};

window.rtRestoreSelection = (range) => {
  if (!range) return;
  const sel = window.getSelection();
  sel.removeAllRanges();
  sel.addRange(range);
};

window.rtExec = (cmd, value = null) => {
  const el = window.activeRichTextEl;
  if (!el) return;
  el.focus();
  document.execCommand('styleWithCSS', false, true);
  document.execCommand(cmd, false, value);
  el.dispatchEvent(new Event('input', { bubbles: true }));
};

window.rtApplyStyle = (styles) => {
  const el = window.activeRichTextEl;
  if (!el) return;
  el.focus();
  const sel = window.getSelection();
  if (!sel || sel.rangeCount === 0) return;

  const range = sel.getRangeAt(0);
  if (range.collapsed) return;

  const span = document.createElement('span');
  Object.assign(span.style, styles);
  try {
    range.surroundContents(span);
  } catch {
    const contents = range.extractContents();
    span.appendChild(contents);
    range.insertNode(span);
  }
  sel.removeAllRanges();
  const nr = document.createRange();
  nr.selectNodeContents(span);
  nr.collapse(false);
  sel.addRange(nr);
  el.dispatchEvent(new Event('input', { bubbles: true }));
};

window.rtApplyFont = (fontFamily) => {
  document.execCommand('styleWithCSS', false, true);
  window.rtExec('fontName', fontFamily);
};

window.rtApplyFontSize = (size) => {
  const el = window.activeRichTextEl;
  if (!el) return;
  el.focus();
  const sel = window.getSelection();
  if (!sel || sel.rangeCount === 0 || sel.isCollapsed) {
    el.style.fontSize = size;
    el.dispatchEvent(new Event('input', { bubbles: true }));
    return;
  }
  window.rtApplyStyle({ fontSize: size });
};

window.rtApplyColor = (color) => {
  document.execCommand('styleWithCSS', false, true);
  window.rtExec('foreColor', color);
};

window.rtApplyHighlight = (color) => {
  document.execCommand('styleWithCSS', false, true);
  if (color === 'transparent') {
    window.rtExec('removeFormat');
    return;
  }
  window.rtExec('hiliteColor', color);
};

window.rtInsertLink = () => {
  const url = window.prompt('URL ссылки', 'https://');
  if (!url) return;
  window.rtExec('createLink', url);
};

const RichHtmlView = ({ html, className = '', tag: Tag = 'div', mode = 'block', id }) => {
  const safe = window.sanitizeRichHtml(window.plainToRichHtml(html, mode));
  if (!safe) return null;
  return (
    <Tag
      id={id}
      className={`article-richtext ${className}`.trim()}
      dangerouslySetInnerHTML={{ __html: safe }}
    />
  );
};

const RichTextEditor = ({ value, onChange, onFocus, placeholder, className = '', minHeight, mode = 'block' }) => {
  const ref = React.useRef(null);
  const focusedRef = React.useRef(false);
  const lastEmitted = React.useRef(value || '');

  const syncFromProp = React.useCallback((next) => {
    const el = ref.current;
    if (!el) return;
    const html = window.plainToRichHtml(next || '', mode);
    if (el.innerHTML !== html) el.innerHTML = html;
    lastEmitted.current = next || '';
  }, [mode]);

  React.useEffect(() => {
    syncFromProp(value);
  }, [value, syncFromProp]);

  const emitChange = () => {
    const el = ref.current;
    if (!el) return;
    const html = window.sanitizeRichHtml(el.innerHTML);
    lastEmitted.current = html;
    onChange(html);
  };

  const handleFocus = () => {
    focusedRef.current = true;
    window.activeRichTextEl = ref.current;
    onFocus?.();
  };

  const handleBlur = () => {
    focusedRef.current = false;
    window.setTimeout(() => {
      const active = document.activeElement;
      if (active?.closest?.('.rt-toolbar')) return;
      if (window.activeRichTextEl === ref.current) window.activeRichTextEl = null;
    }, 120);
  };

  return (
    <div
      ref={ref}
      className={`rt-editor ${className}`.trim()}
      contentEditable
      suppressContentEditableWarning
      data-placeholder={placeholder}
      style={minHeight ? { minHeight } : undefined}
      onInput={emitChange}
      onFocus={handleFocus}
      onBlur={handleBlur}
    />
  );
};

const RichTextToolbar = ({ visible }) => {
  const [fontOpen, setFontOpen] = React.useState(false);
  const [sizeOpen, setSizeOpen] = React.useState(false);
  const [colorOpen, setColorOpen] = React.useState(false);
  const [hlOpen, setHlOpen] = React.useState(false);
  const wrapRef = React.useRef(null);

  React.useEffect(() => {
    if (!fontOpen && !sizeOpen && !colorOpen && !hlOpen) return;
    const close = (e) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) {
        setFontOpen(false);
        setSizeOpen(false);
        setColorOpen(false);
        setHlOpen(false);
      }
    };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [fontOpen, sizeOpen, colorOpen, hlOpen]);

  if (!visible) return null;

  const prevent = (e) => e.preventDefault();

  const btn = (cmd, value, child, title) => (
    <button
      type="button"
      className="rt-toolbar-btn"
      title={title}
      onMouseDown={prevent}
      onClick={() => window.rtExec(cmd, value)}
    >
      {child}
    </button>
  );

  return (
    <div className="rt-toolbar" ref={wrapRef} onMouseDown={prevent}>
      <div className="rt-toolbar-group">
        <div className="rt-toolbar-dropdown">
          <button type="button" className="rt-toolbar-select" onMouseDown={prevent} onClick={() => setFontOpen((v) => !v)}>
            Шрифт
            <Icon name="chevronDown" size={12} />
          </button>
          {fontOpen && (
            <div className="rt-toolbar-menu">
              {window.RT_FONTS.map((f) => (
                <button
                  type="button"
                  key={f.id}
                  className="rt-toolbar-menu-item"
                  style={{ fontFamily: f.id }}
                  onMouseDown={prevent}
                  onClick={() => { window.rtApplyFont(f.id); setFontOpen(false); }}
                >
                  {f.name}
                </button>
              ))}
            </div>
          )}
        </div>
        <div className="rt-toolbar-dropdown">
          <button type="button" className="rt-toolbar-select rt-toolbar-select--sm" onMouseDown={prevent} onClick={() => setSizeOpen((v) => !v)}>
            16
            <Icon name="chevronDown" size={12} />
          </button>
          {sizeOpen && (
            <div className="rt-toolbar-menu rt-toolbar-menu--sm">
              {window.RT_SIZES.map((s) => (
                <button
                  type="button"
                  key={s.id}
                  className="rt-toolbar-menu-item"
                  onMouseDown={prevent}
                  onClick={() => { window.rtApplyFontSize(s.id); setSizeOpen(false); }}
                >
                  {s.name}
                </button>
              ))}
            </div>
          )}
        </div>
      </div>

      <div className="rt-toolbar-sep" />

      <div className="rt-toolbar-group">
        {btn('bold', null, <strong>B</strong>, 'Жирный')}
        {btn('italic', null, <em>I</em>, 'Курсив')}
        {btn('underline', null, <span className="rt-u">U</span>, 'Подчёркивание')}
        {btn('strikeThrough', null, <span className="rt-s">S</span>, 'Зачёркивание')}
      </div>

      <div className="rt-toolbar-sep" />

      <div className="rt-toolbar-group">
        <div className="rt-toolbar-dropdown">
          <button type="button" className="rt-toolbar-btn rt-toolbar-color" onMouseDown={prevent} onClick={() => setColorOpen((v) => !v)} title="Цвет текста">
            <span className="rt-color-a">A</span>
            <span className="rt-color-bar" style={{ background: '#dc2626' }} />
          </button>
          {colorOpen && (
            <div className="rt-toolbar-palette">
              {window.RT_COLORS.map((c) => (
                <button
                  type="button"
                  key={c}
                  className="rt-toolbar-swatch"
                  style={{ background: c, border: c === '#ffffff' ? '1px solid #e5e7eb' : undefined }}
                  onMouseDown={prevent}
                  onClick={() => { window.rtApplyColor(c); setColorOpen(false); }}
                />
              ))}
            </div>
          )}
        </div>
        <div className="rt-toolbar-dropdown">
          <button type="button" className="rt-toolbar-btn" onMouseDown={prevent} onClick={() => setHlOpen((v) => !v)} title="Цвет фона">
            <Icon name="edit" size={14} />
          </button>
          {hlOpen && (
            <div className="rt-toolbar-palette">
              {window.RT_HIGHLIGHTS.map((c) => (
                <button
                  type="button"
                  key={c}
                  className="rt-toolbar-swatch"
                  style={{
                    background: c === 'transparent' ? '#fff' : c,
                    border: '1px solid #e5e7eb',
                  }}
                  onMouseDown={prevent}
                  onClick={() => { window.rtApplyHighlight(c); setHlOpen(false); }}
                />
              ))}
            </div>
          )}
        </div>
      </div>

      <div className="rt-toolbar-sep" />

      <div className="rt-toolbar-group">
        {btn('justifyLeft', null, <Icon name="alignLeft" size={14} />, 'По левому краю')}
        {btn('justifyCenter', null, <Icon name="alignCenter" size={14} />, 'По центру')}
        {btn('justifyRight', null, <Icon name="alignRight" size={14} />, 'По правому краю')}
        {btn('justifyFull', null, <Icon name="alignJustify" size={14} />, 'По ширине')}
      </div>

      <div className="rt-toolbar-sep" />

      <div className="rt-toolbar-group">
        {btn('insertUnorderedList', null, <Icon name="list" size={14} />, 'Маркированный список')}
        {btn('insertOrderedList', null, <Icon name="listOl" size={14} />, 'Нумерованный список')}
        <button type="button" className="rt-toolbar-btn" title="Ссылка" onMouseDown={prevent} onClick={window.rtInsertLink}>
          <Icon name="link" size={14} />
        </button>
        <button type="button" className="rt-toolbar-btn" title="Очистить форматирование" onMouseDown={prevent} onClick={() => window.rtExec('removeFormat')}>
          <Icon name="x" size={14} />
        </button>
      </div>

      <div className="rt-toolbar-sep" />

      <div className="rt-toolbar-group">
        <button type="button" className="rt-toolbar-btn" title="Отменить" onMouseDown={prevent} onClick={() => window.rtExec('undo')}>
          <Icon name="history" size={14} style={{ transform: 'scaleX(-1)' }} />
        </button>
        <button type="button" className="rt-toolbar-btn" title="Повторить" onMouseDown={prevent} onClick={() => window.rtExec('redo')}>
          <Icon name="history" size={14} />
        </button>
      </div>
    </div>
  );
};

window.RichHtmlView = RichHtmlView;
window.RichTextEditor = RichTextEditor;
window.RichTextToolbar = RichTextToolbar;
