// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useEffect } from 'react'
import Icon from './components/Icon'
import ContextMenu from './components/ContextMenu'
import { BarToggle, BarButton, BarCombo, BAR_H } from './components/BarControls'
import {
  onMessage, notifyReady,
  setOverridesEnabled, addRule, updateRule, deleteRule,
  reorderRules, duplicateRule, reapplyOverrides, clearOverrideRules,
  savePreset, loadPreset, deletePreset,
  saveRuleTemplate, addFromTemplate, deleteRuleTemplate,
} from './lib/rhinoBridge'

const COND_TYPES = [
  { value: 'layer_name',  label: 'Layer-Name' },
  { value: 'user_string', label: 'UserString' },
  { value: 'object_name', label: 'Objekt-Name' },
]

const OPS = [
  { value: 'equals',      label: '=' },
  { value: 'not_equals',  label: '≠' },
  { value: 'contains',    label: 'enthält' },
  { value: 'starts_with', label: 'beginnt mit' },
  { value: 'ends_with',   label: 'endet mit' },
]

const labelXs = {
  fontSize: 9, color: 'var(--text-muted)',
  textTransform: 'uppercase', letterSpacing: '0.06em',
  fontWeight: 600,
}

const pillInput = {
  height: BAR_H,
  background: 'var(--bg-input)',
  border: '1px solid var(--border)',
  borderRadius: 999,
  color: 'var(--text-primary)',
  fontSize: 11, fontFamily: 'var(--font)',
  padding: '0 10px',
  outline: 'none',
  boxSizing: 'border-box',
}

// ---------------------------------------------------------------------------

function ConditionLeaf({ cond, layers, onChange, onRemove, canRemove }) {
  const t = cond?.type || 'layer_name'
  const op = cond?.operator || 'equals'
  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: 6,
      padding: 8,
      border: '1px solid var(--border-light)', borderRadius: 'var(--r-lg)',
      background: 'var(--bg-section)',
    }}>
      <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
        <BarCombo stretch
          value={t}
          onChange={(v) => onChange({ ...cond, type: v })}>
          {COND_TYPES.map(c => <option key={c.value} value={c.value}>{c.label}</option>)}
        </BarCombo>
        {canRemove && (
          <BarButton icon="close" onClick={onRemove}
            title="Diese Bedingung entfernen" />
        )}
      </div>
      {t === 'user_string' && (
        <input
          type="text" placeholder="Key"
          value={cond?.key || ''}
          onChange={(e) => onChange({ ...cond, key: e.target.value })}
          style={{ ...pillInput, width: '100%' }}
        />
      )}
      <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
        <BarCombo
          value={op}
          onChange={(v) => onChange({ ...cond, operator: v })}
          width={100}>
          {OPS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
        </BarCombo>
        {t === 'layer_name' ? (
          <BarCombo stretch
            value={cond?.value || ''}
            onChange={(v) => onChange({ ...cond, value: v })}>
            <option value="">—</option>
            {(layers || []).map(l => (
              <option key={l.fullPath} value={l.fullPath}>{l.fullPath}</option>
            ))}
          </BarCombo>
        ) : (
          <input
            type="text" placeholder="Wert"
            value={cond?.value || ''}
            onChange={(e) => onChange({ ...cond, value: e.target.value })}
            style={{ ...pillInput, flex: 1, minWidth: 0 }}
          />
        )}
      </div>
    </div>
  )
}

function ConditionsEditor({ rule, layers, onChange }) {
  const conds = rule.conditions && rule.conditions.length > 0
    ? rule.conditions
    : (rule.condition ? [rule.condition] : [{ type: 'layer_name', operator: 'equals', value: '' }])
  const logic = (rule.conditionsLogic || 'and').toLowerCase()

  const update = (i, newCond) => {
    const next = conds.slice()
    next[i] = newCond
    onChange({ ...rule, conditions: next, condition: undefined })
  }
  const remove = (i) => {
    const next = conds.slice()
    next.splice(i, 1)
    onChange({ ...rule, conditions: next.length ? next : [{ type: 'layer_name', operator: 'equals', value: '' }], condition: undefined })
  }
  const add = () => {
    const next = conds.slice()
    next.push({ type: 'layer_name', operator: 'equals', value: '' })
    onChange({ ...rule, conditions: next, condition: undefined })
  }
  const setLogic = (l) => onChange({ ...rule, conditionsLogic: l })

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {conds.length > 1 && (
        <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
          <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>Logik:</span>
          <BarToggle label="AND"
            active={logic === 'and'}
            onClick={() => setLogic('and')}
            title="Alle Bedingungen müssen zutreffen" />
          <BarToggle label="OR"
            active={logic === 'or'}
            onClick={() => setLogic('or')}
            title="Mindestens eine Bedingung muss zutreffen" />
        </div>
      )}
      {conds.map((c, i) => (
        <ConditionLeaf
          key={i}
          cond={c}
          layers={layers}
          onChange={(nc) => update(i, nc)}
          onRemove={() => remove(i)}
          canRemove={conds.length > 1}
        />
      ))}
      <div style={{ alignSelf: 'flex-start' }}>
        <BarToggle icon="add" label="Bedingung"
          onClick={add}
          title="Weitere Bedingung hinzufügen" />
      </div>
    </div>
  )
}

