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

function send(type, payload = {}) {
  if (!window.RHINO_MODE) { console.log('[Swisstopo] →', type, payload); return }
  document.title = 'RHINOMSG::' + JSON.stringify({ type, payload })
}

function Field({ label, hint, children }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4, padding: '6px 0' }}>
      <span className="label-xs">{label}</span>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>{children}</div>
      {hint && (
        <span style={{ fontSize: 9, color: 'var(--text-muted)', lineHeight: 1.4 }}>{hint}</span>
      )}
    </div>
  )
}

function SectionLabel({ children }) {
  return (
    <div style={{
      fontSize: 9, color: 'var(--text-muted)', fontWeight: 600,
      letterSpacing: 0.5, textTransform: 'uppercase',
      padding: '10px 0 4px',
      borderTop: '1px solid var(--border-light)',
      marginTop: 8,
    }}>{children}</div>
  )
}

function Radio({ value, options, onChange }) {
  return (
    <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
      {options.map(o => (
        <button key={o.value}
          onClick={() => onChange(o.value)}
          className={value === o.value ? 'btn-contained' : 'btn-outlined'}
          style={{ padding: '4px 10px', fontSize: 10 }}
          title={o.hint || ''}
        >
          {o.label}
        </button>
      ))}
    </div>
  )
}

