// 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 { BarToggle, BarButton, BAR_H } from './components/BarControls'
import {
  onMessage, notifyReady,
  setKameraViewport, setKameraProjection, setKameraIso,
  kameraZoomExtents, saveKameraPreset, applyKameraPreset, deleteKameraPreset,
  setKameraNorthAngle,
} from './lib/rhinoBridge'

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 NumberField({ label, value, onCommit, suffix, step = 0.1 }) {
  const [draft, setDraft] = useState(value != null ? value.toFixed(3) : '')
  useEffect(() => {
    setDraft(value != null ? value.toFixed(3) : '')
  }, [value])
  const commit = () => {
    const n = parseFloat(draft)
    if (!isNaN(n)) onCommit(n)
    else setDraft(value != null ? value.toFixed(3) : '')
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
      <span style={labelXs}>{label}</span>
      <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
        <input
          type="number"
          step={step}
          value={draft}
          onChange={(ev) => setDraft(ev.target.value)}
          onBlur={commit}
          onKeyDown={(ev) => {
            if (ev.key === 'Enter') commit()
            if (ev.key === 'Escape') setDraft(value != null ? value.toFixed(3) : '')
          }}
          style={{ ...pillInput, flex: 1, fontFamily: 'var(--font-mono)' }}
        />
        {suffix && (
          <span style={{ fontSize: 9, color: 'var(--text-muted)', minWidth: 18 }}>
            {suffix}
          </span>
        )}
      </div>
    </div>
  )
}

function Vec3Field({ label, value, onCommit }) {
  const v = value || [0, 0, 0]
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span style={labelXs}>{label}</span>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }}>
        {['X', 'Y', 'Z'].map((axis, i) => (
          <NumberField
            key={axis}
            label={axis}
            value={v[i]}
            onCommit={(n) => {
              const next = [v[0], v[1], v[2]]
              next[i] = n
              onCommit(next)
            }}
          />
        ))}
      </div>
    </div>
  )
}