function ActionRow({ label, icon, active, onToggle, children }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <label style={{
        display: 'flex', alignItems: 'center', gap: 8,
        cursor: 'pointer', userSelect: 'none',
      }}>
        <input type="checkbox" checked={active} onChange={onToggle}
               style={{ width: 'auto', height: 'auto', padding: 0 }} />
        <Icon name={icon} size={14} style={{ color: 'var(--text-muted)' }} />
        <span style={{ fontSize: 11, color: active ? 'var(--text-primary)' : 'var(--text-muted)' }}>
          {label}
        </span>
      </label>
      {active && (
        <div style={{ marginLeft: 26, display: 'flex', gap: 6, alignItems: 'center' }}>
          {children}
        </div>
      )}
    </div>
  )
}

function ActionsEditor({ actions, linetypes, hatchPatterns, onChange }) {
  const a = actions || {}
  const setProp = (key, val) => {
    const next = { ...a }
    if (val === '' || val === null || val === undefined) {
      delete next[key]
    } else {
      next[key] = val
    }
    onChange(next)
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      <ActionRow
        label="Farbe" icon="palette"
        active={'color' in a}
        onToggle={(e) => setProp('color', e.target.checked ? (a.color || '#888888') : '')}
      >
        <input
          type="color"
          value={a.color || '#888888'}
          onChange={(e) => setProp('color', e.target.value)}
          style={{ width: 32, height: BAR_H, padding: 0, flexShrink: 0,
                    border: '1px solid var(--border)', borderRadius: 999,
                    background: 'var(--bg-input)' }}
        />
        <input
          type="text"
          value={a.color || ''}
          placeholder="#rrggbb"
          onChange={(e) => setProp('color', e.target.value)}
          style={{ ...pillInput, flex: 1, minWidth: 0, fontFamily: 'DM Mono, monospace' }}
        />
      </ActionRow>

      <ActionRow
        label="Strichstärke" icon="line_weight"
        active={'lineweight' in a}
        onToggle={(e) => setProp('lineweight', e.target.checked ? (a.lineweight ?? 0.25) : '')}
      >
        <input
          type="number" step={0.05} min={0}
          value={a.lineweight ?? ''}
          onChange={(e) => setProp('lineweight', parseFloat(e.target.value) || 0)}
          style={{ ...pillInput, width: 80, fontFamily: 'DM Mono, monospace' }}
        />
        <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>mm</span>
      </ActionRow>

      <ActionRow
        label="Linientyp" icon="more_horiz"
        active={'linetype' in a}
        onToggle={(e) => setProp('linetype', e.target.checked ? (a.linetype || 'Continuous') : '')}
      >
        <BarCombo stretch
          value={a.linetype || ''}
          onChange={(v) => setProp('linetype', v)}>
          <option value="">—</option>
          {(linetypes || []).map(lt => <option key={lt} value={lt}>{lt}</option>)}
        </BarCombo>
      </ActionRow>

      <ActionRow
        label="Schraffur" icon="grid_view"
        active={'hatchPattern' in a}
        onToggle={(e) => setProp('hatchPattern', e.target.checked ? (a.hatchPattern || 'Solid') : '')}
      >
        <BarCombo stretch
          value={a.hatchPattern || ''}
          onChange={(v) => setProp('hatchPattern', v)}>
          <option value="">—</option>
          {(hatchPatterns || []).map(hp => <option key={hp} value={hp}>{hp}</option>)}
        </BarCombo>
      </ActionRow>

      <ActionRow
        label="Schraffur-Skala" icon="aspect_ratio"
        active={'hatchScale' in a}
        onToggle={(e) => setProp('hatchScale', e.target.checked ? (a.hatchScale ?? 1.0) : '')}
      >
        <input
          type="number" step={0.1} min={0.001}
          value={a.hatchScale ?? ''}
          onChange={(e) => setProp('hatchScale', parseFloat(e.target.value) || 1.0)}
          style={{ ...pillInput, width: 80, fontFamily: 'DM Mono, monospace' }}
        />
      </ActionRow>

      <div style={{ fontSize: 9, color: 'var(--text-muted)', fontStyle: 'italic', lineHeight: 1.4 }}>
        Hatch-Override modifiziert nur existierende Schraffuren. Curves ohne Hatch bleiben unverändert.
      </div>
    </div>
  )
}