export default function SwisstopoApp() {
  const [ebenen,       setEbenen]       = useState([])
  // Standort
  const [searchText,   setSearchText]   = useState('')
  const [center,       setCenter]       = useState(null)  // {e, n, label}
  const [searching,    setSearching]    = useState(false)
  // Optionen
  const [radius,       setRadius]       = useState(100)
  const [getBuild,     setGetBuild]     = useState(true)
  const [buildVersion, setBuildVersion] = useState('v2')   // v2 (stabil) / v3 (beta)
  const [buildVariant, setBuildVariant] = useState('separated')
  const [getTerrain,   setGetTerrain]   = useState(false)
  const [getOrtho,     setGetOrtho]     = useState(false)
  const [getContours,  setGetContours]  = useState(false)
  const [getContourTin,setGetContourTin]= useState(false)
  const [getContourSchicht, setGetContourSchicht] = useState(false)
  const [contourInt,   setContourInt]   = useState('2.0')
  // TLM3D deaktiviert: swisstopo liefert nur GDB/SHP/GPKG — kein DXF.
  // Rhino kann das nicht nativ importieren; OSM-Importer ist die Alternative
  // fuer Vektordaten (Strassen/Wasser/Gebaeude).
  const getTlm = false
  const tlmKinds = {}
  const [shift,        setShift]        = useState(true)
  const [autoZoom,     setAutoZoom]     = useState(true)
  const [replaceExisting, setReplaceExisting] = useState(true)
  const [clipToBbox,   setClipToBbox]   = useState(false)
  const [terrainRes,   setTerrainRes]   = useState('2.0')
  // Live-Log
  const [logs,         setLogs]         = useState([])
  const [running,      setRunning]      = useState(false)
  const [done,         setDone]         = useState(false)
  const logRef = useRef(null)

  useEffect(() => {
    onMessage('SWISSTOPO_STATE', ({ ebenen }) => {
      if (Array.isArray(ebenen)) setEbenen(ebenen)
    })
    onMessage('GEOCODE_RESULT', ({ result }) => {
      setSearching(false)
      if (result && result.e != null && result.n != null) {
        setCenter({ e: result.e, n: result.n, label: result.label || searchText })
      } else {
        setCenter(null)
        addLog('Keine Adresse gefunden')
      }
    })
    onMessage('SWISSTOPO_LOG', ({ msg }) => addLog(msg))
    onMessage('IMPORT_DONE', ({ count }) => {
      setRunning(false)
      setDone(true)
      addLog(`✓ Fertig — ${count} Objekt(e) importiert`)
    })
    notifyReady()
    const blockContext = (ev) => ev.preventDefault()
    document.addEventListener('contextmenu', blockContext)
    return () => document.removeEventListener('contextmenu', blockContext)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // Auto-Scroll Log
  useEffect(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight
  }, [logs])

  const addLog = (m) => setLogs(l => [...l, m])

  const handleSearch = () => {
    const t = searchText.trim()
    if (!t) return
    setSearching(true)
    setCenter(null)
    addLog(`Suche '${t}'...`)
    send('GEOCODE', { text: t })
  }

  const handleManualCoords = (eRaw, nRaw) => {
    const e = parseFloat(eRaw), n = parseFloat(nRaw)
    if (e > 2000000 && n > 1000000) {
      setCenter({ e, n, label: `LV95 manuell` })
    } else {
      setCenter(null)
    }
  }

  const handleImport = () => {
    if (!center) { addLog('Bitte zuerst einen Standort wählen'); return }
    if (!getBuild && !getTerrain && !getContours && !getContourTin && !getContourSchicht && !getTlm) {
      addLog('Mindestens eine Datenquelle wählen'); return
    }
    setLogs([])
    setRunning(true)
    setDone(false)
    const kinds = []
    if (getBuild)         kinds.push('buildings')
    if (getTerrain)       kinds.push('terrain')
    if (getOrtho && getTerrain) kinds.push('ortho')
    if (getContours)      kinds.push('contours')
    if (getContourTin)    kinds.push('contour_tin')
    if (getContourSchicht)kinds.push('contour_schicht')
    if (getTlm)           kinds.push('tlm')
    const tlmList = Object.entries(tlmKinds).filter(([, v]) => v).map(([k]) => k)
    send('RUN_IMPORT', {
      centerE: center.e,
      centerN: center.n,
      radius: Number(radius),
      kinds,
      shiftToOrigin: shift,
      autoZoom,
      replaceExisting,
      clipToBbox,
      terrainResolution: terrainRes,
      buildVersion,
      buildVariant,
      contourInterval: contourInt,
      tlmKinds: tlmList,
    })
  }

  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: 'var(--bg-dialog)',
      display: 'flex', flexDirection: 'column',
      fontFamily: 'var(--font)', color: 'var(--text-primary)',
      overflow: 'hidden',
    }}>
      <div style={{ flex: 1, overflowY: 'auto', padding: '10px 16px' }}>

        <SectionLabel>Standort</SectionLabel>

        <Field label="ADRESSE / ORT" hint='z.B. "Bahnhofstrasse 1, Zürich" oder "Bern"'>
          <input
            value={searchText}
            onChange={(e) => setSearchText(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') handleSearch() }}
            placeholder="Adresse oder Ortsname"
            style={{ flex: 1, fontSize: 11, padding: '5px 8px' }}
          />
          <button
            className="btn-outlined"
            onClick={handleSearch}
            disabled={searching || !searchText.trim()}
            style={{ padding: '4px 10px', fontSize: 11 }}
          >
            {searching ? '…' : 'Suchen'}
          </button>
        </Field>

        <Field label="ODER LV95-KOORDS (E / N)"
                hint="East ~ 2'500'000–2'850'000, North ~ 1'070'000–1'300'000">
          <input
            placeholder="E"
            onChange={(e) => handleManualCoords(e.target.value, center?.n || '')}
            style={{ width: 110, fontSize: 11, fontFamily: 'DM Mono, monospace', padding: '5px 8px' }}
          />
          <span style={{ color: 'var(--text-muted)' }}>/</span>
          <input
            placeholder="N"
            onChange={(e) => handleManualCoords(center?.e || '', e.target.value)}
            style={{ width: 110, fontSize: 11, fontFamily: 'DM Mono, monospace', padding: '5px 8px' }}
          />
        </Field>

        {center && (
          <div style={{
            display: 'flex', alignItems: 'center', gap: 8,
            padding: '8px 10px',
            background: 'var(--accent-dim)',
            border: '1px solid var(--accent-border)',
            borderRadius: 'var(--r)',
            marginTop: 4,
          }}>
            <Icon name="location_on" size={14} style={{ color: 'var(--accent)' }} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 11, fontWeight: 500, overflow: 'hidden',
                            textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {center.label}
              </div>
              <div style={{ fontSize: 9, fontFamily: 'DM Mono, monospace',
                            color: 'var(--text-muted)' }}>
                E {Math.round(center.e)} · N {Math.round(center.n)}
              </div>
            </div>
          </div>
        )}

        <SectionLabel>Bereich</SectionLabel>

        <Field label="RADIUS"
                hint="Halbe Kantenlänge der quadratischen Bounding-Box um den Standort">
          <Radio
            value={radius}
            options={[
              { value: 50,  label: '50 m'  },
              { value: 100, label: '100 m' },
              { value: 200, label: '200 m' },
              { value: 500, label: '500 m' },
              { value: 1000, label: '1 km' },
            ]}
            onChange={setRadius}
          />
        </Field>

        <SectionLabel>Was holen</SectionLabel>

        <Field label="DATEN">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={getBuild} onChange={(e) => setGetBuild(e.target.checked)} />
            <Icon name="location_city" size={13} /> Bestand-Gebäude (swissBUILDINGS3D, DWG)
          </label>
        </Field>
        {getBuild && (
          <Field label="VERSION"
                  hint="2.0 = stabil, kein Solid/Separated-Split (alle Kategorien auf eigenen DXF-Layern innerhalb einer DWG). 3.0 = neuer, Beta — kann manchmal Probleme mit Variant-Erkennung haben.">
            <Radio
              value={buildVersion}
              options={[
                { value: 'v2', label: '2.0 (stabil)' },
                { value: 'v3', label: '3.0 (beta)' },
              ]}
              onChange={setBuildVersion}
            />
          </Field>
        )}
        {getBuild && buildVersion === 'v3' && (
          <Field label="GEBÄUDE-VARIANTE"
                  hint="Solid: ein geschlossenes Solid pro Gebäude (klein, schnell). Separated: Dach/Fassade/Wand als separate Objekte (mehr Detail, ermoeglicht z.B. Dach auszublenden).">
            <Radio
              value={buildVariant}
              options={[
                { value: 'separated', label: 'Separated (Dach/Fassade getrennt)' },
                { value: 'solid',     label: 'Solid (ein Volumen pro Gebäude)' },
              ]}
              onChange={setBuildVariant}
            />
          </Field>
        )}
        <Field label="">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={getTerrain} onChange={(e) => setGetTerrain(e.target.checked)} />
            <Icon name="terrain" size={13} /> Terrain (swissALTI3D → Mesh)
          </label>
        </Field>
        {getTerrain && (
          <Field label="TERRAIN-AUFLÖSUNG">
            <Radio
              value={terrainRes}
              options={[
                { value: '0.5', label: '0.5 m (sehr fein)',
                  hint: 'Bei 200m bbox: 400×400 = 160k Quads — bei 500m bbox 1M Quads!' },
                { value: '2.0', label: '2 m (Standard)',
                  hint: 'Gute Balance — bei 200m bbox: 100×100 = 10k Quads' },
              ]}
              onChange={setTerrainRes}
            />
          </Field>
        )}
        <Field label="">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer',
                           opacity: getTerrain ? 1 : 0.4 }}>
            <input type="checkbox" checked={getOrtho} disabled={!getTerrain}
                    onChange={(e) => setGetOrtho(e.target.checked)} />
            <Icon name="image" size={13} /> Orthofoto auf Terrain mappen (SWISSIMAGE 10cm)
          </label>
        </Field>

        <Field label=""
                hint="2D-Höhenlinien aus dem swissALTI3D-DEM. Werden flach auf die OKFF-Ebene des aktiven Geschosses gelegt — direkt zeichnungstauglich. Unabhängig vom 3D-Mesh.">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={getContours}
                    onChange={(e) => setGetContours(e.target.checked)} />
            <Icon name="terrain" size={13} /> Höhenlinien (2D, auf aktivem Geschoss)
          </label>
        </Field>
        <Field label=""
                hint="3D-TIN-Mesh aus den Vertices der Höhenlinien — Delaunay-trianguliert. Stilisierter Topo-Look mit weniger Polygonen als das DEM-Mesh.">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={getContourTin}
                    onChange={(e) => setGetContourTin(e.target.checked)} />
            <Icon name="lan" size={13} /> TIN-Mesh aus Höhenlinien
          </label>
        </Field>
        <Field label=""
                hint="Schichtenmodell: jede geschlossene Höhenlinie wird zur planaren Fläche auf ihrer Z-Höhe — der architektonische Pappmodell-Look.">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={getContourSchicht}
                    onChange={(e) => setGetContourSchicht(e.target.checked)} />
            <Icon name="stacks" size={13} /> Schichtenmodell aus Höhenlinien
          </label>
        </Field>
        {(getContours || getContourTin || getContourSchicht) && (
          <Field label="HÖHEN-ABSTAND">
            <Radio value={contourInt}
              options={[
                { value: '1.0', label: '1 m (fein)' },
                { value: '2.0', label: '2 m (Standard)' },
                { value: '5.0', label: '5 m (grob)' },
              ]}
              onChange={setContourInt} />
          </Field>
        )}

        <SectionLabel>Positionierung</SectionLabel>

        <Field label="ORIGIN"
                hint="LV95-Koords sind im Bereich 2.6 Mio / 1.2 Mio — fürs Architekturmodell zu gross. Auf 0/0/0 verschiebt alles zum aktiven Standort.">
          <Radio
            value={shift ? 'origin' : 'lv95'}
            options={[
              { value: 'origin', label: 'Auf Welt-Origin verschieben' },
              { value: 'lv95',   label: 'Original LV95 lassen' },
            ]}
            onChange={(v) => setShift(v === 'origin')}
          />
        </Field>

        <Field label="">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={autoZoom} onChange={(e) => setAutoZoom(e.target.checked)} />
            Auto-Zoom auf importierte Objekte
          </label>
        </Field>

        <Field label="" hint="Vorhandene swisstopo-Objekte (mit Tag dossier_swisstopo_kind) werden vor dem neuen Import gelöscht. Verhindert doppelte Gebäude bei mehrfachem Import desselben Gebiets.">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={replaceExisting}
                    onChange={(e) => setReplaceExisting(e.target.checked)} />
            Bestehende swisstopo-Objekte vorher löschen
          </label>
        </Field>

        <Field label="" hint="Filter: nur Gebäude/Terrain innerhalb des Radius behalten. AUS = ganzer 1km² Tile bleibt drin (schneller Import, kann manuell gelöscht werden). AN = präziser aber langsam bei InstanceReferences.">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6,
                           fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={clipToBbox}
                    onChange={(e) => setClipToBbox(e.target.checked)} />
            Auf Radius zuschneiden (langsam, optional)
          </label>
        </Field>

        {(logs.length > 0 || running) && (
          <>
            <SectionLabel>Status</SectionLabel>
            <div ref={logRef} style={{
              fontSize: 10, fontFamily: 'DM Mono, monospace',
              background: 'var(--bg-input)',
              border: '1px solid var(--border)',
              borderRadius: 'var(--r)',
              padding: 8,
              maxHeight: 140,
              overflowY: 'auto',
              color: 'var(--text-secondary)',
              lineHeight: 1.5,
            }}>
              {logs.map((m, i) => <div key={i}>{m}</div>)}
              {running && <div style={{ color: 'var(--accent)' }}>Läuft…</div>}
            </div>
          </>
        )}
      </div>

      <div style={{
        display: 'flex', alignItems: 'center', gap: 6,
        padding: '10px 14px',
        borderTop: '1px solid var(--border)',
        background: 'var(--bg-section)',
      }}>
        <div style={{ flex: 1, fontSize: 10, color: 'var(--text-muted)' }}>
          {center ? `Tiles werden im Projekt-Ordner neben der .3dm gecacht (Fallback: ~/Library/Caches/Dossier/swisstopo/ wenn ungespeichert)` : 'Wähle zuerst einen Standort'}
        </div>
        <button className="btn-text" onClick={() => send('CANCEL', {})}
                 disabled={running}>
          {done ? 'Schliessen' : 'Abbrechen'}
        </button>
        <button className="btn-contained" onClick={handleImport}
                 disabled={!center || running}>
          <Icon name="download" size={13} />
          <span>{running ? 'Importiere…' : 'Importieren'}</span>
        </button>
      </div>
    </div>
  )
}
