import { useConfirm } from '../confirm.jsx';
import { useState, useMemo, useEffect, useRef } from 'react';
import { api, S } from '../lib.js';

const MODEL_EXTENSIONS = ['.stl','.3mf','.f3d','.step','.stp','.obj','.iges','.igs','.fcstd','.amf','.scad'];

const DEFAULTS = {
  materialpreis_pro_rolle: 10,    // €/Rolle (1 kg = 1000 g → 0.01 €/g)
  stromverbrauch_kw: 0.15,
  strompreis_pro_kwh: 0.38,      druckerpreis: 550,
  gesamtdruckstunden: 5000,      verschleiss_pro_stunde: 0.25,
};
const LS_CUSTOM = 'dd_kalk3d_custom_defaults';
const getEffectiveDefaults = () => {
  try { const s = localStorage.getItem(LS_CUSTOM); if (s) return { ...DEFAULTS, ...JSON.parse(s) }; } catch {}
  return { ...DEFAULTS };
};
const getFarbFaktor = n => Math.round((1.0 + Math.max(0, n - 1) * 0.1) * 100) / 100;
const STUFEN = [
  { key:'f', emoji:'💖', label:'Freundschaft', mult:1.0, c:'#ff6b9d' },
  { key:'n', emoji:'🤝', label:'Normal',       mult:1.5, c:'#4ecdc4' },
  { key:'a', emoji:'💼', label:'Auftrag',      mult:2.5, c:'#ffe66d' },
];

// ── Bild komprimieren (client-seitig, max 800px, JPEG 0.75) ──────────────────
function compressImage(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = e => {
      const img = new Image();
      img.onload = () => {
        const MAX = 800;
        let w = img.width, h = img.height;
        if (w > MAX || h > MAX) {
          if (w > h) { h = Math.round(h * MAX / w); w = MAX; }
          else       { w = Math.round(w * MAX / h); h = MAX; }
        }
        const canvas = document.createElement('canvas');
        canvas.width = w; canvas.height = h;
        canvas.getContext('2d').drawImage(img, 0, 0, w, h);
        resolve(canvas.toDataURL('image/jpeg', 0.75));
      };
      img.onerror = reject;
      img.src = e.target.result;
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

// ── Stepper ───────────────────────────────────────────────────────────────────
function Stepper({ label, value, onChange, step, unit, min = 0, hint }) {
  const [raw, setRaw] = useState(String(value));

  // Sync wenn value sich von außen ändert (z.B. beim Bearbeiten eines Archiv-Eintrags)
  useEffect(() => { setRaw(String(value)); }, [value]);

  const dec = () => { const v = Math.max(min, Math.round((value - step) * 10000) / 10000); onChange(v); setRaw(String(v)); };
  const inc = () => { const v = Math.round((value + step) * 10000) / 10000; onChange(v); setRaw(String(v)); };

  return (
    <div>
      <div style={{ color:'rgba(255,255,255,0.4)', fontSize:10, fontFamily:'monospace', marginBottom:5, letterSpacing:1 }}>
        {label.toUpperCase()}{unit ? ` (${unit})` : ''}
      </div>
      <div style={{ display:'flex', alignItems:'center', background:'rgba(255,255,255,0.05)', borderRadius:8, border:'1px solid rgba(255,255,255,0.1)', overflow:'hidden' }}>
        <button onClick={dec} style={{ padding:'10px 12px', background:'transparent', border:'none', color:'rgba(255,255,255,0.6)', fontSize:20, cursor:'pointer', flexShrink:0, lineHeight:1 }}>−</button>
        <input
          type="number" value={raw} step={step}
          onChange={e => {
            setRaw(e.target.value);
            const parsed = parseFloat(e.target.value);
            if (!isNaN(parsed)) onChange(Math.max(min, parsed));
          }}
          onBlur={() => {
            const parsed = parseFloat(raw);
            const safe = isNaN(parsed) ? min : Math.max(min, parsed);
            onChange(safe); setRaw(String(safe));
          }}
          style={{ flex:1, background:'transparent', border:'none', color:'#fff', fontSize:15, fontFamily:"'Space Mono',monospace", textAlign:'center', outline:'none', minWidth:0, padding:'10px 4px' }}
        />
        <button onClick={inc} style={{ padding:'10px 12px', background:'transparent', border:'none', color:'rgba(255,255,255,0.6)', fontSize:20, cursor:'pointer', flexShrink:0, lineHeight:1 }}>+</button>
      </div>
      {hint && <div style={{ color:'rgba(255,255,255,0.5)', fontSize:10, fontFamily:'monospace', marginTop:3 }}>{hint}</div>}
    </div>
  );
}

function SmallInput({ label, value, onChange, step = 0.01 }) {
  const [raw, setRaw] = useState(String(value));
  useEffect(() => { setRaw(String(value)); }, [value]);
  return (
    <div>
      <div style={{ color:'rgba(255,255,255,0.6)', fontSize:9, fontFamily:'monospace', marginBottom:3 }}>{label}</div>
      <input
        type="number" value={raw} step={step}
        onChange={e => {
          setRaw(e.target.value);
          const parsed = parseFloat(e.target.value);
          if (!isNaN(parsed)) onChange(parsed);
        }}
        onBlur={() => {
          const parsed = parseFloat(raw);
          if (!isNaN(parsed)) { onChange(parsed); setRaw(String(parsed)); }
          else setRaw(String(value));
        }}
        style={{ ...S.inp, padding:'7px 8px', fontSize:13 }}
      />
    </div>
  );
}

// ── Bild-Modal ────────────────────────────────────────────────────────────────
function ImageModal({ src, onClose }) {
  return (
    <div style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.9)', zIndex:9000,
      display:'flex', alignItems:'center', justifyContent:'center', padding:20 }}
      onClick={onClose}>
      <img src={src} alt="Vorschau"
        style={{ maxWidth:'100%', maxHeight:'90vh', borderRadius:10, objectFit:'contain' }} />
    </div>
  );
}

