import React, { useState, useEffect, useCallback } from 'react';

interface Item { id: string; filename: string; output_px: string; has_alpha: boolean;
  folder_id: string | null; by_name: string; tasks: string[]; delivery_status: string; nas_status: string;
  model_used: string; variant_of: string | null; mode: string; thumb_path: string | null; prompt_used: string | null;
  color_tag: string | null; created_at: string; }

const TAGS = [
  { id: 'red', label: 'Rot', color: '#E5484D' },
  { id: 'orange', label: 'Orange', color: '#E8830C' },
  { id: 'green', label: 'Grün', color: '#46A758' },
  { id: 'final', label: 'Final', color: '#3A3733' },
];
const tagColor = (t: string | null) => TAGS.find((x) => x.id === t)?.color || null;

export default function LibraryApp() {
  const [items, setItems] = useState<Item[]>([]);
  const [folders, setFolders] = useState<any[]>([]);
  const [models, setModels] = useState<any[]>([]);
  const [folderFilter, setFolderFilter] = useState<string | null>(null);
  const [pick, setPick] = useState<Set<string>>(new Set());
  const [variantSel, setVariantSel] = useState<Record<string, string>>({});
  const [compare, setCompare] = useState<Item | null>(null);
  const [promptOf, setPromptOf] = useState<Item | null>(null);
  const [saveView, setSaveView] = useState<Item | null>(null);
  const [tagMenu, setTagMenu] = useState<string | null>(null);
  const [tagFilter, setTagFilter] = useState<string | null>(null);
  const [toast, setToast] = useState<string | null>(null);
  const notify = (t: string) => { setToast(t); setTimeout(() => setToast(null), 2400); };

  // Modellname: Admin-Label, sonst lesbarer Rest der Modell-ID.
  const modelName = (id: string | null) => {
    if (!id) return null;
    const m = models.find((x) => x.model_id === id);
    if (m) return m.label;
    return id.split('/').pop()!.replace(/-/g, ' ');
  };

  const load = useCallback(async () => {
    const [i, f, m] = await Promise.all([
      fetch('/api/items').then((r) => r.json()).catch(() => ({ items: [] })),
      fetch('/api/folders').then((r) => r.json()).catch(() => ({ folders: [] })),
      fetch('/api/models').then((r) => r.json()).catch(() => ({ models: [] })),
    ]);
    setItems(i.items || []); setFolders(f.folders || []); setModels(m.models || []);
  }, []);
  useEffect(() => { load(); }, [load]);

  const rename = async (id: string, filename: string) =>
    fetch(`/api/items/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filename }) });
  const setTag = async (id: string, color_tag: string | null) => {
    setItems((x) => x.map((y) => y.id === id ? { ...y, color_tag } : y));
    setTagMenu(null);
    await fetch(`/api/items/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ color_tag }) });
  };
  const setFolder = async (id: string, folder_id: string | null) => {
    await fetch(`/api/items/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ folder_id }) });
    load();
  };
  const del = async (id: string) => { await fetch(`/api/items/${id}`, { method: 'DELETE' }); setItems((x) => x.filter((y) => y.id !== id)); };
  const delSelected = async () => { for (const id of pick) await fetch(`/api/items/${id}`, { method: 'DELETE' }); setPick(new Set()); load(); notify('Gelöscht.'); };
  const deliverSelected = async () => {
    notify('Sende an Picdrop …');
    const r = await fetch('/api/deliver', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemIds: [...pick] }) }).then((x) => x.json());
    setPick(new Set()); load(); notify(`${r.delivered}/${r.total} nach Picdrop ausgeliefert.`);
  };
  const toggle = (id: string) => setPick((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const moveSelected = async (folder_id: string | null) => {
    for (const id of pick) await fetch(`/api/items/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ folder_id }) });
    setPick(new Set()); load(); notify(folder_id ? 'In Ordner verschoben.' : 'Aus Ordner entfernt.');
  };
  const zipSelected = async () => {
    notify('Packe ZIP …');
    const res = await fetch('/api/items/zip', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemIds: [...pick] }) });
    if (!res.ok) { notify('ZIP fehlgeschlagen.'); return; }
    const blob = await res.blob();
    const a = document.createElement('a'); a.href = URL.createObjectURL(blob);
    a.download = `klarbild_${new Date().toISOString().slice(0, 10)}.zip`; a.click();
    URL.revokeObjectURL(a.href); notify('ZIP geladen.');
  };
  const alternative = async (id: string) => {
    notify('Erzeuge Alternative …');
    const r = await fetch(`/api/items/${id}/alternative`, { method: 'POST' }).then((x) => x.json());
    if (r.ok) notify('Alternative wird erzeugt — erscheint gleich hier.'); else notify(r.error || 'Fehler.');
    setTimeout(load, 2500);
  };
  // Ergebnis als neue Vorlage ins Studio übernehmen und weiterbearbeiten.
  const reuse = (id: string) => { window.location.href = `/?reuse=${id}`; };

  const newFolder = async () => {
    const name = prompt('Name des Ordners?'); if (!name) return;
    const gallery = prompt('Picdrop-Galerie für diesen Ordner? (leer = Standard)') || '';
    await fetch('/api/folders', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, picdrop_gallery: gallery.trim() || null }) });
    load();
  };
  const delFolder = async (id: string) => {
    if (!confirm('Ordner löschen? Die Bilder bleiben erhalten.')) return;
    await fetch(`/api/folders?id=${id}`, { method: 'DELETE' });
    if (folderFilter === id) setFolderFilter(null);
    load();
  };
  const renameFolder = async (o: any) => {
    const name = prompt('Ordner umbenennen:', o.name); if (name == null) return;
    const gallery = prompt('Picdrop-Galerie (leer = Standard):', o.picdrop_gallery || '');
    await fetch('/api/folders', { method: 'PATCH', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ id: o.id, name: name.trim() || o.name, picdrop_gallery: (gallery || '').trim() || null }) });
    load();
  };

  // Nach Ordner + Markierung filtern, dann Alternativen unter ihrem Ursprung gruppieren.
  const filtered = items
    .filter((v) => !folderFilter || v.folder_id === folderFilter)
    .filter((v) => !tagFilter || v.color_tag === tagFilter);
  const groupMap = new Map<string, Item[]>();
  for (const it of filtered) {
    const root = it.variant_of || it.id;
    if (!groupMap.has(root)) groupMap.set(root, []);
    groupMap.get(root)!.push(it);
  }
  const groups = [...groupMap.values()].map((g) => g.slice().sort((a, b) => +new Date(a.created_at) - +new Date(b.created_at)));
  groups.sort((a, b) => +new Date(b[b.length - 1].created_at) - +new Date(a[a.length - 1].created_at));
  const shown = (g: Item[]) => g.find((x) => x.id === variantSel[g[0].id]) || g[g.length - 1];

  return (
    <div>
      <div className="kopfzeile">
        <span className="mono-label">Bibliothek{filtered.length ? ` · ${filtered.length}` : ''}</span>
        <div className="reihe">
          {pick.size > 0 && <>
            <span className="fein">{pick.size} gewählt</span>
            <button className="mini stark" onClick={deliverSelected}>Nach Picdrop</button>
            <button className="mini" onClick={zipSelected}>ZIP laden</button>
            <select className="mini-select" value="" onChange={(e) => { if (e.target.value) moveSelected(e.target.value === '__none' ? null : e.target.value); }}>
              <option value="" disabled>In Ordner …</option>
              {folders.map((o) => <option key={o.id} value={o.id}>{o.name}</option>)}
              <option value="__none">Kein Ordner</option>
            </select>
            <button className="mini" onClick={delSelected}>Löschen</button>
          </>}
          <button className="mini" onClick={newFolder}>Neuer Ordner</button>
        </div>
      </div>

      {/* Ordner-Filter */}
      <div className="ordnerleiste">
        <button className={`chip ${!folderFilter ? 'an' : ''}`} onClick={() => setFolderFilter(null)}>Alle · {items.length}</button>
        {folders.map((o) => (
          <span key={o.id} className={`chip-wrap ${folderFilter === o.id ? 'an' : ''}`}>
            <button className="chip" onClick={() => setFolderFilter(folderFilter === o.id ? null : o.id)}>
              {o.name} · {o.count}{o.picdrop_gallery ? ' →' : ''}
            </button>
            {folderFilter === o.id && <>
              <button className="chip-x" title="Ordner umbenennen" onClick={() => renameFolder(o)}>✎</button>
              <button className="chip-x del" title="Ordner löschen" onClick={() => delFolder(o.id)}>✕</button>
            </>}
          </span>
        ))}
      </div>
      <div className="fein hinweis">Ordner gruppieren die Bibliothek und können je Ordner eine eigene Picdrop-Galerie bekommen (Pfeil = eigene Galerie hinterlegt).</div>

      {/* Farbmarkierungen filtern */}
      <div className="ordnerleiste tagbar">
        <button className={`chip ${!tagFilter ? 'an' : ''}`} onClick={() => setTagFilter(null)}>Alle Markierungen</button>
        {TAGS.map((t) => (
          <button key={t.id} className={`chip flagchip ${tagFilter === t.id ? 'an' : ''}`} onClick={() => setTagFilter(tagFilter === t.id ? null : t.id)}>
            <span className="flag" style={{ color: t.color }}>⚑</span> {t.label}
          </button>
        ))}
      </div>

      {filtered.length === 0 ? (
        <div className="leer"><span className="regmark" /><h3>{folderFilter ? 'Ordner ist leer' : 'Noch nichts erstellt'}</h3>
          <p>{folderFilter ? 'Weise Bildern über das Ordner-Menü diesen Ordner zu.' : 'Lege im Studio los — die Ergebnisse sammeln sich hier.'}</p></div>
      ) : (
        <div className="galerie">
          {groups.map((g) => {
            const v = shown(g);
            const multi = g.length > 1;
            return (
              <article key={g[0].id} className={`kachel ${pick.has(v.id) ? 'gewaehlt' : ''}`}>
                <div className="kachel-bild" onClick={() => toggle(v.id)}>
                  <img src={`/api/items/${v.id}/file?thumb=1`} alt="" loading="lazy" />
                  <span className="haken">{pick.has(v.id) ? '✓' : ''}</span>
                  {(v.mode === 'compose' || v.mode === 'generate') &&
                    <span className="modetag">{v.mode === 'compose' ? 'kombiniert' : 'erzeugt'}</span>}
                  {v.color_tag && <span className="flagbadge" style={{ color: tagColor(v.color_tag)! }}>⚑</span>}
                  {multi && <span className="fassung">Fassung {g.indexOf(v) + 1}/{g.length}</span>}
                </div>

                {multi && (
                  <div className="varianten">
                    {g.map((x, idx) => (
                      <button key={x.id} className={`vthumb ${x.id === v.id ? 'an' : ''}`}
                        onClick={() => setVariantSel((s) => ({ ...s, [g[0].id]: x.id }))} title={`Fassung ${idx + 1}`}>
                        <img src={`/api/items/${x.id}/file?thumb=1`} alt="" loading="lazy" />
                      </button>
                    ))}
                  </div>
                )}

                <input className="name" defaultValue={v.filename || ''} key={v.id} onBlur={(e) => rename(v.id, e.target.value)} />
                <div className="meta">{(v.tasks || []).join(' · ')}{v.output_px ? ` · ${v.output_px}px` : ''}{v.has_alpha ? ' · transparent' : ''}{modelName(v.model_used) ? ` · ${modelName(v.model_used)}` : ''}
                  {v.delivery_status === 'delivered' && <span className="dbadge ok">Picdrop ✓</span>}
                  {v.delivery_status === 'pending' && <span className="dbadge">Picdrop …</span>}
                  {v.delivery_status === 'failed' && <span className="dbadge err">Picdrop ✕</span>}
                  {v.nas_status === 'mirrored' && <span className="dbadge ok">NAS ✓</span>}
                  {v.nas_status === 'failed' && <span className="dbadge err">NAS ✕</span>}
                </div>
                <div className="reihe knapp">
                  <div className="tagwrap">
                    <button className="mini flagbtn" style={v.color_tag ? { color: tagColor(v.color_tag)!, borderColor: tagColor(v.color_tag)! } : {}}
                      onClick={() => setTagMenu(tagMenu === v.id ? null : v.id)} title="Markierung">⚑</button>
                    {tagMenu === v.id && (
                      <div className="tagmenu" onMouseLeave={() => setTagMenu(null)}>
                        <button onClick={() => setTag(v.id, null)}><span className="flag none">⚑</span> Keine</button>
                        {TAGS.map((t) => (
                          <button key={t.id} onClick={() => setTag(v.id, t.id)}><span className="flag" style={{ color: t.color }}>⚑</span> {t.label}</button>
                        ))}
                      </div>
                    )}
                  </div>
                  {v.prompt_used && <button className="mini" onClick={() => setPromptOf(v)}>Prompt</button>}
                  {v.mode !== 'generate' && <button className="mini" onClick={() => setCompare(v)}>Vorher/Nachher</button>}
                  <button className="mini stark2" onClick={() => setSaveView(v)} title="Groß öffnen, dann sichern (iPhone: In Fotos sichern)">Laden</button>
                  <button className="mini" onClick={() => reuse(v.id)} title="Ergebnis im Studio weiterbearbeiten">Weiter</button>
                  <button className="mini" onClick={() => alternative(v.id)} title="Weitere Fassung erzeugen">+ Alt.</button>
                  <select className="mini-select" value={v.folder_id || ''} onChange={(e) => setFolder(v.id, e.target.value || null)}>
                    <option value="">Kein Ordner</option>
                    {folders.map((o) => <option key={o.id} value={o.id}>{o.name}</option>)}
                  </select>
                  <button className="mini" onClick={() => del(v.id)}>✕</button>
                </div>
              </article>
            );
          })}
        </div>
      )}

      {compare && (
        <div className="lupe" onClick={() => setCompare(null)}>
          <div className="vergleich" onClick={(e) => e.stopPropagation()}>
            <img className="unten" src={`/api/items/${compare.id}/file?src=1`} alt="vorher" />
            <img className="oben" src={`/api/items/${compare.id}/file`} alt="nachher" id="ov" />
            <input type="range" min={0} max={100} defaultValue={50}
              onChange={(e) => { const o = document.getElementById('ov'); if (o) o.style.clipPath = `inset(0 0 0 ${e.target.value}%)`; }} />
          </div>
          <div className="lupe-fuss">{compare.filename} · {compare.output_px}px — Regler: links {compare.mode === 'compose' ? 'Vorlage' : 'Original'}, rechts Ergebnis</div>
        </div>
      )}
      {saveView && (
        <div className="lupe" onClick={() => setSaveView(null)}>
          <div className="savewrap" onClick={(e) => e.stopPropagation()}>
            <img className="saveimg blur" src={`/api/items/${saveView.id}/file?thumb=1`} alt="" />
            <img className="saveimg full" src={`/api/items/${saveView.id}/file?preview=1`} alt={saveView.filename || ''} />
          </div>
          <div className="save-fuss" onClick={(e) => e.stopPropagation()}>
            <span>📱 iPhone/iPad: lange auf das Bild tippen → <b>„In Fotos sichern"</b>.</span>
            <a className="mini stark" href={`/api/items/${saveView.id}/file?download=1`}>Original als Datei (.png)</a>
            <button className="mini" onClick={() => setSaveView(null)}>Schließen</button>
          </div>
        </div>
      )}
      {promptOf && (
        <div className="lupe" onClick={() => setPromptOf(null)}>
          <div className="promptbox" onClick={(e) => e.stopPropagation()}>
            <div className="pb-kopf"><b>{promptOf.filename}</b>
              <button className="mini" onClick={() => { navigator.clipboard?.writeText(promptOf.prompt_used || ''); notify('Prompt kopiert.'); }}>Kopieren</button></div>
            <pre className="pb-text">{promptOf.prompt_used}</pre>
            <div className="fein">{promptOf.model_used ? `Modell: ${modelName(promptOf.model_used)} · ` : ''}{promptOf.output_px}px</div>
          </div>
        </div>
      )}
      {toast && <div className="toast">{toast}</div>}
      <LibStyles />
    </div>
  );
}

