// format-toolbar.jsx — Selection-anchored floating format bar with text color picker
//
// Operates on the editor textarea: when the user selects a non-empty range, a
// small popover appears above the selection. Colors wrap selection in
// <span style="color:..."> (markdown is HTML-friendly so this renders in preview).
// Bold / italic / strike / code / link wrap selection with the corresponding
// markdown syntax. Clear color strips a wrapping color span on the selection.

const TEXT_COLORS = [
  { name: 'red',     value: '#E5484D' },
  { name: 'orange',  value: '#E58E26' },
  { name: 'yellow',  value: '#D5A526' },
  { name: 'green',   value: '#3E9B4F' },
  { name: 'teal',    value: '#1F9B98' },
  { name: 'blue',    value: '#3E63DD' },
  { name: 'violet',  value: '#7C5CD9' },
  { name: 'pink',    value: '#D6409F' },
];

function getTextareaSelectionRect(textarea) {
  // Mirror-div technique: copy the textarea's box & content up to caret start,
  // measure where a marker span lands.
  if (!textarea) return null;
  const ta = textarea;
  const style = window.getComputedStyle(ta);
  const div = document.createElement('div');
  const props = [
    'boxSizing','width','height','overflowX','overflowY',
    'borderTopWidth','borderRightWidth','borderBottomWidth','borderLeftWidth',
    'paddingTop','paddingRight','paddingBottom','paddingLeft',
    'fontStyle','fontVariant','fontWeight','fontStretch','fontSize','fontSizeAdjust',
    'lineHeight','fontFamily','textAlign','textTransform','textIndent',
    'letterSpacing','wordSpacing','tabSize','MozTabSize','whiteSpace','wordBreak','wordWrap',
  ];
  div.style.position = 'absolute';
  div.style.visibility = 'hidden';
  div.style.whiteSpace = 'pre-wrap';
  div.style.wordWrap = 'break-word';
  div.style.top = '0';
  div.style.left = '-9999px';
  props.forEach(p => { div.style[p] = style[p]; });
  div.style.width = ta.clientWidth + 'px';
  div.style.height = 'auto';

  const value = ta.value;
  const start = ta.selectionStart;
  const end = ta.selectionEnd;
  const before = value.substring(0, start);
  const selected = value.substring(start, end) || '.';

  div.textContent = before;
  const span = document.createElement('span');
  span.textContent = selected;
  div.appendChild(span);

  document.body.appendChild(div);
  const taRect = ta.getBoundingClientRect();
  const spanRect = span.getBoundingClientRect();
  const divRect = div.getBoundingClientRect();
  const top = taRect.top + (spanRect.top - divRect.top) - ta.scrollTop;
  const left = taRect.left + (spanRect.left - divRect.left) - ta.scrollLeft;
  document.body.removeChild(div);
  return { top, left, width: spanRect.width, height: spanRect.height };
}

