// minimal-atoms.jsx — palette, fonts, contexts, common atoms (Reisetagebuch / Variante C)

(function () {
  const { useState, useMemo, useEffect, createContext, useContext } = React;
  const { CATS, Icon, expDate, expTime, expCat, expDesc, expLoc, expAmt } = window;

  // ── Palette ─────────────────────────────────────────────────
  const p = {
    paper:   '#f7f3eb',
    paper2:  '#fdfaf3',
    paper3:  '#efe9d8',
    ink:     '#1c1a16',
    ink2:    '#2c2a24',
    muted:   '#7a7468',
    line:    '#dcd5c5',
    line2:   '#c8bfa8',
    accent:  '#2e5a3d',   // forest green
    accent2: '#3d7350',
    rust:    '#a44a2a',
    rule:    'rgba(28,26,22,0.10)',
    seaBg:   '#e6e0cf',
    landBg:  '#efeadd',
  };
  // Poppins everywhere — display uses 600/500, body 400.
  const F = 'Poppins, -apple-system, system-ui, sans-serif';
  const MONO = '"JetBrains Mono", ui-monospace, monospace';

  // ── Category state — kommt aus UKProviders.useData ──────────
  const CatContext = createContext(null);
  // Passthrough — der echte Provider ist UKProviders.DataAndSyncProvider.
  const CatProvider = ({ children }) => <>{children}</>;
  const FALLBACK_CATS = CATS.map(c => ({ ...c, is_user: 0, deleted: 0, updated_at: 0, synced: 1 }));
  const useCats = () => {
    const data = window.UKProviders && window.UKProviders.useData ? window.UKProviders.useData() : null;
    const cats = (data && data.categories && data.categories.length) ? data.categories : FALLBACK_CATS;
    const catById = useMemo(() => Object.fromEntries(cats.map(c => [c.id, c])), [cats]);
    return {
      cats, catById,
      addCat:    (label, emoji) => data && data.addCategory(label, emoji),
      removeCat: (id) => data && data.removeCategory(id),
    };
  };

  // ── Trip nav state (which view) ─────────────────────────────
  const NavContext = createContext(null);
  const useNav = () => useContext(NavContext);

  // ── Sync state — kommt aus UKProviders.useSync ──────────────
  const SyncContext = createContext(null);
  const SyncProvider = ({ children }) => <>{children}</>;
  const useSync = () => {
    const s = window.UKProviders && window.UKProviders.useSync ? window.UKProviders.useSync() : null;
    if (!s) return { online: true, pending: 0, lastSync: null, syncing: false,
                     syncNow: () => {}, setOnline: () => {}, queueOne: () => {}, error: null };
    return { ...s, queueOne: () => {} };
  };

  const fmtSyncAge = (d) => {
    if (!d) return 'noch nie';
    const diff = (Date.now() - d.getTime()) / 1000;
    if (diff < 60)     return 'gerade eben';
    if (diff < 3600)   return `vor ${Math.round(diff/60)} Min`;
    if (diff < 86400)  return `vor ${Math.round(diff/3600)} Std`;
    return `vor ${Math.round(diff/86400)} Tag(en)`;
  };

  // ── Common atoms ────────────────────────────────────────────
  const Eyebrow = ({ children, style = {} }) => (
    <div style={{
      fontFamily: F, fontSize: 10, color: p.muted, fontWeight: 600,
      letterSpacing: 1.5, textTransform: 'uppercase', ...style,
    }}>{children}</div>
  );

  const HRule = ({ label, style = {} }) => (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '0 24px', margin: '22px 0 12px', ...style }}>
      <div style={{ flex: 1, height: 1, background: p.rule }}/>
      {label && <Eyebrow style={{ fontSize: 9, letterSpacing: 2 }}>{label}</Eyebrow>}
      <div style={{ flex: 1, height: 1, background: p.rule }}/>
    </div>
  );

  const CatMark = ({ cat, size = 24 }) => (
    <div style={{
      width: size, height: size, borderRadius: 2,
      background: cat ? cat.color + '14' : 'transparent', border: `1px solid ${cat ? cat.color + '55' : p.line2}`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontSize: size * 0.55, flexShrink: 0,
    }}>{cat ? cat.emoji : '?'}</div>
  );

  const Metric = ({ label, value, sub }) => (
    <div>
      <Eyebrow>{label}</Eyebrow>
      <div style={{ fontFamily: F, fontSize: 22, color: p.ink, fontWeight: 600, marginTop: 4, letterSpacing: -0.3 }}>{value}</div>
      <div style={{ fontFamily: F, fontSize: 11, color: p.muted, marginTop: 2 }}>{sub}</div>
    </div>
  );

  const Pchip = ({ children, active, onClick, style = {} }) => (
    <button onClick={onClick} style={{
      flexShrink: 0, padding: '4px 10px', borderRadius: 999,
      border: `1px solid ${active ? p.ink : p.line}`,
      background: active ? p.ink : 'transparent',
      color: active ? p.paper : p.ink,
      fontFamily: F, fontSize: 11, fontWeight: 500, cursor: 'pointer', ...style,
    }}>{children}</button>
  );

  // List row for expenses — opens detail on click
  function ListRow({ e, onClick }) {
    const { catById } = useCats();
    const c = catById[expCat(e)];
    return (
      <button onClick={() => onClick && onClick(e)} style={{
        width: '100%', display: 'flex', alignItems: 'center', gap: 10,
        padding: '10px 0', borderBottom: `1px solid ${p.rule}`,
        border: 0, background: 'transparent', cursor: onClick ? 'pointer' : 'default',
        textAlign: 'left',
      }}>
        <div style={{ width: 32, fontFamily: F, fontSize: 11, color: p.muted, fontWeight: 500 }}>{expTime(e) || ''}</div>
        <CatMark cat={c} size={24}/>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: F, fontSize: 14, color: p.ink, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{expDesc(e) || '—'}</div>
          <div style={{ fontFamily: F, fontSize: 10, color: p.muted, marginTop: 1, display: 'flex', alignItems: 'center', gap: 4 }}>
            <span>{expLoc(e) || ''}</span>
            {expLoc(e) && <span>·</span>}
            <span>{c ? c.label : '—'}</span>
          </div>
        </div>
        <div style={{ fontFamily: F, fontSize: 15, color: p.ink, fontWeight: 600 }}>
          {expAmt(e).toLocaleString('de-DE', { minimumFractionDigits: 2 })}&nbsp;€
        </div>
      </button>
    );
  }

  // FAB
  const FAB = ({ onClick }) => (
    <button onClick={onClick} style={{
      position: 'absolute', bottom: 50, right: 22, zIndex: 30,
      width: 56, height: 56, borderRadius: 28,
      border: 0, background: p.ink, color: p.paper,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      cursor: 'pointer', boxShadow: '0 10px 26px rgba(28,26,22,0.30)',
    }}>
      <Icon.plus/>
    </button>
  );

  // Overlay wrapper
  const Overlay = ({ children }) => (
    <div style={{ position: 'absolute', inset: 0, zIndex: 28, overflow: 'auto',
      animation: 'minSlide 0.22s ease-out' }}>
      <style>{`@keyframes minSlide { from { transform: translateY(20px); opacity: 0; } to { transform: none; opacity: 1; } }`}</style>
      {children}
    </div>
  );

  function OverlayHead({ onBack, label, action }) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 18px' }}>
        <button onClick={onBack} style={{
          border: 0, background: 'transparent', color: p.ink, cursor: 'pointer',
          display: 'flex', alignItems: 'center', gap: 6, fontFamily: F, fontSize: 14, fontWeight: 500,
        }}>
          <Icon.back/> zurück
        </button>
        {label && <Eyebrow>{label}</Eyebrow>}
        <div style={{ minWidth: 60, display: 'flex', justifyContent: 'flex-end' }}>{action}</div>
      </div>
    );
  }

  // ── Receipt capture — Foto aufnehmen / aus Galerie wählen ───
  const MAX_RECEIPT_DIM = 1600;
  const RECEIPT_QUALITY = 0.85;

  async function shrinkPhoto(file) {
    const bitmap = await createImageBitmap(file);
    try {
      const scale = Math.min(1, MAX_RECEIPT_DIM / Math.max(bitmap.width, bitmap.height));
      const w = Math.max(1, Math.round(bitmap.width * scale));
      const h = Math.max(1, Math.round(bitmap.height * scale));
      const canvas = document.createElement('canvas');
      canvas.width = w; canvas.height = h;
      canvas.getContext('2d').drawImage(bitmap, 0, 0, w, h);
      return await new Promise(resolve => canvas.toBlob(b => resolve(b), 'image/jpeg', RECEIPT_QUALITY));
    } finally {
      bitmap.close && bitmap.close();
    }
  }

  function ReceiptCapture({ onPick, existingUrl, height = 140, label = 'Beleg-Foto aufnehmen' }) {
    const [preview, setPreview] = useState(null);
    const inputRef = React.useRef(null);

    useEffect(() => {
      if (!existingUrl) { setPreview(null); return; }
      let url = null;
      let cancelled = false;
      (async () => {
        try {
          const m = /id=([^&]+)/.exec(existingUrl);
          const id = m ? decodeURIComponent(m[1]) : null;
          if (!id) return;
          url = await window.UKAPI.receiptBlobUrl(id);
          if (!cancelled) setPreview(url);
        } catch (_) { /* keine Vorschau */ }
      })();
      return () => {
        cancelled = true;
        if (url) URL.revokeObjectURL(url);
      };
    }, [existingUrl]);

    const handle = async (e) => {
      const f = e.target.files && e.target.files[0];
      if (!f) return;
      try {
        const blob = await shrinkPhoto(f);
        const url = URL.createObjectURL(blob);
        setPreview(url);
        onPick && onPick(blob, 'image/jpeg');
      } catch (err) {
        alert('Foto konnte nicht verarbeitet werden: ' + err.message);
      }
    };

    return (
      <div onClick={() => inputRef.current && inputRef.current.click()} style={{
        height, borderRadius: 6,
        border: preview ? '1px solid ' + p.line2 : '1.5px dashed ' + p.line2,
        background: preview ? p.paper2 : p.paper3,
        cursor: 'pointer', position: 'relative', overflow: 'hidden',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <input ref={inputRef} type="file" accept="image/*" capture="environment"
          onChange={handle} style={{ display: 'none' }}/>
        {preview
          ? <img src={preview} alt="Beleg" style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
          : <div style={{ fontFamily: F, fontSize: 12, color: p.muted, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
              <div style={{
                width: 38, height: 38, borderRadius: 999, background: p.paper2,
                border: '1px solid ' + p.line2, color: p.accent,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <Icon.cam style={{ width: 18, height: 18 }}/>
              </div>
              {label}
            </div>
        }
      </div>
    );
  }

  const ReceiptSlot = (props) => <ReceiptCapture {...props}/>;

  function ConfirmModal({ title, message, confirmLabel, destructive, onCancel, onConfirm }) {
    const lbl = confirmLabel || 'OK';
    const dest = destructive !== false;
    return (
      <div style={{
        position: 'absolute', inset: 0, zIndex: 200,
        background: 'rgba(28,26,22,0.45)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: 24,
      }}>
        <div style={{
          background: p.paper, borderRadius: 10, padding: '20px 22px',
          maxWidth: 320, width: '100%', boxShadow: '0 12px 32px rgba(0,0,0,0.18)',
        }}>
          <div style={{ fontFamily: F, fontSize: 16, fontWeight: 600, color: p.ink, marginBottom: 8 }}>
            {title}
          </div>
          <div style={{ fontFamily: F, fontSize: 13, color: p.ink2, lineHeight: 1.5, marginBottom: 16 }}>
            {message}
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <button onClick={onCancel} style={{
              flex: 1, border: '1px solid ' + p.line2, background: 'transparent', color: p.ink,
              fontFamily: F, fontSize: 13, fontWeight: 500, padding: '9px 0', borderRadius: 5, cursor: 'pointer',
            }}>Abbrechen</button>
            <button onClick={onConfirm} style={{
              flex: 1, border: 0,
              background: dest ? p.rust : p.accent, color: p.paper,
              fontFamily: F, fontSize: 13, fontWeight: 600, padding: '9px 0', borderRadius: 5, cursor: 'pointer',
            }}>{lbl}</button>
          </div>
        </div>
      </div>
    );
  }

  function EmptyState({ title, hint }) {
    return (
      <div style={{
        padding: '40px 24px', textAlign: 'center',
        fontFamily: F, color: p.muted,
      }}>
        <div style={{ fontSize: 14, color: p.ink, fontWeight: 600, marginBottom: 6 }}>{title}</div>
        {hint && <div style={{ fontSize: 12, lineHeight: 1.5 }}>{hint}</div>}
      </div>
    );
  }

  Object.assign(window, {
    MinPalette: p, MinF: F, MinMono: MONO,
    CatContext, CatProvider, useCats,
    NavContext, useNav,
    SyncContext, SyncProvider, useSync, fmtSyncAge,
    MinEyebrow: Eyebrow, MinHRule: HRule, MinCatMark: CatMark, MinMetric: Metric,
    MinPchip: Pchip, MinListRow: ListRow, MinFAB: FAB,
    MinOverlay: Overlay, MinOverlayHead: OverlayHead,
    MinReceiptSlot: ReceiptSlot,
    MinReceiptCapture: ReceiptCapture,
    MinConfirmModal: ConfirmModal,
    MinEmptyState: EmptyState,
  });
})();