function RuleCard({ rule, index, total, layers, linetypes, hatchPatterns, onPatch, onDelete, onDuplicate, onMoveUp, onMoveDown, onContextMenu }) {
  const [open, setOpen] = useState(false)

  const summarize = () => {
    const conds = (rule.conditions && rule.conditions.length > 0)
      ? rule.conditions
      : (rule.condition ? [rule.condition] : [])
    const logic = (rule.conditionsLogic || 'and').toUpperCase()
    const a = rule.actions || {}
    const parts = []
    const condTexts = conds.map(c => {
      if (c.type === 'layer_name')  return `Layer ${c.operator} "${c.value || '?'}"`
      if (c.type === 'user_string') return `${c.key || '?'} ${c.operator} "${c.value || '?'}"`
      if (c.type === 'object_name') return `Name ${c.operator} "${c.value || '?'}"`
      return ''
    }).filter(Boolean)
    if (condTexts.length === 1) parts.push(condTexts[0])
    else if (condTexts.length > 1) parts.push(condTexts.join(` ${logic} `))
    const acts = Object.keys(a)
    if (acts.length) parts.push('→ ' + acts.join(', '))
    return parts.join('  ')
  }

  return (
    <div
      onContextMenu={(ev) => { if (onContextMenu) { ev.preventDefault(); onContextMenu(ev) } }}
      style={{
      border: '1px solid var(--border)', borderRadius: 'var(--r-lg)',
      background: 'var(--bg-section)', padding: 8,
      marginBottom: 8,
      opacity: rule.enabled === false ? 0.5 : 1,
    }}>
      {/* Row 1: index + checkbox + name + edit-toggle */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
        <span className="chip" style={{ flexShrink: 0 }}>#{index + 1}</span>
        <input
          type="checkbox"
          checked={rule.enabled !== false}
          onChange={(e) => onPatch({ ...rule, enabled: e.target.checked })}
          title="Regel aktiv"
          style={{ flexShrink: 0, width: 'auto', height: 'auto', padding: 0 }}
        />
        <input
          type="text"
          value={rule.name || ''}
          placeholder="Regel-Name"
          onChange={(e) => onPatch({ ...rule, name: e.target.value })}
          style={{ ...pillInput, flex: 1, minWidth: 0 }}
        />
        <BarButton icon={open ? 'expand_less' : 'edit'}
          onClick={() => setOpen(!open)}
          title={open ? 'Einklappen' : 'Bearbeiten'} />
      </div>

      {!open && (
        <div style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 6, marginLeft: 4,
                      overflowWrap: 'break-word', wordBreak: 'break-word' }}>
          {summarize() || '(leer)'}
        </div>
      )}

      {open && (
        <>
          <div style={{ display: 'flex', alignItems: 'center', gap: 4, marginTop: 8 }}>
            <BarButton icon="arrow_upward"
              onClick={() => onMoveUp()}
              disabled={index === 0}
              title="Prio höher (nach oben)" />
            <BarButton icon="arrow_downward"
              onClick={() => onMoveDown()}
              disabled={index === total - 1}
              title="Prio tiefer (nach unten)" />
            <BarButton icon="content_copy"
              onClick={() => onDuplicate()}
              title="Duplizieren" />
            <div style={{ flex: 1 }} />
            <BarButton icon="delete"
              onClick={() => { if (confirm(`Regel "${rule.name}" löschen?`)) onDelete() }}
              title="Löschen" />
          </div>

          <div style={{ marginTop: 10, display: 'flex', flexDirection: 'column', gap: 10 }}>
            <div>
              <div style={{ ...labelXs, marginBottom: 6 }}>Bedingungen</div>
              <ConditionsEditor rule={rule} layers={layers} onChange={onPatch} />
            </div>
            <div>
              <div style={{ ...labelXs, marginBottom: 6 }}>Überschreibungen</div>
              <ActionsEditor
                actions={rule.actions}
                linetypes={linetypes}
                hatchPatterns={hatchPatterns}
                onChange={(a) => onPatch({ ...rule, actions: a })}
              />
            </div>
          </div>
        </>
      )}
    </div>
  )
}

// ---------------------------------------------------------------------------