function LibStyles() {
  return <style>{`
    .kopfzeile{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap;}
    .reihe{display:flex;gap:8px;align-items:center;flex-wrap:wrap;}.reihe.knapp{margin-top:8px;}
    .fein{font-size:11.5px;color:var(--soft);}
    .hinweis{margin:0 0 14px;line-height:1.5;}
    .mini{background:var(--card);border:1px solid var(--line);border-radius:3px;padding:6px 11px;cursor:pointer;font-family:inherit;font-size:12.5px;color:var(--ink);text-decoration:none;}
    .ordnerleiste{display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-bottom:8px;}
    .chip-wrap{display:inline-flex;align-items:center;border-radius:20px;}
    .chip{background:var(--card);border:1px solid var(--line);border-radius:20px;padding:6px 13px;cursor:pointer;font-family:var(--font-mono);font-size:11px;letter-spacing:.04em;color:var(--soft);white-space:nowrap;}
    .chip.an,.chip-wrap.an .chip{border-color:var(--accent);background:var(--accent-bg);color:var(--accent);}
    .chip-x{border:none;background:none;color:var(--accent);cursor:pointer;font-size:12px;padding:0 4px;}
    .chip-x.del{color:var(--err);padding:0 8px 0 2px;}
    .leer{padding:60px 24px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:10px;}
    .leer h3{margin:0;font-size:17px;}.leer p{margin:0;color:var(--soft);max-width:38ch;}
    .galerie{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px;align-items:start;}
    @media(min-width:768px){.galerie{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px;}}
    .kachel{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:8px;}
    .kachel.gewaehlt{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent);}
    .kachel-bild{position:relative;border-radius:3px;overflow:hidden;cursor:pointer;
      background:repeating-conic-gradient(oklch(90% 0.006 95) 0% 25%, oklch(96% 0.004 95) 0% 50%) 50%/16px 16px;}
    .kachel-bild img{width:100%;height:auto;display:block;transition:transform .12s;}
    .kachel-bild:active img{transform:scale(.98);}
    .haken{position:absolute;top:6px;left:6px;width:21px;height:21px;border-radius:50%;border:1.5px solid #fff;background:rgba(22,21,15,.35);color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;}
    .kachel.gewaehlt .haken{background:var(--accent);}
    .modetag{position:absolute;top:6px;right:6px;background:rgba(59,91,219,.92);color:#fff;font-family:var(--font-mono);font-size:9px;letter-spacing:.06em;text-transform:uppercase;padding:2px 7px;border-radius:20px;}
    .flagbadge{position:absolute;top:5px;left:6px;font-size:19px;line-height:1;text-shadow:0 1px 2px rgba(0,0,0,.35);}
    .tagbar{margin:0 0 12px;}
    .flagchip .flag{font-size:13px;vertical-align:-1px;}
    .flag.none{color:var(--soft);}
    .tagwrap{position:relative;display:inline-block;}
    .flagbtn{font-size:14px;line-height:1;padding:5px 9px;}
    .tagmenu{position:absolute;bottom:calc(100% + 4px);left:0;z-index:20;background:var(--card);border:1px solid var(--line);border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,.16);padding:5px;display:flex;flex-direction:column;min-width:130px;}
    .tagmenu button{display:flex;align-items:center;gap:8px;background:none;border:none;text-align:left;padding:7px 9px;cursor:pointer;font-family:inherit;font-size:13px;border-radius:4px;color:var(--ink);}
    .tagmenu button:hover{background:var(--paper);}
    .tagmenu .flag{font-size:15px;}
    .savewrap{position:relative;max-width:94vw;max-height:78vh;display:flex;}
    .saveimg{max-width:94vw;max-height:78vh;border-radius:4px;display:block;}
    .saveimg.blur{filter:blur(8px);position:absolute;inset:0;width:100%;height:100%;object-fit:contain;}
    .saveimg.full{position:relative;z-index:1;}
    .save-fuss{display:flex;flex-direction:column;align-items:center;gap:10px;color:#EAEAE3;font-size:13.5px;text-align:center;max-width:90vw;}
    .fassung{position:absolute;bottom:6px;right:6px;background:rgba(22,21,15,.7);color:#fff;font-family:var(--font-mono);font-size:9px;padding:2px 7px;border-radius:20px;}
    .varianten{display:flex;gap:5px;margin-top:6px;overflow-x:auto;}
    .vthumb{flex:0 0 auto;width:40px;height:40px;border:1px solid var(--line);border-radius:3px;overflow:hidden;padding:0;background:none;cursor:pointer;}
    .vthumb.an{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent);}
    .vthumb img{width:100%;height:100%;object-fit:cover;display:block;}
    .name{margin-top:8px;width:100%;font-size:12.5px;padding:6px 8px;font-family:var(--font-mono);border:1px solid var(--line);border-radius:3px;background:#fff;}
    .meta{font-size:11px;color:var(--soft);margin-top:5px;}
    .mini.stark{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600;}
    .mini.stark2{border-color:var(--accent);color:var(--accent);font-weight:600;}
    .dbadge{display:inline-block;margin-left:6px;font-family:var(--font-mono);font-size:9px;letter-spacing:.08em;text-transform:uppercase;background:var(--paper);color:var(--soft);padding:1px 6px;border-radius:20px;}
    .dbadge.ok{background:var(--accent-bg);color:var(--accent);}
    .dbadge.err{color:var(--err);}
    .mini-select{border:1px solid var(--line);border-radius:3px;padding:5px 7px;font-family:inherit;font-size:12px;background:#fff;}
    .lupe{position:fixed;inset:0;background:rgba(22,21,15,.85);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:26px;z-index:50;}
    .vergleich{position:relative;max-width:90vw;max-height:76vh;}
    .vergleich img{max-width:90vw;max-height:70vh;display:block;border-radius:3px;}
    .vergleich .oben{position:absolute;inset:0;clip-path:inset(0 0 0 50%);}
    .vergleich input[type=range]{position:absolute;left:0;right:0;bottom:-34px;width:100%;}
    .lupe-fuss{color:#EAEAE3;font-family:var(--font-mono);font-size:12px;margin-top:30px;text-align:center;}
    .promptbox{background:var(--card);border-radius:var(--radius);max-width:min(92vw,620px);width:100%;padding:16px;display:flex;flex-direction:column;gap:10px;}
    .pb-kopf{display:flex;justify-content:space-between;align-items:center;gap:10px;}
    .pb-text{white-space:pre-wrap;word-break:break-word;font-family:var(--font-mono);font-size:12.5px;line-height:1.5;background:var(--paper);border:1px solid var(--line);border-radius:4px;padding:12px;max-height:50vh;overflow:auto;margin:0;}
    .toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);background:var(--ink);color:#FBFBF7;padding:10px 18px;border-radius:3px;font-size:13.5px;z-index:60;}
  `}</style>;
}