export default function KameraApp() {
  const [vp, setVp] = useState(null)
  const [presets, setPresets] = useState([])
  const [presetName, setPresetName] = useState('')
  const [northAngle, setNorthAngleState] = useState(0)

  useEffect(() => {
    onMessage('STATE', (s) => {
      setVp(s.viewport || null)
      setPresets(s.presets || [])
      if (typeof s.northAngle === 'number') setNorthAngleState(s.northAngle)
    })
    notifyReady()
  }, [])

  if (!vp) {
    return (
      <div style={{ padding: 14, color: 'var(--text-muted)', fontSize: 11 }}>
        Kein aktiver Viewport.
      </div>
    )
  }

  const isPar = !!vp.parallel
  const updateLoc = (loc)    => setKameraViewport({ loc })
  const updateTgt = (target) => setKameraViewport({ target })
  const updateLens = (lensMm) => setKameraViewport({ lensMm })
  const updateFW = (frustumW) => setKameraViewport({ frustumW })

  const saveCurrent = () => {
    const n = (presetName || '').trim()
    if (!n) return
    saveKameraPreset(n)
    setPresetName('')
  }

  return (
    <div style={{
      padding: 14,
      display: 'flex', flexDirection: 'column', gap: 16,
      fontFamily: 'var(--font)', color: 'var(--text-primary)',
      background: 'var(--bg-panel)', minHeight: '100vh',
      boxSizing: 'border-box',
    }}>
      {/* Header: Viewport-Name + Projektion-Toggle */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <span style={labelXs}>Viewport</span>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 13, fontWeight: 600 }}>{vp.name || 'Unnamed'}</span>
          <div style={{ flex: 1 }} />
          <BarToggle label="Perspektive"
            active={!isPar}
            onClick={() => setKameraProjection(false)} />
          <BarToggle label="Parallel"
            active={isPar}
            onClick={() => setKameraProjection(true)} />
        </div>
      </div>

      {/* Plan-Norden — Rotations-Winkel im Uhrzeigersinn von +Y */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <span style={labelXs}>Plan-Norden (Rotation von +Y, im Uhrzeigersinn)</span>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <input
            type="number" min={0} max={360} step={0.5}
            value={northAngle.toFixed(1)}
            onChange={(e) => {
              const a = parseFloat(e.target.value)
              if (!isNaN(a)) {
                setNorthAngleState(a)
                setKameraNorthAngle(a)
              }
            }}
            style={{ ...pillInput, flex: 1, fontFamily: 'DM Mono, monospace' }}
          />
          <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>°</span>
          <BarToggle label="Reset"
            onClick={() => { setNorthAngleState(0); setKameraNorthAngle(0) }}
            title="Norden zurueck auf +Y (0°)" />
        </div>
        <span style={{ fontSize: 10, color: 'var(--text-muted)', lineHeight: 1.4 }}>
          Norden = +Y bei 0°. Bei rotierten Projekten (z.B. swissBUILDINGS in
          LV95-Orientierung oder Sonnenberechnungen) hier den Plan-Norden in
          Grad eintragen. Wirkt auf TOP, ISO und N/O/S/W-Ansichten.
        </span>
      </div>

      {/* Iso-Quick-Picker */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <span style={labelXs}>Isometrie (Standard, true-iso 35°/45°)</span>
        <div style={{ display: 'flex', gap: 4 }}>
          {['NW', 'NE', 'SE', 'SW'].map(v => (
            <BarToggle key={v} label={v}
              onClick={() => setKameraIso(v)}
              title={`Isometrie aus ${v} (Kamera blickt Richtung Szene)`}
              minWidth={48} />
          ))}
        </div>
      </div>

      {/* Kamera-Position + Target */}
      <Vec3Field label="Kamera-Position (m)" value={vp.loc} onCommit={updateLoc} />
      <Vec3Field label="Blick-Ziel (m)" value={vp.target} onCommit={updateTgt} />

      {/* Distance read-only */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        padding: '6px 12px',
        background: 'var(--bg-section)',
        borderRadius: 999,
        border: '1px solid var(--border-light)',
      }}>
        <span style={labelXs}>Distanz</span>
        <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)',
                        color: 'var(--text-secondary)' }}>
          {vp.distance != null ? vp.distance.toFixed(2) + ' m' : '—'}
        </span>
      </div>

      {/* Linse / Frustum je nach Projektion */}
      {isPar ? (
        <NumberField
          label="Frustum-Breite (m)"
          value={vp.frustumW}
          onCommit={updateFW}
          suffix="m"
          step={0.5}
        />
      ) : (
        <NumberField
          label="Brennweite (mm, 35mm-Aequivalent)"
          value={vp.lensMm}
          onCommit={updateLens}
          suffix="mm"
          step={1}
        />
      )}

      <BarToggle icon="zoom_out_map" label="Zoom Extents"
        onClick={() => kameraZoomExtents()} />

      {/* Presets */}
      <div style={{
        display: 'flex', flexDirection: 'column', gap: 6,
        padding: 10, borderRadius: 'var(--r-lg)',
        background: 'var(--bg-section)',
        border: '1px solid var(--border-light)',
      }}>
        <span style={labelXs}>Presets</span>
        <div style={{ display: 'flex', gap: 4 }}>
          <input
            type="text"
            placeholder="Name…"
            value={presetName}
            onChange={(ev) => setPresetName(ev.target.value)}
            onKeyDown={(ev) => { if (ev.key === 'Enter') saveCurrent() }}
            style={{ ...pillInput, flex: 1 }}
          />
          <BarToggle label="Speichern"
            active={!!presetName.trim()}
            disabled={!presetName.trim()}
            onClick={saveCurrent} />
        </div>
        {presets.length === 0 ? (
          <span style={{ fontSize: 10, color: 'var(--text-muted)', fontStyle: 'italic' }}>
            Keine Presets gespeichert.
          </span>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
            {presets.map(p => (
              <div
                key={p.id}
                style={{
                  display: 'flex', alignItems: 'center', gap: 6,
                  padding: '2px 6px 2px 4px',
                  borderRadius: 999,
                  background: 'var(--bg-item)',
                  border: '1px solid var(--border-light)',
                  fontSize: 11,
                }}
              >
                <BarButton icon="play_arrow"
                  onClick={() => applyKameraPreset(p.id)}
                  title="Anwenden" />
                <span style={{ flex: 1, minWidth: 0,
                                overflow: 'hidden', textOverflow: 'ellipsis',
                                whiteSpace: 'nowrap' }}>{p.name}</span>
                <span style={{ fontSize: 9, color: 'var(--text-muted)',
                                fontFamily: 'var(--font-mono)' }}>
                  {p.parallel ? 'Par' : 'Persp'}
                </span>
                <BarButton icon="close"
                  onClick={() => deleteKameraPreset(p.id)}
                  title="Loeschen" />
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  )
}