function FormatToolbar({ textareaRef, scrollRef, value, onChange }) {
  const [pos, setPos] = React.useState(null);
  const [sel, setSel] = React.useState(null);
  const barRef = React.useRef(null);

  // Measure selection and place popover
  const measure = React.useCallback(() => {
    const ta = textareaRef.current;
    if (!ta) { setPos(null); return; }
    const start = ta.selectionStart;
    const end = ta.selectionEnd;
    if (start === end) { setPos(null); setSel(null); return; }
    const rect = getTextareaSelectionRect(ta);
    if (!rect) { setPos(null); return; }
    const barW = barRef.current?.offsetWidth || 280;
    const barH = barRef.current?.offsetHeight || 36;
    const containerRect = ta.parentElement?.parentElement?.getBoundingClientRect();
    if (!containerRect) return;
    let top = rect.top - containerRect.top - barH - 10;
    let left = rect.left - containerRect.left + rect.width / 2 - barW / 2;
    let arrowX = barW / 2;
    if (left < 8) { arrowX -= (8 - left); left = 8; }
    const maxLeft = containerRect.width - barW - 8;
    if (left > maxLeft) { arrowX += (left - maxLeft); left = maxLeft; }
    if (top < 8) top = rect.top - containerRect.top + rect.height + 10;
    setPos({ top, left, arrowX });
    setSel({ start, end });
  }, [textareaRef]);

  // Hook into selection changes
  React.useEffect(() => {
    const ta = textareaRef.current;
    if (!ta) return;
    const onSel = () => {
      // Defer one frame so selection has settled
      requestAnimationFrame(measure);
    };
    const hide = () => { setPos(null); setSel(null); };
    ta.addEventListener('select', onSel);
    ta.addEventListener('mouseup', onSel);
    ta.addEventListener('keyup', onSel);
    ta.addEventListener('blur', (e) => {
      // Don't hide if focus moved into our toolbar
      setTimeout(() => {
        if (!barRef.current?.contains(document.activeElement) &&
            !barRef.current?.matches(':hover')) hide();
      }, 100);
    });
    const onWinScroll = () => { if (pos) measure(); };
    const sc = scrollRef?.current;
    sc?.addEventListener('scroll', onWinScroll);
    window.addEventListener('resize', measure);
    return () => {
      ta.removeEventListener('select', onSel);
      ta.removeEventListener('mouseup', onSel);
      ta.removeEventListener('keyup', onSel);
      sc?.removeEventListener('scroll', onWinScroll);
      window.removeEventListener('resize', measure);
    };
  }, [measure, textareaRef, scrollRef, pos]);

  const wrap = (left, right = left) => {
    const ta = textareaRef.current;
    if (!ta || !sel) return;
    const v = ta.value;
    const inner = v.substring(sel.start, sel.end);
    const next = v.substring(0, sel.start) + left + inner + right + v.substring(sel.end);
    onChange(next);
    requestAnimationFrame(() => {
      ta.focus();
      ta.selectionStart = sel.start + left.length;
      ta.selectionEnd = sel.end + left.length;
      measure();
    });
  };

  const applyColor = (color) => {
    const ta = textareaRef.current;
    if (!ta || !sel) return;
    const v = ta.value;
    let inner = v.substring(sel.start, sel.end);
    // Strip an enclosing color span if present
    const colorSpanRe = /^<span style="color:[^"]+">([\s\S]*)<\/span>$/;
    const m = inner.match(colorSpanRe);
    if (m) inner = m[1];
    const wrapped = `<span style="color:${color}">${inner}</span>`;
    const next = v.substring(0, sel.start) + wrapped + v.substring(sel.end);
    onChange(next);
    requestAnimationFrame(() => {
      ta.focus();
      ta.selectionStart = sel.start;
      ta.selectionEnd = sel.start + wrapped.length;
      measure();
    });
  };

  const clearColor = () => {
    const ta = textareaRef.current;
    if (!ta || !sel) return;
    const v = ta.value;
    let inner = v.substring(sel.start, sel.end);
    const colorSpanRe = /^<span style="color:[^"]+">([\s\S]*)<\/span>$/;
    const m = inner.match(colorSpanRe);
    if (!m) {
      // Try to strip nested
      inner = inner.replace(/<span style="color:[^"]+">([\s\S]*?)<\/span>/g, '$1');
    } else {
      inner = m[1];
    }
    const next = v.substring(0, sel.start) + inner + v.substring(sel.end);
    onChange(next);
    requestAnimationFrame(() => {
      ta.focus();
      ta.selectionStart = sel.start;
      ta.selectionEnd = sel.start + inner.length;
      measure();
    });
  };

  const makeLink = () => {
    const ta = textareaRef.current;
    if (!ta || !sel) return;
    const v = ta.value;
    const inner = v.substring(sel.start, sel.end);
    const url = window.prompt('URL', 'https://');
    if (!url) return;
    const wrapped = `[${inner}](${url})`;
    const next = v.substring(0, sel.start) + wrapped + v.substring(sel.end);
    onChange(next);
    requestAnimationFrame(() => {
      ta.focus();
      ta.selectionStart = sel.start;
      ta.selectionEnd = sel.start + wrapped.length;
      measure();
    });
  };

  if (!pos) return null;
  return (
    <div ref={barRef} className="format-bar"
         style={{ top: pos.top, left: pos.left, '--arrow-x': pos.arrowX + 'px' }}
         onMouseDown={(e) => e.preventDefault() /* don't blur textarea */}>
      <button onClick={() => wrap('**')} title="Bold (Cmd+B)" style={{ fontWeight: 700 }}>B</button>
      <button onClick={() => wrap('*')} title="Italic (Cmd+I)" style={{ fontStyle: 'italic' }}>I</button>
      <button onClick={() => wrap('~~')} title="Strikethrough" style={{ textDecoration: 'line-through' }}>S</button>
      <button onClick={() => wrap('`')} title="Inline code" style={{ fontFamily: 'var(--font-mono)', fontSize: 12 }}>{'<>'}</button>
      <span className="fb-divider" />
      <button onClick={makeLink} title="Link">
        <svg width="14" height="14" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
          <path d="M8 12a4 4 0 0 0 5.66 0l2.83-2.83a4 4 0 0 0-5.66-5.66L9.83 4.85" />
          <path d="M12 8a4 4 0 0 0-5.66 0L3.5 10.83a4 4 0 0 0 5.66 5.66l1-1" />
        </svg>
      </button>
      <span className="fb-divider" />
      <div className="fb-color-swatches">
        {TEXT_COLORS.map(c => (
          <button key={c.name} className="fb-swatch" style={{ background: c.value }}
                  title={c.name} onClick={() => applyColor(c.value)} />
        ))}
        <button className="fb-swatch clear" title="Clear color" onClick={clearColor} />
      </div>
    </div>
  );
}

window.FormatToolbar = FormatToolbar;
