import { useState, useEffect, useRef } from 'react'
import Icon from './components/Icon'
import { onMessage, notifyReady, send } from './lib/rhinoBridge'

const SYMBOL_GROUPS = [
  { title: 'Mathematik / Architektur',
    symbols: ['∅', 'Ø', '⌀', '°', '±', '×', '÷', '²', '³', '½', '¼', '¾', '⅓', '⅔',
              '≤', '≥', '≠', '≈', '∞', '√', '∆', 'π', 'µ'] },
  { title: 'Pfeile',
    symbols: ['←', '→', '↑', '↓', '↔', '↕', '⇐', '⇒', '⇑', '⇓', '⇔'] },
  { title: 'Auszeichnung',
    symbols: ['•', '·', '▪', '◆', '◇', '★', '☆', '✓', '✗', '§', '¶', '©', '®', '™'] },
]
const FRAME_OPTIONS = [
  { value: 'none',    label: 'Kein Rahmen' },
  { value: 'rect',    label: 'Rechteck' },
  { value: 'capsule', label: 'Kapsel' },
]
const SIZE_PRESETS = [0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.50, 0.70, 1.00]

const BAR_H = 22

function Pill({ children, onClick, active, disabled, title, style }) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      title={title}
      onMouseEnter={(e) => {
        if (disabled || active) return
        e.currentTarget.style.background = 'var(--bg-item-hover)'
        e.currentTarget.style.borderColor = 'var(--accent)'
      }}
      onMouseLeave={(e) => {
        if (active) return
        e.currentTarget.style.background = 'var(--bg-input)'
        e.currentTarget.style.borderColor = 'var(--border)'
      }}
      style={{
        height: BAR_H, minWidth: BAR_H,
        padding: '0 10px',
        background: active ? 'var(--accent)' : 'var(--bg-input)',
        color: active ? 'var(--bg-panel)' : 'var(--text-primary)',
        border: '1px solid var(--border)',
        borderRadius: 999,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        gap: 4, fontSize: 11,
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.5 : 1,
        appearance: 'none', WebkitAppearance: 'none',
        lineHeight: 1, boxSizing: 'border-box',
        transition: 'background 0.15s, border-color 0.15s',
        ...style,
      }}
    >{children}</button>
  )
}

function Dropdown({ value, onChange, options, width, title }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center',
      height: BAR_H + 2, width, boxSizing: 'border-box',
      background: 'var(--bg-input)',
      border: '1px solid var(--border)',
      borderRadius: 999,
      overflow: 'hidden', flexShrink: 0,
    }} title={title}>
      <select value={value || ''}
        onChange={(e) => onChange(e.target.value)}
        style={{
          width: '100%', height: '100%',
          background: 'transparent', color: 'var(--text-primary)',
          border: 'none', outline: 'none',
          padding: '0 18px 0 10px', fontSize: 11,
          appearance: 'none', WebkitAppearance: 'none',
          backgroundImage: 'var(--select-arrow)',
          backgroundRepeat: 'no-repeat',
          backgroundPosition: 'right 6px center',
          cursor: 'pointer',
        }}>
        {options}
      </select>
    </div>
  )
}