export default function OverridesApp() {
  const [state, setState] = useState({
    enabled: false, rules: [], layers: [], linetypes: [], hatchPatterns: [], presets: [],
    activePreset: null, ruleTemplates: [],
  })
  const [selectedPreset, setSelectedPreset] = useState('')
  const [selectedTemplate, setSelectedTemplate] = useState('')
  const [ctxMenu, setCtxMenu] = useState(null)  // {x, y, ruleId}

  useEffect(() => {
    onMessage('STATE', (s) => {
      setState((prev) => ({ ...prev, ...s }))
      // Dropdown synct sich auf das Backend-activePreset nur wenn der wert
      // gesetzt ist (z.B. nachdem Topbar eine Kombination geladen hat).
      // Wenn activePreset null wird (Rules wurden gerade editiert -> variant C),
      // BEHALTEN wir die lokale Auswahl — sonst weiss der Save-Button nicht
      // mehr in welche Kombination der User gerade editiert.
      if (s && s.activePreset) {
        setSelectedPreset(s.activePreset)
      }
    })
    notifyReady()
  }, [])

  const onPatch = (rule) => updateRule(rule.id, rule)
  const onMove = (id, delta) => {
    const ids = state.rules.map(r => r.id)
    const i = ids.indexOf(id)
    const j = i + delta
    if (i < 0 || j < 0 || j >= ids.length) return
    const next = ids.slice()
    next.splice(j, 0, next.splice(i, 1)[0])
    reorderRules(next)
  }

  // Kontextmenue fuer eine Regel — analog Ausschnitte/Ebenen.
  const ruleCtxItems = (ruleId) => {
    const rule = (state.rules || []).find(r => r.id === ruleId)
    if (!rule) return []
    const i = state.rules.findIndex(r => r.id === ruleId)
    const enabled = rule.enabled !== false
    return [
      { label: enabled ? 'Deaktivieren' : 'Aktivieren',
        icon: enabled ? 'visibility_off' : 'visibility',
        onClick: () => updateRule(ruleId, { ...rule, enabled: !enabled }) },
      { divider: true },
      { label: 'Prio hoeher (nach oben)',
        icon: 'arrow_upward', disabled: i <= 0,
        onClick: () => onMove(ruleId, -1) },
      { label: 'Prio tiefer (nach unten)',
        icon: 'arrow_downward', disabled: i >= state.rules.length - 1,
        onClick: () => onMove(ruleId, +1) },
      { divider: true },
      { label: 'Duplizieren',
        icon: 'content_copy',
        onClick: () => duplicateRule(ruleId) },
      { label: 'Als Vorlage speichern…',
        icon: 'bookmark_add',
        onClick: () => {
          const def = rule.name || 'Vorlage'
          const name = window.prompt('Name für Vorlage:', def)
          if (!name || !name.trim()) return
          saveRuleTemplate(name.trim(), rule)
        } },
      { divider: true },
      { label: 'Löschen',
        icon: 'delete', danger: true,
        onClick: () => {
          if (window.confirm(`Regel "${rule.name || '(ohne Name)'}" löschen?`)) deleteRule(ruleId)
        } },
    ]
  }


  return (
    <div style={{
      width: '100%', height: '100%',
      display: 'flex', flexDirection: 'column',
      padding: 10, gap: 10,
      fontFamily: 'var(--font)', color: 'var(--text-primary)',
      background: 'var(--bg-base)',
      boxSizing: 'border-box',
    }}>
      {/* Override-Kombinationen — Dropdown plus kontextabhaengiger Save.
          Globaler AN/AUS-Toggle ist jetzt in der Oberleiste, hier ueber-
          fluessig. Reapply-Button raus: Backend re-applied automatisch
          bei jeder Aenderung. */}
      <div style={{
        display: 'flex', flexDirection: 'column', gap: 6,
        padding: 10,
        background: 'var(--bg-section)',
        border: '1px solid var(--border)',
        borderRadius: 'var(--r-lg)',
      }}>
        <span style={labelXs}>Override-Kombinationen</span>
        <BarCombo stretch
          value={selectedPreset}
          onChange={(v) => {
            setSelectedPreset(v)
            if (v) {
              loadPreset(v, 'replace')
            } else {
              clearOverrideRules()
            }
          }}
          title="Kombination zum Bearbeiten oeffnen">
          <option value="">— neu / keine —</option>
          {(state.presets || []).map(p => (
            <option key={p.name} value={p.name}>
              {p.name} ({p.ruleCount})
            </option>
          ))}
        </BarCombo>
        <div style={{ display: 'flex', gap: 6 }}>
          <div style={{ flex: 1 }}>
            <BarToggle icon="save"
              label={selectedPreset ? 'Speichern' : 'Als Kombination speichern…'}
              active={state.rules.length > 0}
              disabled={state.rules.length === 0}
              onClick={() => {
                if (selectedPreset) { savePreset(selectedPreset); return }
                const existing = (state.presets || []).map(p => p.name)
                const def = `Kombination ${existing.length + 1}`
                const name = window.prompt('Name für neue Kombination:', def)
                if (!name || !name.trim()) return
                const t = name.trim()
                if (existing.includes(t) && !window.confirm(`Kombination "${t}" überschreiben?`)) return
                savePreset(t)
                setSelectedPreset(t)
              }}
              title={selectedPreset
                ? `Änderungen in "${selectedPreset}" speichern`
                : 'Aktuelle Regeln als neue Kombination speichern'} />
          </div>
          <BarButton icon="delete"
            onClick={() => {
              if (!selectedPreset) return
              if (!window.confirm(`Kombination "${selectedPreset}" dauerhaft loeschen?`)) return
              deletePreset(selectedPreset)
              setSelectedPreset('')
            }}
            disabled={!selectedPreset}
            title="Gewaehlte Kombination dauerhaft loeschen" />
        </div>
      </div>

      {/* Neue Regel: leere Regel ODER aus Vorlage. */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 6,
        padding: '8px 10px',
        background: 'var(--bg-section)',
        border: '1px solid var(--border)',
        borderRadius: 'var(--r-lg)',
      }}>
        <button
          onClick={() => addRule({})}
          className="btn-add"
          title="Leere Regel oben einfuegen"
        >
          <Icon name="add" size={16} />
        </button>
        <BarCombo stretch
          value={selectedTemplate}
          onChange={(v) => {
            if (!v) { setSelectedTemplate(''); return }
            if (v === '__delete__') {
              if (!selectedTemplate) return
              if (!window.confirm(`Vorlage "${selectedTemplate}" dauerhaft loeschen?`)) return
              deleteRuleTemplate(selectedTemplate)
              setSelectedTemplate('')
              return
            }
            addFromTemplate(v)
            setSelectedTemplate(v)
          }}
          title="Regel aus Vorlage einfuegen">
          <option value="">+ Aus Vorlage…</option>
          {(state.ruleTemplates || []).map(t => (
            <option key={t.name} value={t.name}>{t.name}</option>
          ))}
          {selectedTemplate && (state.ruleTemplates || []).some(t => t.name === selectedTemplate) && (
            <>
              <option disabled>──────────</option>
              <option value="__delete__">🗑 "{selectedTemplate}" loeschen</option>
            </>
          )}
        </BarCombo>
      </div>

      <div style={{ fontSize: 10, color: 'var(--text-muted)', fontStyle: 'italic', lineHeight: 1.4 }}>
        Regeln sind additiv. Bei Konflikt gewinnt die <b>oberste</b>.
      </div>

      {/* Rule list */}
      <div style={{ flex: 1, overflowY: 'auto', overflowX: 'hidden', minHeight: 0 }}>
        {(state.rules || []).length === 0 && (
          <div style={{
            padding: '32px 16px', textAlign: 'center',
            color: 'var(--text-muted)', fontSize: 11,
            border: '1px dashed var(--border)',
            borderRadius: 'var(--r-lg)',
            background: 'var(--bg-section)',
          }}>
            <Icon name="auto_fix_high" size={32} style={{ color: 'var(--text-muted)', opacity: 0.5 }} />
            <div style={{ marginTop: 8 }}>Noch keine Regeln.</div>
            <div style={{ marginTop: 4, fontSize: 10 }}>
              Oben <Icon name="add" size={11} /> klicken um eine neue Regel zu erstellen.
            </div>
          </div>
        )}
        {(state.rules || []).map((r, i) => (
          <RuleCard
            key={r.id}
            rule={r}
            index={i}
            total={state.rules.length}
            layers={state.layers}
            linetypes={state.linetypes}
            hatchPatterns={state.hatchPatterns}
            onPatch={onPatch}
            onDelete={() => deleteRule(r.id)}
            onDuplicate={() => duplicateRule(r.id)}
            onMoveUp={() => onMove(r.id, -1)}
            onMoveDown={() => onMove(r.id, +1)}
            onContextMenu={(ev) => setCtxMenu({ x: ev.clientX, y: ev.clientY, ruleId: r.id })}
          />
        ))}
      </div>
      {ctxMenu && (
        <ContextMenu
          x={ctxMenu.x}
          y={ctxMenu.y}
          items={ruleCtxItems(ctxMenu.ruleId)}
          onClose={() => setCtxMenu(null)}
        />
      )}
    </div>
  )
}
