/* Wedding Gifts — RTL fuzzy search app */
const { useState, useMemo, useEffect, useRef, useCallback } = React;
const { WEDDINGS, WEDDING_ORDER, FIELDS } = window.Data;

const ILS = (n) => '₪' + Number(n).toLocaleString('he-IL');

/* ---------- Highlighted name ---------- */
function HighlightedName({ name, query }) {
  const segs = useMemo(() => window.Fuzzy.highlightSegments(name, query), [name, query]);
  return (
    <span>
      {segs.map((s, i) => s.hit
        ? <mark key={i} className="hl">{s.text}</mark>
        : <React.Fragment key={i}>{s.text}</React.Fragment>)}
    </span>
  );
}

/* ---------- Ornament ---------- */
function Ornament() {
  return (
    <div className="ornament" aria-hidden="true">
      <span className="line" />
      <svg width="18" height="18" viewBox="0 0 18 18"><path d="M9 1 L17 9 L9 17 L1 9 Z" fill="none" stroke="currentColor" strokeWidth="1.2"/></svg>
      <span className="line" />
    </div>
  );
}

/* ---------- Result card ---------- */
function ResultCard({ rec, query }) {
  const w = WEDDINGS[rec.wedding];
  const hasGift = rec.amount != null && rec.amount > 0;
  const invited = String(rec.invited || '').trim();
  const arrived = String(rec.arrived || '').trim();
  const showGuests = invited !== '' || arrived !== '';

  return (
    <article className="card" style={{ '--w-accent': w.accent, '--w-soft': w.soft, '--w-ink': w.ink }}>
      <div className="card-top">
        <h3 className="card-name"><HighlightedName name={rec.name} query={query} /></h3>
        <span className="badge">{w.title}</span>
      </div>

      <div className="card-amount">
        {hasGift
          ? <span className="amt">{ILS(rec.amount)}</span>
          : <span className="amt amt-none">— לא ידוע</span>}
      </div>

      <div className="card-meta">
        {rec.side ? <span className="chip"><i className="k">צד</i>{rec.side}</span> : null}
        {showGuests
          ? <span className="chip"><i className="k">אורחים</i>{(invited || '0')} הוזמנו · {(arrived || '0')} הגיעו</span>
          : null}
        {rec.notes ? <span className="chip chip-note"><i className="k">הערה</i>{rec.notes}</span> : null}
      </div>
    </article>
  );
}