// HTML im contentEditable → Format-Runs fuer Rhino RTF (Phase 2)
function htmlToRuns(rootEl) {
  const runs = []
  function flush(text, ctx) {
    if (text === '') return
    runs.push({ text, ...ctx })
  }
  function walk(node, ctx) {
    if (node.nodeType === Node.TEXT_NODE) {
      flush(node.textContent, ctx); return
    }
    if (node.nodeType !== Node.ELEMENT_NODE) return
    const tag = node.tagName.toLowerCase()
    if (tag === 'br') { flush('\n', ctx); return }
    const nc = { ...ctx }
    if (tag === 'b' || tag === 'strong') nc.bold = true
    if (tag === 'i' || tag === 'em')     nc.italic = true
    if (tag === 'u')                     nc.underline = true
    if (tag === 'sup')                   nc.sup = true
    if (tag === 'sub')                   nc.sub = true
    // Computed style oder inline style.
    const cs = window.getComputedStyle ? window.getComputedStyle(node) : null
    if (node.style.fontFamily) nc.font = node.style.fontFamily.replace(/['"]/g, '').split(',')[0].trim()
    else if (cs?.fontFamily && cs.fontFamily !== ctx.font && cs.fontFamily) {
      // nur uebernehmen wenn explizit anders
    }
    if (node.style.color) nc.color = node.style.color
    if (node.style.fontWeight) {
      const fw = node.style.fontWeight
      if (fw === 'bold' || parseInt(fw) >= 600) nc.bold = true
    }
    if (node.style.fontStyle === 'italic') nc.italic = true
    if (node.style.textDecoration?.includes('underline')) nc.underline = true
    // Legacy <font> Element von execCommand
    if (tag === 'font') {
      const c = node.getAttribute('color'); if (c) nc.color = c
      const f = node.getAttribute('face');  if (f) nc.font = f.split(',')[0].trim()
    }
    for (const child of node.childNodes) walk(child, nc)
    // Block-Element bekommt Newline am Ende
    if (tag === 'p' || tag === 'div') {
      if (!runs.length || !runs[runs.length-1].text.endsWith('\n'))
        flush('\n', ctx)
    }
  }
  const baseCtx = { font: null, color: null, bold: false, italic: false,
                     underline: false, sup: false, sub: false }
  for (const child of rootEl.childNodes) walk(child, baseCtx)
  // Trailing-Newline weg
  if (runs.length && runs[runs.length-1].text === '\n') runs.pop()
  return runs
}

function SymbolPopover({ open, onClose, onPick }) {
  if (!open) return null
  return (
    <>
      <div onClick={onClose}
        style={{ position: 'fixed', inset: 0, zIndex: 100,
                  background: 'transparent' }} />
      <div style={{
        position: 'absolute', zIndex: 101,
        marginTop: 4,
        background: 'var(--bg-panel)',
        border: '1px solid var(--border)',
        borderRadius: 6,
        padding: 8,
        boxShadow: '0 4px 16px rgba(0,0,0,0.4)',
        display: 'flex', flexDirection: 'column', gap: 8,
        maxWidth: 360,
      }}>
        {SYMBOL_GROUPS.map((grp, gi) => (
          <div key={gi} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
            <span style={{ fontSize: 9, color: 'var(--text-muted)',
                            textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              {grp.title}
            </span>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 3 }}>
              {grp.symbols.map(s => (
                <button key={s} onClick={() => { onPick(s); onClose() }}
                  title={`Einfügen: ${s}`}
                  onMouseEnter={(e) => {
                    e.currentTarget.style.background = 'var(--bg-item-hover)'
                    e.currentTarget.style.borderColor = 'var(--accent)'
                  }}
                  onMouseLeave={(e) => {
                    e.currentTarget.style.background = 'var(--bg-input)'
                    e.currentTarget.style.borderColor = 'var(--border)'
                  }}
                  style={{
                    width: 30, height: 26,
                    background: 'var(--bg-input)',
                    color: 'var(--text-primary)',
                    border: '1px solid var(--border)',
                    borderRadius: 4,
                    fontSize: 14, lineHeight: 1, cursor: 'pointer', padding: 0,
                    transition: 'background 0.12s, border-color 0.12s',
                  }}>{s}</button>
              ))}
            </div>
          </div>
        ))}
      </div>
    </>
  )
}

export default function TextEditorApp() {
  const [fonts, setFonts] = useState([])
  const [font, setFont] = useState('Helvetica')
  const [size, setSize] = useState(0.20)
  const [bold, setBold] = useState(false)
  const [italic, setItalic] = useState(false)
  const [underline, setUnderline] = useState(false)
  const [align, setAlign] = useState('left')
  const [color, setColor] = useState(null)  // [r,g,b] oder null
  // Neue Options
  const [frame, setFrame] = useState('none')          // none | rect | capsule
  const [horizontalToView, setHorizontalToView] = useState(false)
  const [rotation, setRotation] = useState(0)
  const [maskMargin, setMaskMargin] = useState(0)
  const [symbolsOpen, setSymbolsOpen] = useState(false)
  const [styles, setStyles] = useState([])
  const editorRef = useRef(null)

  useEffect(() => {
    onMessage('INIT', (data) => {
      setFonts(data.fonts || [])
      setStyles(data.styles || [])
      const s = data.settings || {}
      if (s.font) setFont(s.font)
      if (s.size != null) setSize(s.size)
      if (s.bold != null) setBold(!!s.bold)
      if (s.italic != null) setItalic(!!s.italic)
      if (s.underline != null) setUnderline(!!s.underline)
      if (s.align) setAlign(s.align)
      // Editor-Default-Font setzen
      setTimeout(() => editorRef.current?.focus(), 100)
    })
    notifyReady()
  }, [])

  const exec = (cmd, value) => {
    try {
      document.execCommand(cmd, false, value)
      editorRef.current?.focus()
    } catch (e) { console.error('execCommand', cmd, e) }
  }
  const insertText = (s) => {
    try {
      document.execCommand('insertText', false, s)
      editorRef.current?.focus()
    } catch (e) { console.error('insertText', e) }
  }

  const toggleBold = () => { setBold(b => !b); exec('bold') }
  const toggleItalic = () => { setItalic(b => !b); exec('italic') }
  const toggleUnderline = () => { setUnderline(b => !b); exec('underline') }
  const doAlign = (a) => { setAlign(a)
    exec(a === 'center' ? 'justifyCenter' : a === 'right' ? 'justifyRight' : 'justifyLeft') }
  const doSup = () => exec('superscript')
  const doSub = () => exec('subscript')
  // Stil anwenden: Toolbar-State setzen + (wenn Auswahl im Editor) via
  // execCommand auf die Selektion applizieren.
  const applyStyle = (style) => {
    if (!style) return
    // Toolbar-State synchronisieren
    if (style.font) setFont(style.font)
    if (style.size != null) setSize(style.size)
    setBold(!!style.bold)
    setItalic(!!style.italic)
    setUnderline(!!style.underline)
    if (style.align) setAlign(style.align)
    // Auf Selektion applizieren (oder zumindest fuer kommendes Tippen)
    try {
      const sel = window.getSelection()
      const hasSel = sel && sel.rangeCount > 0 && sel.toString().length > 0
      document.execCommand('styleWithCSS', false, true)
      if (style.font) document.execCommand('fontName', false, style.font)
      // Bold/Italic/Underline togglen, falls Selektion da ist oder nicht
      const wantBold = !!style.bold
      const wantItal = !!style.italic
      const wantUnd  = !!style.underline
      if (document.queryCommandState('bold') !== wantBold)
        document.execCommand('bold')
      if (document.queryCommandState('italic') !== wantItal)
        document.execCommand('italic')
      if (document.queryCommandState('underline') !== wantUnd)
        document.execCommand('underline')
    } catch (e) { console.error('applyStyle', e) }
    editorRef.current?.focus()
  }

  const onColorPick = (hex) => {
    const m = hex.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i)
    if (m) setColor([parseInt(m[1],16), parseInt(m[2],16), parseInt(m[3],16)])
    exec('foreColor', hex)
  }
  const clearColor = () => { setColor(null); exec('foreColor', '#000000') }

  const onCommit = () => {
    const el = editorRef.current
    if (!el) return
    const text = el.innerText || ''
    if (!text.trim()) return
    // Phase 2: Format-Runs aus HTML extrahieren fuer Rich-Text-Mapping
    let runs = null
    try { runs = htmlToRuns(el) } catch (e) { console.error(e) }
    send('COMMIT', {
      text,
      runs,
      settings: {
        font, size, bold, italic, underline, align, color,
        frame, horizontalToView, rotation, maskMargin,
      },
    })
  }
  const onCancel = () => send('CANCEL', {})

  return (
    <div style={{
      padding: 10, height: '100vh',
      display: 'flex', flexDirection: 'column', gap: 8,
      fontFamily: 'var(--font)', color: 'var(--text-primary)',
      background: 'var(--bg-panel)',
      boxSizing: 'border-box', overflow: 'hidden',
    }}>
      {/* Toolbar Row 1: Stil | Font | Size | Color | Layer-Reset */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
        <Dropdown value=""
          onChange={(v) => {
            const st = styles.find(s => s.id === v)
            if (st) applyStyle(st)
          }}
          width={150}
          title="Text-Stil anwenden (auf Selektion oder als Default fuer kommendes Tippen)"
          options={[
            <option key="__none__" value="">— Stil wählen —</option>,
            ...styles.map(s => (
              <option key={s.id} value={s.id}>{s.name}</option>
            )),
          ]} />
        <Dropdown value={font} onChange={(v) => { setFont(v); exec('fontName', v) }}
          width={150} title="Schrift"
          options={
            fonts.length === 0
              ? <option value="">— Fonts laden —</option>
              : fonts.map(f => <option key={f} value={f}>{f}</option>)
          } />
        <Dropdown value={String(size)}
          onChange={(v) => setSize(parseFloat(v))}
          width={90} title="Texthöhe (m)"
          options={SIZE_PRESETS.map(s => (
            <option key={s} value={String(s)}>{s.toFixed(2)} m</option>
          ))}
        />
        <label style={{
          display: 'inline-flex', alignItems: 'center', gap: 4,
          height: BAR_H + 2, padding: '0 8px',
          background: 'var(--bg-input)', border: '1px solid var(--border)',
          borderRadius: 999, cursor: 'pointer', flexShrink: 0,
          boxSizing: 'border-box',
        }} title="Textfarbe">
          <input type="color"
            style={{ width: 16, height: 16, border: 'none', padding: 0, background: 'transparent' }}
            onChange={(e) => onColorPick(e.target.value)} />
          <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>Farbe</span>
        </label>
        <Pill onClick={clearColor} title="Layer-Farbe verwenden">Layer</Pill>
      </div>

      {/* Toolbar Row 2: B I U + Align + Sup/Sub */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
        <Pill active={bold} onClick={toggleBold} title="Fett">
          <Icon name="format_bold" size={13} />
        </Pill>
        <Pill active={italic} onClick={toggleItalic} title="Kursiv">
          <Icon name="format_italic" size={13} />
        </Pill>
        <Pill active={underline} onClick={toggleUnderline} title="Unterstrichen">
          <Icon name="format_underlined" size={13} />
        </Pill>
        <div style={{ width: 6 }} />
        <Pill active={align === 'left'} onClick={() => doAlign('left')} title="Links">
          <Icon name="format_align_left" size={13} />
        </Pill>
        <Pill active={align === 'center'} onClick={() => doAlign('center')} title="Mittig">
          <Icon name="format_align_center" size={13} />
        </Pill>
        <Pill active={align === 'right'} onClick={() => doAlign('right')} title="Rechts">
          <Icon name="format_align_right" size={13} />
        </Pill>
        <div style={{ width: 6 }} />
        <Pill onClick={doSup} title="Hochstellen (x²)" style={{ fontFamily: 'serif' }}>x²</Pill>
        <Pill onClick={doSub} title="Tiefstellen (x₂)" style={{ fontFamily: 'serif' }}>x₂</Pill>
      </div>

      {/* Toolbar Row 3: Frame / Rotation / Mask / Horizontal-to-view / Symbole */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
        <Dropdown value={frame} onChange={setFrame} width={130}
          title="Rahmen um den Text"
          options={FRAME_OPTIONS.map(o => (
            <option key={o.value} value={o.value}>{o.label}</option>
          ))} />
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 4,
          height: BAR_H + 2, padding: '0 10px', boxSizing: 'border-box',
          background: 'var(--bg-input)', border: '1px solid var(--border)',
          borderRadius: 999, flexShrink: 0,
        }} title="Mask-Rand (m) — weisser Hintergrund hinter Text">
          <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>Mask</span>
          <input type="number" step="0.05" min="0"
            value={maskMargin}
            onChange={(e) => setMaskMargin(parseFloat(e.target.value) || 0)}
            style={{
              width: 50, background: 'transparent', border: 'none', outline: 'none',
              color: 'var(--text-primary)', fontSize: 11,
              fontFamily: 'DM Mono, monospace', padding: 0, textAlign: 'right',
              appearance: 'auto',
            }} />
          <span style={{ fontSize: 9, color: 'var(--text-muted)' }}>m</span>
        </div>
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 4,
          height: BAR_H + 2, padding: '0 10px', boxSizing: 'border-box',
          background: 'var(--bg-input)', border: '1px solid var(--border)',
          borderRadius: 999, flexShrink: 0,
        }} title="Rotation in Grad">
          <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>Rot</span>
          <input type="number" step="1" value={rotation}
            onChange={(e) => setRotation(parseFloat(e.target.value) || 0)}
            style={{
              width: 50, background: 'transparent', border: 'none', outline: 'none',
              color: 'var(--text-primary)', fontSize: 11,
              fontFamily: 'DM Mono, monospace', padding: 0, textAlign: 'right',
              appearance: 'auto',
            }} />
          <span style={{ fontSize: 9, color: 'var(--text-muted)' }}>°</span>
        </div>
        <Pill active={horizontalToView}
          onClick={() => setHorizontalToView(b => !b)}
          title="Text steht immer zur Kamera (DrawForward)">
          <Icon name="screen_rotation" size={13} />
          <span style={{ fontSize: 10 }}>Zur Kamera</span>
        </Pill>
        <div style={{ position: 'relative' }}>
          <Pill onClick={() => setSymbolsOpen(o => !o)}
            active={symbolsOpen}
            title="Sonderzeichen einfügen">
            <Icon name="emoji_symbols" size={13} />
            <span style={{ fontSize: 10 }}>Symbole</span>
          </Pill>
          <SymbolPopover
            open={symbolsOpen}
            onClose={() => setSymbolsOpen(false)}
            onPick={(s) => insertText(s)} />
        </div>
      </div>

      {/* WYSIWYG Editor */}
      <div
        ref={editorRef}
        contentEditable
        suppressContentEditableWarning
        spellCheck={false}
        style={{
          flex: 1, minHeight: 100,
          padding: 12,
          background: 'var(--bg-input)',
          color: 'var(--text-primary)',
          border: '1px solid var(--border)',
          borderRadius: 6,
          fontFamily: font,
          fontSize: 14, lineHeight: 1.5,
          outline: 'none',
          overflowY: 'auto',
          textAlign: align,
        }}
      />

      {/* Bottom Buttons */}
      <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 6 }}>
        <Pill onClick={onCancel}>Abbrechen</Pill>
        <button onClick={onCommit}
          style={{
            height: BAR_H + 2, padding: '0 14px',
            background: 'var(--accent)',
            color: 'var(--bg-panel)',
            border: '1px solid var(--accent)',
            borderRadius: 999,
            fontSize: 11, fontWeight: 600,
            cursor: 'pointer',
            appearance: 'none', WebkitAppearance: 'none',
            boxSizing: 'border-box',
          }}>Einfügen</button>
      </div>
    </div>
  )
}