// ── Kostenrechner ─────────────────────────────────────────────────────────────
export default function Kalkulator3D({ toast, editData, onEditDone, mobile, setActive }) {
  const [gramm,   setGramm]   = useState(editData?.gramm   ?? 50);
  const [stunden, setStunden] = useState(editData?.stunden ?? 3);
  const [farben,  setFarben]  = useState(editData?.farben  ?? 1);
  const [vars,    setVars]    = useState(editData ? {
    materialpreis_pro_rolle:  editData.materialpreis_pro_gramm != null ? Math.round(editData.materialpreis_pro_gramm * 1000 * 100) / 100 : DEFAULTS.materialpreis_pro_rolle,
    stromverbrauch_kw:        editData.stromverbrauch_kw,
    strompreis_pro_kwh:       editData.strompreis_pro_kwh,
    druckerpreis:             editData.druckerpreis,
    gesamtdruckstunden:       editData.gesamtdruckstunden,
    verschleiss_pro_stunde:   editData.verschleiss_pro_stunde,
  } : { ...getEffectiveDefaults() });
  const [showAdv,   setShowAdv]   = useState(false);
  const [name,      setName]      = useState(editData?.name      ?? '');
  const [bemerkung, setBemerkung] = useState(editData?.bemerkung ?? '');
  const [image,     setImage]     = useState(editData?.image     ?? null);
  const [saving,    setSaving]    = useState(false);
  const [modelFiles,    setModelFiles]    = useState([]); // neue Dateien zum Hochladen
  const [existingFiles, setExistingFiles] = useState([]); // bereits gespeicherte Dateien
  const [modelFolderId, setModelFolderId] = useState(null);
  const fileRef      = useRef(null);
  const modelFileRef = useRef(null);
  const sv = (k, v) => setVars(p => ({ ...p, [k]: v }));

  // Im Bearbeitungsmodus: existierende Dateien laden (ohne Ordner zu erstellen)
  useEffect(() => {
    if (!editData?.id || !editData?.name) return;
    (async () => {
      try {
        const base = await api(`/tools/dateien/find-folder?name=3D-Modelle`);
        if (!base) return; // Basisordner existiert noch nicht → keine Dateien
        const sub = await api(`/tools/dateien/find-folder?name=${encodeURIComponent(editData.name.trim())}&parent_id=${base.id}`);
        if (!sub) return; // Unterordner existiert nicht → keine Dateien
        setModelFolderId(sub.id);
        const data = await api(`/tools/dateien?folder_id=${sub.id}`);
        setExistingFiles(data.own || []);
      } catch {}
    })();
  }, [editData?.id]);

  const calc = useMemo(() => {
    const f   = getFarbFaktor(farben);
    const matProGramm = vars.materialpreis_pro_rolle / 1000;
    const mat = gramm   * matProGramm                    * f;
    const str = stunden * vars.stromverbrauch_kw         * vars.strompreis_pro_kwh;
    const ver = stunden * vars.verschleiss_pro_stunde;
    return { mat, str, ver, grund: mat + str + ver };
  }, [gramm, stunden, farben, vars]);

  const handleImagePick = async e => {
    const file = e.target.files?.[0];
    if (!file) return;
    if (!file.type.startsWith('image/')) { toast('Nur Bilddateien erlaubt (JPG, PNG, …)', 'error'); e.target.value = ''; return; }
    if (file.size > 20 * 1024 * 1024) { toast(`Bild zu groß (${(file.size/1024/1024).toFixed(1)} MB) – max. 20 MB`, 'error'); e.target.value = ''; return; }
    try {
      const compressed = await compressImage(file);
      setImage(compressed);
    } catch { toast('Bild konnte nicht verarbeitet werden – ist die Datei beschädigt?', 'error'); }
    e.target.value = '';
  };

  const save = async () => {
    if (!name.trim()) { toast('Bitte einen Namen eingeben', 'error'); return; }
    setSaving(true);
    try {
      const payload = { name, gramm, stunden, farben,
        materialpreis_pro_gramm: vars.materialpreis_pro_rolle / 1000,
        stromverbrauch_kw:       vars.stromverbrauch_kw,
        strompreis_pro_kwh:      vars.strompreis_pro_kwh,
        druckerpreis:            vars.druckerpreis,
        gesamtdruckstunden:      vars.gesamtdruckstunden,
        verschleiss_pro_stunde:  vars.verschleiss_pro_stunde,
        preis_freundschaft: calc.grund * 1.0,
        preis_normal:       calc.grund * 1.5,
        preis_auftrag:      calc.grund * 2.5,
        image, bemerkung };

      if (editData?.id) {
        await api(`/tools/kalkulator3d/${editData.id}`, { method:'PUT', body:payload });
        // Neue Dateien hochladen falls vorhanden
        if (modelFiles.length > 0) {
          let folderId = modelFolderId;
          if (!folderId) {
            // Ordner erst jetzt anlegen wenn wirklich Dateien da sind
            const base = await api('/tools/dateien/ensure-folder', { body: { name: '3D-Modelle' } });
            const sub  = await api('/tools/dateien/ensure-folder', { body: { name: editData.name.trim(), parent_id: base.id } });
            folderId = sub.id;
            setModelFolderId(folderId);
          }
          const form = new FormData();
          form.append('folder_id', folderId);
          for (const f of modelFiles) form.append('files', f);
          await fetch('/api/tools/dateien/upload-3d', {
            method:'POST',
            headers:{ Authorization:`Bearer ${localStorage.getItem('sk_token')}` },
            body: form,
          });
          setModelFiles([]);
          const data = await api(`/tools/dateien?folder_id=${folderId}`);
          setExistingFiles(data.own || []);
        }
        toast('Aktualisiert ✓'); onEditDone?.();
      } else {
        await api('/tools/kalkulator3d', { body:payload });
        // 3D-Dateien hochladen wenn vorhanden
        if (modelFiles.length > 0) {
          try {
            // 1. "3D-Modelle" Basisordner sicherstellen
            const base = await api('/tools/dateien/ensure-folder', { body: { name: '3D-Modelle' } });
            // 2. Unterordner mit Modellnamen anlegen
            const sub  = await api('/tools/dateien/ensure-folder', { body: { name: name.trim(), parent_id: base.id } });
            // 3. Dateien hochladen
            const form = new FormData();
            form.append('folder_id', sub.id);
            for (const f of modelFiles) form.append('files', f);
            await fetch('/api/tools/dateien/upload-3d', {
              method: 'POST',
              headers: { Authorization: `Bearer ${localStorage.getItem('sk_token')}` },
              body: form,
            });
            toast(`Gespeichert ✓ · ${modelFiles.length} Datei(en) in 3D-Modelle/${name.trim()} abgelegt`);
          } catch {
            toast('Gespeichert ✓ (Datei-Upload fehlgeschlagen)', 'error');
          }
        } else {
          toast('Gespeichert ✓');
        }
        setName(''); setBemerkung(''); setImage(null); setModelFiles([]);
        setActive?.('kalkulator3d-saved');
      }
    } catch(e) { toast(e.message, 'error'); } finally { setSaving(false); }
  };

  const pad = mobile ? '14px 14px 90px' : '36px 44px';

  return (
    <div style={{ padding:pad, maxWidth:860 }}>
      <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:20 }}>
        <div>
          {editData && <div style={{ color:'#ffe66d', fontSize:10, fontFamily:'monospace', marginBottom:4 }}>✎ {editData.name}</div>}
          <h1 style={{ color:'#fff', fontFamily:"'Space Mono',monospace", fontSize:mobile?18:22, margin:0 }}>Kostenrechner</h1>
        </div>
        <div style={{ display:'flex', gap:8 }}>
          {editData && <button onClick={onEditDone} style={S.btn('#ff6b9d', true)}>✕ Abbrechen</button>}
          {!editData && <button onClick={() => window.location.reload()} title="Neu laden"
            style={{ background:'transparent', border:'1px solid rgba(255,255,255,0.1)', borderRadius:8,
              color:'rgba(255,255,255,0.4)', cursor:'pointer', padding:'6px 10px', fontSize:14, fontFamily:'monospace' }}>↺</button>}
        </div>
      </div>

      {/* Eingaben */}
      <div style={{ ...S.card, marginBottom:10 }}>
        <div style={{ display:'flex', flexDirection:'column', gap:10, marginBottom:10 }}>
          <Stepper label="Gewicht"    value={gramm}   onChange={setGramm}   step={1}   unit="g" min={0} />
          <Stepper label="Druckdauer" value={stunden} onChange={setStunden} step={0.5} unit="h" min={0} />
          <Stepper label="Anzahl Farben" value={farben}
            onChange={v => setFarben(Math.max(1, Math.round(v)))} step={1} min={1}
            hint={`Farbfaktor: ×${getFarbFaktor(farben).toFixed(2)}`} />
        </div>

        <button onClick={() => setShowAdv(v => !v)} style={{
          width:'100%', marginTop:4, background:'rgba(255,255,255,0.02)',
          border:'1px solid rgba(255,255,255,0.06)', borderRadius:7,
          padding:'9px 12px', color:'rgba(255,255,255,0.6)', cursor:'pointer',
          fontFamily:'monospace', fontSize:11, textAlign:'left',
          display:'flex', alignItems:'center', gap:7,
        }}>
          <span style={{ display:'inline-block', transform:showAdv?'rotate(90deg)':'rotate(0)', transition:'transform 0.18s' }}>▶</span>
          Erweiterte Einstellungen
          <span style={{ marginLeft:'auto', fontSize:9, background:'rgba(78,205,196,0.1)', borderRadius:3, padding:'2px 6px', color:'#4ecdc4' }}>
            {Object.entries(vars).some(([k,v]) => v !== getEffectiveDefaults()[k]) ? 'GEÄNDERT' : 'STANDARD'}
          </span>
        </button>
        {showAdv && (
          <div style={{ marginTop:10, background:'rgba(0,0,0,0.2)', border:'1px solid rgba(255,255,255,0.05)', borderRadius:9, padding:12 }}>
            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:10 }}>
              <SmallInput label="Material €/Rolle" value={vars.materialpreis_pro_rolle} onChange={v=>sv('materialpreis_pro_rolle',v)} step={0.5}/>
              <SmallInput label="Strom kW"       value={vars.stromverbrauch_kw}        onChange={v=>sv('stromverbrauch_kw',v)}        step={0.01}/>
              <SmallInput label="Strom €/kWh"    value={vars.strompreis_pro_kwh}       onChange={v=>sv('strompreis_pro_kwh',v)}       step={0.01}/>
              <SmallInput label="Drucker €"      value={vars.druckerpreis}             onChange={v=>sv('druckerpreis',v)}             step={10}/>
              <SmallInput label="Lebensdauer h"  value={vars.gesamtdruckstunden}       onChange={v=>sv('gesamtdruckstunden',v)}       step={100}/>
              <SmallInput label="Verschleiß €/h" value={vars.verschleiss_pro_stunde}   onChange={v=>sv('verschleiss_pro_stunde',v)}   step={0.01}/>
            </div>
            <div style={{ display:'flex', gap:8, marginTop:10 }}>
              <button onClick={() => {
                localStorage.setItem(LS_CUSTOM, JSON.stringify(vars));
                toast('Als persönlicher Standard gespeichert ✓');
              }} style={{ ...S.btn('#4ecdc4', true), flex:1, textAlign:'center' }}>
                ★ Als Standard speichern
              </button>
              <button onClick={() => {
                localStorage.removeItem(LS_CUSTOM);
                setVars({ ...DEFAULTS });
                toast('Auf Werkseinstellungen zurückgesetzt');
              }} style={{ ...S.btn('#ff6b9d', true) }} title="Werkseinstellungen wiederherstellen">
                ↺
              </button>
            </div>
          </div>
        )}
      </div>

      {/* Ergebnis */}
      <div style={{ ...S.card, marginBottom:10 }}>
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:0 }}>
          {[['Material',calc.mat,'#a78bfa'],['Strom',calc.str,'#60a5fa'],['Verschleiß',calc.ver,'#f59e0b'],['Grundkosten',calc.grund,'#4ecdc4']].map(([l,v,c],i) => (
            <div key={l} style={{
              padding:'10px 14px',
              borderBottom: i < 2 ? '1px solid rgba(255,255,255,0.05)' : 'none',
              borderRight:  i % 2 === 0 ? '1px solid rgba(255,255,255,0.05)' : 'none',
            }}>
              <div style={{ color:'rgba(255,255,255,0.6)', fontSize:9, fontFamily:'monospace', marginBottom:2 }}>{l.toUpperCase()}</div>
              <div style={{ color:c, fontSize:i===3?18:14, fontFamily:"'Space Mono',monospace", fontWeight:i===3?700:400 }}>
                {v.toFixed(2)} €
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Preise */}
      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:8, marginBottom:12 }}>
        {STUFEN.map((s, i) => (
          <div key={s.key} style={{
            background:`${s.c}10`, border:`1px solid ${s.c}30`, borderRadius:10,
            padding:'12px 10px', textAlign:'center', transform:i===1?'scale(1.04)':'scale(1)',
          }}>
            <div style={{ fontSize:20, marginBottom:3 }}>{s.emoji}</div>
            <div style={{ color:'rgba(255,255,255,0.6)', fontSize:9, fontFamily:'monospace', marginBottom:4 }}>{s.label}</div>
            <div style={{ color:s.c, fontSize:mobile?16:20, fontFamily:"'Space Mono',monospace", fontWeight:700 }}>
              {(calc.grund * s.mult).toFixed(2)}€
            </div>
            <div style={{ color:'rgba(255,255,255,0.5)', fontSize:8, fontFamily:'monospace', marginTop:2 }}>×{s.mult}</div>
          </div>
        ))}
      </div>

      {/* Speichern */}
      <div style={S.card}>
        <div style={{ ...S.head, marginBottom:10 }}>BERECHNUNG SPEICHERN</div>

        {/* Name */}
        <div style={{ marginBottom:10 }}>
          <label style={{ ...S.head, display:'block', marginBottom:4 }}>NAME</label>
          <input value={name} onChange={e => setName(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && save()}
            placeholder='z.B. "Halterung Müller"'
            style={{ ...S.inp, fontSize:15 }} />
        </div>

        {/* Bemerkung */}
        <div style={{ marginBottom:10 }}>
          <label style={{ ...S.head, display:'block', marginBottom:4 }}>BEMERKUNG</label>
          <textarea value={bemerkung} onChange={e => setBemerkung(e.target.value)}
            placeholder="Material, Infill, Notizen…"
            rows={3}
            style={{ ...S.inp, resize:'vertical', lineHeight:1.6, fontSize:14, padding:'9px 12px' }} />
        </div>

        {/* Bild */}
        <div style={{ marginBottom:14 }}>
          <label style={{ ...S.head, display:'block', marginBottom:6 }}>BILD (optional)</label>
          <input ref={fileRef} type="file" accept="image/*" onChange={handleImagePick}
            style={{ display:'none' }} />
          {image ? (
            <div style={{ position:'relative', display:'inline-block' }}>
              <img src={image} alt="Vorschau"
                style={{ width:'100%', maxWidth:240, height:140, objectFit:'cover', borderRadius:8,
                  border:'1px solid rgba(255,255,255,0.1)', display:'block' }} />
              <button onClick={() => setImage(null)} style={{
                position:'absolute', top:6, right:6,
                width:24, height:24, borderRadius:'50%',
                background:'rgba(0,0,0,0.7)', border:'none',
                color:'#fff', fontSize:13, cursor:'pointer', lineHeight:1,
              }}>✕</button>
            </div>
          ) : (
            <button onClick={() => fileRef.current?.click()} style={{
              width:'100%', padding:'20px', background:'rgba(255,255,255,0.03)',
              border:'1px dashed rgba(255,255,255,0.15)', borderRadius:8,
              color:'rgba(255,255,255,0.6)', cursor:'pointer', fontFamily:'monospace', fontSize:12,
            }}>📷 Bild hinzufügen</button>
          )}
        </div>

        {/* 3D-Modelldateien – beim Neuanlegen */}
        {!editData?.id && (
          <div style={{ marginBottom:14 }}>
            <label style={{ ...S.head, display:'block', marginBottom:6 }}>
              3D-DATEIEN (optional) – werden in 3D-Modelle/{name.trim()||'…'} abgelegt
            </label>
            <input ref={modelFileRef} type="file" multiple
              accept={MODEL_EXTENSIONS.join(',')}
              onChange={e => setModelFiles(Array.from(e.target.files||[]))}
              style={{ display:'none' }} />
            {modelFiles.length > 0 ? (
              <div style={{ background:'rgba(255,255,255,0.03)', border:'1px solid rgba(255,255,255,0.1)',
                borderRadius:8, padding:10 }}>
                {modelFiles.map((f,i) => (
                  <div key={i} style={{ display:'flex', alignItems:'center', justifyContent:'space-between',
                    padding:'4px 0', borderBottom: i<modelFiles.length-1 ? '1px solid rgba(255,255,255,0.05)' : 'none' }}>
                    <span style={{ color:'rgba(255,255,255,0.7)', fontFamily:'monospace', fontSize:11,
                      overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', maxWidth:'80%' }}>
                      🖨 {f.name}
                    </span>
                    <span style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, flexShrink:0 }}>
                      {(f.size/1024/1024).toFixed(1)} MB
                    </span>
                  </div>
                ))}
                <div style={{ display:'flex', gap:6, marginTop:8 }}>
                  <button onClick={() => modelFileRef.current?.click()}
                    style={{ ...S.btn('#4ecdc4', true), flex:1, textAlign:'center', fontSize:11 }}>
                    + Weitere hinzufügen
                  </button>
                  <button onClick={() => setModelFiles([])}
                    style={{ ...S.btn('#ff6b9d', true), fontSize:11 }}>✕</button>
                </div>
              </div>
            ) : (
              <button onClick={() => modelFileRef.current?.click()} style={{
                width:'100%', padding:'16px', background:'rgba(255,255,255,0.03)',
                border:'1px dashed rgba(255,255,255,0.15)', borderRadius:8,
                color:'rgba(255,255,255,0.6)', cursor:'pointer', fontFamily:'monospace', fontSize:12,
              }}>🖨 3D-Dateien anhängen (STL, 3MF, F3D, STEP …)</button>
            )}
          </div>
        )}

        {/* 3D-Modelldateien – beim Bearbeiten */}
        {editData?.id && (
          <div style={{ marginBottom:14 }}>
            <label style={{ ...S.head, display:'block', marginBottom:6 }}>
              3D-DATEIEN – 3D-Modelle/{editData.name}
            </label>
            <input ref={modelFileRef} type="file" multiple
              accept={MODEL_EXTENSIONS.join(',')}
              onChange={e => setModelFiles(Array.from(e.target.files||[]))}
              style={{ display:'none' }} />

            {/* Existierende Dateien */}
            {existingFiles.length > 0 && (
              <div style={{ background:'rgba(255,255,255,0.03)', border:'1px solid rgba(255,255,255,0.08)',
                borderRadius:8, padding:10, marginBottom:8 }}>
                {existingFiles.map((f,i) => (
                  <div key={f.id} style={{ display:'flex', alignItems:'center', gap:8,
                    padding:'5px 0', borderBottom: i<existingFiles.length-1 ? '1px solid rgba(255,255,255,0.05)' : 'none' }}>
                    <span style={{ fontSize:16, flexShrink:0 }}>🖨</span>
                    <span style={{ color:'rgba(255,255,255,0.7)', fontFamily:'monospace', fontSize:11,
                      flex:1, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                      {f.originalname}
                    </span>
                    <span style={{ color:'rgba(255,255,255,0.25)', fontFamily:'monospace', fontSize:9, flexShrink:0 }}>
                      {(f.size/1024/1024).toFixed(1)} MB
                    </span>
                    <button onClick={async () => {
                      try {
                        await api(`/tools/dateien/${f.id}`, { method:'DELETE' });
                        const remaining = existingFiles.filter(x => x.id !== f.id);
                        setExistingFiles(remaining);
                        // Ordner löschen wenn er jetzt leer ist
                        if (remaining.length === 0 && modelFolderId) {
                          await api(`/tools/dateien/folders/${modelFolderId}`, { method:'DELETE' });
                          setModelFolderId(null);
                        }
                      } catch(e) { toast(e.message, 'error'); }
                    }} style={{ background:'transparent', border:'none', cursor:'pointer',
                      color:'rgba(255,107,157,0.5)', fontSize:14, padding:'0 2px', flexShrink:0, lineHeight:1 }}>✕</button>
                  </div>
                ))}
              </div>
            )}

            {/* Neue Dateien zum Hochladen */}
            {modelFiles.length > 0 && (
              <div style={{ background:'rgba(78,205,196,0.04)', border:'1px solid rgba(78,205,196,0.15)',
                borderRadius:8, padding:10, marginBottom:8 }}>
                <div style={{ ...S.head, marginBottom:6 }}>NEU HINZUFÜGEN</div>
                {modelFiles.map((f,i) => (
                  <div key={i} style={{ display:'flex', justifyContent:'space-between',
                    padding:'3px 0', borderBottom: i<modelFiles.length-1 ? '1px solid rgba(255,255,255,0.05)' : 'none' }}>
                    <span style={{ color:'rgba(255,255,255,0.6)', fontFamily:'monospace', fontSize:11,
                      overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', maxWidth:'80%' }}>
                      {f.name}
                    </span>
                    <span style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, flexShrink:0 }}>
                      {(f.size/1024/1024).toFixed(1)} MB
                    </span>
                  </div>
                ))}
              </div>
            )}

            <div style={{ display:'flex', gap:6 }}>
              <button onClick={() => modelFileRef.current?.click()}
                style={{ ...S.btn('#4ecdc4', true), flex:1, textAlign:'center', fontSize:11, padding:'9px 0' }}>
                + Dateien hinzufügen
              </button>
              {modelFiles.length > 0 && (
                <button onClick={() => setModelFiles([])}
                  style={{ ...S.btn('#ff6b9d', true), fontSize:11 }}>✕ Abbrechen</button>
              )}
            </div>
          </div>
        )}

        <button onClick={save} disabled={saving} style={{
          width:'100%', background:'linear-gradient(135deg,#4ecdc4,#45b7d1)', border:'none',
          borderRadius:8, padding:'12px 0', color:'#0d0d0f',
          fontFamily:"'Space Mono',monospace", fontWeight:700,
          fontSize:13, cursor:saving?'default':'pointer', opacity:saving?0.7:1,
        }}>{saving ? '…' : editData?.id ? '✓ Aktualisieren' : '↓ Speichern'}</button>
      </div>
    </div>
  );
}

// ── Archiv ──────────────────────────────────────────────────────────────
// ── Datei-Downloads für ein Archiv-Modell ────────────────────────────────────
function ModelFiles({ calcId, toast }) {
  const [files,  setFiles]  = useState(null); // null = noch nicht geladen
  const [open,   setOpen]   = useState(false);

  const load = async () => {
    if (files !== null) return;
    try { setFiles(await api(`/tools/kalkulator3d/${calcId}/files`)); }
    catch { setFiles([]); }
  };

  const download = async f => {
    try {
      const res = await fetch(`/api/tools/kalkulator3d/${calcId}/files/${f.id}/download`, {
        headers:{ Authorization:`Bearer ${localStorage.getItem('sk_token')}` }
      });
      if (!res.ok) { toast('Download fehlgeschlagen','error'); return; }
      const blob = await res.blob();
      const a = Object.assign(document.createElement('a'),{ href:URL.createObjectURL(blob), download:f.originalname });
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      setTimeout(()=>URL.revokeObjectURL(a.href),1000);
    } catch(e){ toast(e.message,'error'); }
  };

  const toggle = () => { if (!open) load(); setOpen(v=>!v); };

  return (
    <div>
      <button onClick={toggle} style={{ ...S.btn('#4ecdc4', true), width:'100%', textAlign:'left',
        display:'flex', alignItems:'center', gap:6, fontSize:11 }}>
        <span>🖨</span>
        <span style={{flex:1}}>3D-Dateien {files!==null&&files.length>0?`(${files.length})`:''}</span>
        <span style={{transform:open?'rotate(90deg)':'rotate(0)',transition:'transform 0.2s',fontSize:10}}>▶</span>
      </button>
      {open && (
        <div style={{ marginTop:6, background:'rgba(255,255,255,0.02)', border:'1px solid rgba(255,255,255,0.07)',
          borderRadius:8, overflow:'hidden' }}>
          {files === null ? (
            <div style={{ padding:'10px 14px', color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:11 }}>Lädt…</div>
          ) : files.length === 0 ? (
            <div style={{ padding:'10px 14px', color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:11 }}>Keine Dateien vorhanden</div>
          ) : files.map((f,i) => (
            <div key={f.id} style={{ display:'flex', alignItems:'center', gap:8, padding:'8px 12px',
              borderBottom: i<files.length-1 ? '1px solid rgba(255,255,255,0.05)' : 'none' }}>
              <span style={{ color:'rgba(255,255,255,0.6)', fontFamily:'monospace', fontSize:11,
                flex:1, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                {f.originalname}
              </span>
              <span style={{ color:'rgba(255,255,255,0.25)', fontFamily:'monospace', fontSize:9, flexShrink:0 }}>
                {(f.size/1024/1024).toFixed(1)} MB
              </span>
              <button onClick={()=>download(f)} style={{ ...S.btn('#4ecdc4'), padding:'4px 10px', fontSize:10, flexShrink:0 }}>
                ↓
              </button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ── Share Modal ───────────────────────────────────────────────────────────────
function CalcShareModal({ item, onClose, toast }) {
  const [username, setUsername] = useState('');
  const [shares,   setShares]   = useState([]);
  const load = () => api(`/tools/kalkulator3d/${item.id}/shares`).then(setShares).catch(()=>{});
  useEffect(()=>{ load(); },[]);
  const share = async () => {
    if (!username.trim()) return;
    try { await api(`/tools/kalkulator3d/${item.id}/share`,{body:{username:username.trim()}}); toast('Geteilt ✓'); setUsername(''); load(); }
    catch(e) { toast(e.message,'error'); }
  };
  const unshare = async uid => {
    try { await api(`/tools/kalkulator3d/${item.id}/share/${uid}`,{method:'DELETE'}); setShares(p=>p.filter(s=>s.id!==uid)); toast('Freigabe entfernt'); }
    catch(e) { toast(e.message,'error'); }
  };
  const isMobile = window.innerWidth<768;
  return (
    <div style={{position:'fixed',inset:0,background:'rgba(0,0,0,0.8)',zIndex:6000,
      display:'flex',alignItems:isMobile?'flex-end':'center',justifyContent:'center',padding:isMobile?0:24}}
      onClick={e=>e.target===e.currentTarget&&onClose()}>
      <div style={{background:'#1a1a1e',borderRadius:isMobile?'16px 16px 0 0':16,
        width:'100%',maxWidth:420,padding:'20px 20px 28px',border:'1px solid rgba(255,255,255,0.12)'}}>
        {isMobile&&<div style={{width:36,height:4,background:'rgba(255,255,255,0.15)',borderRadius:2,margin:'0 auto 14px'}}/>}
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:14}}>
          <div style={{color:'#fff',fontFamily:"'Space Mono',monospace",fontSize:13,fontWeight:700}}>
            🖨 {item.name}
          </div>
          <button onClick={onClose} style={{background:'transparent',border:'none',color:'rgba(255,255,255,0.4)',cursor:'pointer',fontSize:18,padding:'0 4px'}}>✕</button>
        </div>
        <p style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:10,marginBottom:12,lineHeight:1.6}}>
          Empfänger können das Modell nur ansehen, nicht bearbeiten oder löschen.
        </p>
        <div style={{display:'flex',gap:8,marginBottom:14}}>
          <input value={username} onChange={e=>setUsername(e.target.value)} onKeyDown={e=>e.key==='Enter'&&share()}
            placeholder="Benutzername" autoCapitalize="none" style={{...S.inp,flex:1,fontSize:15}}/>
          <button onClick={share} style={S.btn('#4ecdc4')}>Teilen</button>
        </div>
        {shares.length>0 ? (
          <div>
            <div style={{...S.head,marginBottom:6}}>GETEILT MIT</div>
            {shares.map(s=>(
              <div key={s.id} style={{display:'flex',justifyContent:'space-between',alignItems:'center',
                padding:'8px 0',borderBottom:'1px solid rgba(255,255,255,0.05)'}}>
                <div>
                  <div style={{color:'rgba(255,255,255,0.8)',fontFamily:'monospace',fontSize:13}}>{s.username}</div>
                  {s.shared_at && <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:10}}>seit {new Date(s.shared_at.replace(' ','T')).toLocaleDateString('de-DE')}</div>}
                </div>
                <button onClick={()=>unshare(s.id)} style={S.btn('#ff6b9d',true)}>✕</button>
              </div>
            ))}
          </div>
        ) : (
          <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:11}}>Noch mit niemandem geteilt.</div>
        )}
      </div>
    </div>
  );
}

export function SavedList({ toast, mobile }) {
  const { confirm, ConfirmDialog } = useConfirm();
  const [own,        setOwn]      = useState([]);
  const [shared,     setShared]   = useState([]);
  const [sharedByMe, setSharedByMe] = useState([]);
  const [loading,    setLoading]  = useState(true);
  const [tab,        setTab]      = useState('own');
  const [editData,   setEditData] = useState(null);
  const [search,     setSearch]   = useState('');
  const [lightbox,   setLightbox] = useState(null);
  const [shareItem,  setShareItem]= useState(null);

  const load = () => {
    setLoading(true);
    api('/tools/kalkulator3d')
      .then(d => { setOwn(d.own||[]); setShared(d.shared||[]); setSharedByMe(d.sharedByMe||[]); })
      .catch(e => toast(e.message,'error'))
      .finally(()=>setLoading(false));
  };
  useEffect(()=>{ load(); },[]);

  const del = async id => {
    try { await api(`/tools/kalkulator3d/${id}`,{method:'DELETE'}); setOwn(p=>p.filter(i=>i.id!==id)); toast('Gelöscht'); }
    catch(e) { toast(e.message,'error'); }
  };

  const items = tab==='own' ? own : tab==='shared' ? shared : sharedByMe;
  const filtered = search.trim()
    ? items.filter(i => i.name.toLowerCase().includes(search.toLowerCase()) || (i.bemerkung&&i.bemerkung.toLowerCase().includes(search.toLowerCase())))
    : items;

  if (editData) return (
    <Kalkulator3D toast={toast} mobile={mobile} editData={editData} onEditDone={() => { setEditData(null); load(); }} />
  );

  return (
    <div style={{ padding: mobile ? '14px 14px 90px' : '36px 44px', maxWidth:900 }}>
      {lightbox && <ImageModal src={lightbox} onClose={() => setLightbox(null)} />}
      {shareItem && <CalcShareModal item={shareItem} onClose={()=>{setShareItem(null);load();}} toast={toast}/>}
      <ConfirmDialog/>

      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:14 }}>
        <h1 style={{ color:'#fff', fontFamily:"'Space Mono',monospace", fontSize:mobile?18:22, margin:0 }}>Archiv</h1>
        <button onClick={load} title="Neu laden"
          style={{ background:'transparent', border:'1px solid rgba(255,255,255,0.1)', borderRadius:8,
            color:'rgba(255,255,255,0.4)', cursor:'pointer', padding:'6px 10px', fontSize:14, fontFamily:'monospace' }}>↺</button>
      </div>

      {/* Tabs */}
      <div style={{ display:'flex', gap:6, marginBottom:14, flexWrap:'wrap' }}>
        {[['own','Meine',own.length],['shared','Geteilt mit mir',shared.length],['sharedByMe','Geteilt von mir',sharedByMe.length]].map(([k,l,cnt])=>(
          <button key={k} onClick={()=>{setTab(k);setSearch('');}} style={{
            padding:'6px 14px', borderRadius:20, fontFamily:'monospace', fontSize:11, cursor:'pointer',
            background: tab===k ? '#4ecdc4' : 'rgba(255,255,255,0.05)',
            color:       tab===k ? '#0d0d0f' : 'rgba(255,255,255,0.55)',
            border:      tab===k ? 'none'    : '1px solid rgba(255,255,255,0.1)',
            fontWeight:  tab===k ? 700       : 400,
          }}>
            {l}{cnt>0&&<span style={{marginLeft:5,opacity:0.7}}>({cnt})</span>}
          </button>
        ))}
      </div>
      {/* Suche */}
      <div style={{ position:'relative', marginBottom:12 }}>
        <span style={{ position:'absolute', left:12, top:'50%', transform:'translateY(-50%)',
          color:'rgba(255,255,255,0.6)', fontSize:14, pointerEvents:'none' }}>⌕</span>
        <input value={search} onChange={e => setSearch(e.target.value)}
          placeholder="Name oder Bemerkung suchen…"
          style={{ ...S.inp, paddingLeft:34, fontSize:15 }} />
        {search && (
          <button onClick={() => setSearch('')} style={{
            position:'absolute', right:10, top:'50%', transform:'translateY(-50%)',
            background:'transparent', border:'none', color:'rgba(255,255,255,0.6)',
            cursor:'pointer', fontSize:16,
          }}>✕</button>
        )}
      </div>

      <p style={{ color:'rgba(255,255,255,0.55)', fontFamily:'monospace', fontSize:10, marginBottom:14 }}>
        {filtered.length} von {items.length} Einträgen{search ? ` für „${search}"` : ''}
      </p>

      {loading && <div style={{ color:'rgba(255,255,255,0.6)', fontFamily:'monospace' }}>Lädt…</div>}

      {!loading && items.length === 0 && (
        <div style={{ ...S.card, textAlign:'center', padding:40 }}>
          <div style={{ fontSize:28, marginBottom:10 }}>◉</div>
          <div style={{ color:'rgba(255,255,255,0.55)', fontFamily:'monospace', fontSize:12 }}>Noch keine Berechnungen.</div>
        </div>
      )}

      {!loading && search && filtered.length === 0 && (
        <div style={{ ...S.card, textAlign:'center', padding:24 }}>
          <div style={{ color:'rgba(255,255,255,0.55)', fontFamily:'monospace', fontSize:12 }}>Keine Treffer.</div>
        </div>
      )}

      {filtered.map(item => (
        <div key={item.id} style={{ ...S.card, marginBottom:10, padding:'14px' }}>
          <div style={{ display:'flex', gap:12 }}>

            {/* Bild Thumbnail */}
            {item.image && (
              <img src={item.image} alt={item.name}
                onClick={() => setLightbox(item.image)}
                style={{ width:72, height:72, objectFit:'cover', borderRadius:8, flexShrink:0,
                  border:'1px solid rgba(255,255,255,0.1)', cursor:'pointer' }} />
            )}

            <div style={{ flex:1, minWidth:0 }}>
              {/* Name + Datum */}
              <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:4 }}>
                <div style={{ display:'flex', alignItems:'center', gap:6 }}>
                  <div style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:700 }}>{item.name}</div>
                  {item.has_files && (
                    <span title="3D-Dateien vorhanden"
                      style={{ fontSize:11, background:'rgba(78,205,196,0.12)', border:'1px solid rgba(78,205,196,0.25)',
                        borderRadius:5, padding:'1px 5px', color:'#4ecdc4', fontFamily:'monospace', fontSize:9,
                        letterSpacing:0.5, flexShrink:0 }}>🖨 Dateien</span>
                  )}
                </div>
                <div style={{ color:'rgba(255,255,255,0.5)', fontFamily:'monospace', fontSize:10, flexShrink:0, marginLeft:8 }}>
                  {new Date(item.created_at).toLocaleDateString('de-DE')}
                </div>
              </div>

              {/* Infos */}
              <div style={{ color:'rgba(255,255,255,0.6)', fontFamily:'monospace', fontSize:10, marginBottom:6 }}>
                {item.gramm}g · {item.stunden}h · {item.farben} Farbe{item.farben > 1 ? 'n' : ''}
              </div>

              {/* Bemerkung */}
              {item.bemerkung && (
                <div style={{ color:'rgba(255,255,255,0.45)', fontFamily:'monospace', fontSize:11,
                  lineHeight:1.5, marginBottom:8, wordBreak:'break-word' }}>
                  {item.bemerkung}
                </div>
              )}

              {/* Preise */}
              <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:6, marginBottom:10 }}>
                {[['💖',item.preis_freundschaft,'#ff6b9d'],['🤝',item.preis_normal,'#4ecdc4'],['💼',item.preis_auftrag,'#ffe66d']].map(([e,v,c]) => (
                  <div key={e} style={{ background:`${c}10`, border:`1px solid ${c}25`, borderRadius:7, padding:'6px 4px', textAlign:'center' }}>
                    <div style={{ fontSize:12 }}>{e}</div>
                    <div style={{ color:c, fontFamily:"'Space Mono',monospace", fontSize:12, fontWeight:700 }}>{v.toFixed(2)}€</div>
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* Aktionen */}
          <div style={{ display:'flex', gap:6, marginTop:10, flexDirection:'column' }}>
            {/* Datei-Downloads */}
            {item.has_files && (
              <ModelFiles calcId={item.id} toast={toast}/>
            )}
            <div style={{ display:'flex', gap:6 }}>
              {!item.is_shared && tab !== 'sharedByMe' ? (
                <>
                  <button onClick={() => setEditData(item)} style={{ ...S.btn('#4ecdc4', true), flex:1, textAlign:'center' }}>✎ Bearbeiten</button>
                  <button onClick={() => setShareItem(item)} style={{ ...S.btn('#ffe66d', true), padding:'0 12px' }} title="Teilen">🤝</button>
                  <button onClick={() => del(item.id)} style={{ ...S.btn('#ff6b9d', true), padding:'0 12px' }} title="Löschen">✕</button>
                </>
              ) : tab === 'sharedByMe' ? (
                <div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:10, padding:'4px 0' }}>
                  → {item.shared_with_name}
                </div>
              ) : (
                <div style={{ color:'rgba(255,255,255,0.25)', fontFamily:'monospace', fontSize:10, padding:'6px 0' }}>
                  von {item.owner_name} · nur Ansicht
                </div>
              )}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}