/* ---------- Empty / hint states ---------- */
function StartHint({ counts }) {
  return (
    <div className="hint">
      <Ornament />
      <p className="hint-lead">חיפוש מתנות חתונה</p>
      <p className="hint-sub">הקלידו שם כדי למצוא כמה נתנו, ומאיזו חתונה.</p>
      <div className="hint-counts">
        {WEDDING_ORDER.map((wid) => (
          <div key={wid} className="hint-count" style={{ '--w-accent': WEDDINGS[wid].accent, '--w-soft': WEDDINGS[wid].soft, '--w-ink': WEDDINGS[wid].ink }}>
            <span className="dot" />
            <div>
              <div className="hc-title">{WEDDINGS[wid].title}</div>
              <div className="hc-sub">{WEDDINGS[wid].subtitle} · {counts[wid] || 0} רשומות</div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function NoResults({ query }) {
  return (
    <div className="hint">
      <Ornament />
      <p className="hint-lead">לא נמצאו תוצאות</p>
      <p className="hint-sub">לא מצאנו התאמה עבור «{query}». נסו איות אחר או שם פרטי בלבד.</p>
    </div>
  );
}

/* ---------- Filter chips ---------- */
function FilterChips({ value, onChange, counts }) {
  const opts = [{ id: 'all', title: 'הכל' }].concat(WEDDING_ORDER.map((wid) => ({ id: wid, title: WEDDINGS[wid].title })));
  return (
    <div className="filters">
      {opts.map((o) => (
        <button
          key={o.id}
          className={'fchip' + (value === o.id ? ' on' : '')}
          style={o.id !== 'all' ? { '--w-accent': WEDDINGS[o.id].accent, '--w-soft': WEDDINGS[o.id].soft, '--w-ink': WEDDINGS[o.id].ink } : {}}
          onClick={() => onChange(o.id)}
        >
          {o.id !== 'all' ? <span className="fdot" /> : null}
          {o.title}
        </button>
      ))}
    </div>
  );
}

/* ---------- Import sheet ---------- */
function MappingRow({ label, field, headers, value, onChange }) {
  return (
    <div className="map-row">
      <label>{label}</label>
      <select value={value == null ? -1 : value} onChange={(e) => onChange(field, parseInt(e.target.value, 10))}>
        <option value={-1}>— ללא —</option>
        {headers.map((h, i) => <option key={i} value={i}>{h || ('עמודה ' + (i + 1))}</option>)}
      </select>
    </div>
  );
}

const FIELD_LABELS = { name: 'שם', amount: 'סכום (כמה שמו)', side: 'צד', notes: 'הערות', invited: 'כמה הוזמנו', arrived: 'כמה הגיעו', phone: 'טלפון' };

function WeddingImport({ wid, onApply }) {
  const w = WEDDINGS[wid];
  const [text, setText] = useState('');
  const [headers, setHeaders] = useState(null);
  const [mapping, setMapping] = useState({});
  const [count, setCount] = useState(0);
  const fileRef = useRef(null);

  function ingest(csv) {
    setText(csv);
    const res = window.Data.buildRecords(csv, wid);
    setHeaders(res.headers);
    setMapping(res.mapping);
    setCount(res.records.length);
  }
  function onFile(e) {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    const r = new FileReader();
    r.onload = () => ingest(String(r.result || ''));
    r.readAsText(f, 'utf-8');
  }
  function remap(field, idx) {
    const m = Object.assign({}, mapping, { [field]: idx });
    setMapping(m);
    const res = window.Data.buildRecords(text, wid, m);
    setCount(res.records.length);
  }
  function apply() {
    if (!text.trim()) return;
    const res = window.Data.buildRecords(text, wid, mapping);
    onApply(wid, res.records);
    setText(''); setHeaders(null); setMapping({}); setCount(0);
    if (fileRef.current) fileRef.current.value = '';
  }

  return (
    <section className="imp-wed" style={{ '--w-accent': w.accent, '--w-soft': w.soft, '--w-ink': w.ink }}>
      <header className="imp-wed-head">
        <span className="dot" />
        <div>
          <div className="iw-title">{w.title}</div>
          <div className="iw-sub">{w.subtitle}</div>
        </div>
      </header>

      <textarea
        className="imp-area"
        dir="rtl"
        placeholder="הדביקו כאן את תוכן ה‑CSV (כולל שורת הכותרות)…"
        value={text}
        onChange={(e) => ingest(e.target.value)}
      />
      <div className="imp-actions">
        <label className="file-btn">
          העלאת קובץ CSV
          <input ref={fileRef} type="file" accept=".csv,text/csv" onChange={onFile} hidden />
        </label>
        {headers ? <span className="imp-count">זוהו {count} רשומות</span> : null}
      </div>

      {headers ? (
        <details className="map-box">
          <summary>התאמת עמודות {mapping.name == null ? '⚠️' : '✓'}</summary>
          <div className="map-grid">
            {FIELDS.map((f) => (
              <MappingRow key={f} label={FIELD_LABELS[f]} field={f} headers={headers} value={mapping[f]} onChange={remap} />
            ))}
          </div>
        </details>
      ) : null}

      <button className="apply-btn" disabled={!text.trim() || mapping.name == null} onClick={apply}>
        שמירת הנתונים של {w.title}
      </button>
    </section>
  );
}

function ImportSheet({ open, onClose, onApply, onReset, counts }) {
  if (!open) return null;
  return (
    <div className="sheet-wrap" onClick={onClose}>
      <div className="sheet" onClick={(e) => e.stopPropagation()}>
        <div className="sheet-grab" />
        <header className="sheet-head">
          <h2>ניהול נתונים</h2>
          <button className="x" onClick={onClose} aria-label="סגירה">✕</button>
        </header>
        <p className="sheet-intro">
          ייצאו כל גיליון Google כ‑CSV והדביקו / העלו אותו כאן. הנתונים נשמרים במכשיר שלכם בלבד.
        </p>
        {WEDDING_ORDER.map((wid) => (
          <WeddingImport key={wid} wid={wid} onApply={onApply} />
        ))}
        <button className="reset-btn" onClick={onReset}>איפוס לנתונים המקוריים</button>
        <p className="sheet-foot">נטענו כעת: {WEDDING_ORDER.map((w) => WEDDINGS[w].title + ' · ' + (counts[w] || 0)).join('   |   ')}</p>
      </div>
    </div>
  );
}

/* ---------- Install (Add to Home Screen) banner ---------- */
const INSTALL_DISMISS_KEY = 'kss_install_dismissed_v1';

function isStandalone() {
  return window.navigator.standalone === true ||
    (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches);
}

function ShareIcon() {
  // iOS "Share" glyph — the button users tap to reach "הוספה למסך הבית"
  return (
    <svg className="shareico" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#2F5E9B" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M12 15V4" /><path d="M8.5 7.5 12 4l3.5 3.5" />
      <path d="M6 11H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2h-1" />
    </svg>
  );
}

function InstallBanner({ onDismiss }) {
  return (
    <div className="install-banner" role="note">
      <span className="install-ico"><img src="icons/icon-192.png" alt="" /></span>
      <div className="install-text">
        <div className="install-title">התקינו את «כמה שמו?»</div>
        <div className="install-sub">
          הוסיפו למסך הבית: הקישו על <ShareIcon /> ואז «הוספה למסך הבית».
        </div>
      </div>
      <button className="install-x" onClick={onDismiss} aria-label="סגירת ההצעה להתקנה">✕</button>
    </div>
  );
}

/* ---------- App ---------- */
function App() {
  const [records, setRecords] = useState(() => {
    const stored = window.Data.load();
    if (stored && stored.records && stored.records.length) return stored.records;
    return window.Data.seedRecords();
  });
  const [query, setQuery] = useState('');
  const [filter, setFilter] = useState('all');
  const [importOpen, setImportOpen] = useState(false);
  const [showInstall, setShowInstall] = useState(false);
  const metaRef = useRef(null);       // { sig, source: 'seed' | 'remote' | 'imported' }
  const lastFetchRef = useRef(0);

  // Cache-first with background revalidation: whatever is cached renders
  // immediately, then we pull the latest data from the network and swap it in
  // if it changed. Skips when the user has imported their own data, and keeps
  // the cache untouched when offline / on error.
  const refresh = useCallback(async (force) => {
    const meta = metaRef.current;
    if (meta && meta.source === 'imported') return;
    const now = Date.now();
    if (!force && now - lastFetchRef.current < 30000) return;
    lastFetchRef.current = now;
    const fresh = await window.Data.fetchRecords();
    if (!fresh) return;
    const sig = window.Data.signature(fresh);
    if (meta && sig === meta.sig) return;
    metaRef.current = { sig, source: 'remote' };
    window.Data.save({ records: fresh, sig, source: 'remote' });
    setRecords(fresh);
  }, []);

  useEffect(() => {
    const stored = window.Data.load();
    if (stored && stored.records && stored.records.length) {
      metaRef.current = { sig: stored.sig || '', source: stored.source || 'seed' };
    } else {
      const seed = window.Data.seedRecords();
      const sig = window.Data.signature(seed);
      metaRef.current = { sig, source: 'seed' };
      window.Data.save({ records: seed, sig, source: 'seed' });
    }
    refresh(true);                                  // pull on load
    const onVis = () => { if (document.visibilityState === 'visible') refresh(); };
    document.addEventListener('visibilitychange', onVis);
    const id = setInterval(() => refresh(), 5 * 60 * 1000);   // and every 5 min
    return () => { document.removeEventListener('visibilitychange', onVis); clearInterval(id); };
  }, [refresh]);

  // Show the "Add to Home Screen" banner once, until dismissed — and never inside the installed app.
  useEffect(() => {
    let dismissed = false;
    try { dismissed = localStorage.getItem(INSTALL_DISMISS_KEY) === '1'; } catch (e) {}
    if (!dismissed && !isStandalone()) setShowInstall(true);
  }, []);

  function dismissInstall() {
    try { localStorage.setItem(INSTALL_DISMISS_KEY, '1'); } catch (e) {}
    setShowInstall(false);
  }

  const counts = useMemo(() => {
    const c = {};
    records.forEach((r) => { c[r.wedding] = (c[r.wedding] || 0) + 1; });
    return c;
  }, [records]);

  const results = useMemo(() => {
    const base = filter === 'all' ? records : records.filter((r) => r.wedding === filter);
    const q = query.trim();
    if (!q) return [];
    const scored = [];
    for (const r of base) {
      const s = window.Fuzzy.scoreName(q, r.name);
      if (s >= 0.34) scored.push({ rec: r, score: s });
    }
    scored.sort((a, b) => (b.score - a.score) || ((b.rec.amount || 0) - (a.rec.amount || 0)));
    return scored.map((x) => x.rec);
  }, [records, query, filter]);

  const total = useMemo(() => results.reduce((s, r) => s + (r.amount || 0), 0), [results]);
  const searching = query.trim().length > 0;

  function applyWedding(wid, recs) {
    setRecords((prev) => {
      const next = prev.filter((r) => r.wedding !== wid).concat(recs);
      const sig = window.Data.signature(next);
      metaRef.current = { sig, source: 'imported' };
      window.Data.save({ records: next, sig, source: 'imported' });
      return next;
    });
    setImportOpen(false);
  }
  function resetSeed() {
    const seed = window.Data.seedRecords();
    const sig = window.Data.signature(seed);
    metaRef.current = { sig, source: 'seed' };
    window.Data.save({ records: seed, sig, source: 'seed' });
    setRecords(seed);
    setImportOpen(false);
    refresh(true);                                  // reset → immediately pull latest live data
  }

  return (
    <div className="app">
      <header className="topbar">
        <div className="brand">
          <span className="brand-mark has-img"><img src="icons/icon-192.png" alt="כמה שמו?" /></span>
          <div>
            <div className="brand-title">כמה שמו?</div>
            <div className="brand-sub">חיפוש מי נתן וכמה</div>
          </div>
        </div>
        <button className="gear" onClick={() => setImportOpen(true)} aria-label="ניהול נתונים">
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><path d="M4 7h16M4 12h16M4 17h10"/></svg>
        </button>
      </header>

      {showInstall ? <InstallBanner onDismiss={dismissInstall} /> : null}

      <div className="searchbar">
        <div className="search-input">
          <svg className="s-ico" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.2-3.2"/></svg>
          <input
            type="search"
            inputMode="search"
            placeholder="חיפוש לפי שם…"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            autoFocus
          />
          {query ? <button className="clear" onClick={() => setQuery('')} aria-label="ניקוי">✕</button> : null}
        </div>
        <FilterChips value={filter} onChange={setFilter} counts={counts} />
      </div>

      <main className="results">
        {!searching ? <StartHint counts={counts} />
          : results.length === 0 ? <NoResults query={query.trim()} />
            : results.map((r) => <ResultCard key={r.id} rec={r} query={query} />)}
      </main>

      {searching && results.length > 0 ? (
        <footer className="totalbar">
          <span className="t-count">{results.length} תוצאות</span>
          <span className="t-sum">{ILS(total)}</span>
        </footer>
      ) : null}

      <ImportSheet
        open={importOpen}
        onClose={() => setImportOpen(false)}
        onApply={applyWedding}
        onReset={resetSeed}
        counts={counts}
      />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
