/* =========================================================
   Tappt — Moment card (edit · delete · comments · likes)
   + branded auth-gate popup for logged-out visitors.
   Shared by the dashboard (MomentsScreen, profile) and the
   public live profile, so behaviour is always identical.
   ========================================================= */
/* shared lime verified seal — used on profile, moments, comments, bio */
function VerifiedSeal({ size = 18 }) {
  return (
    <svg className="vseal-ico" width={size} height={size} viewBox="0 0 24 24" aria-label="Verified" style={{ flex: 'none' }}>
      <path fill="var(--brand)" d="M23 12l-2.44-2.79.34-3.69-3.61-.82-1.89-3.2L12 2.96 8.6 1.5 6.71 4.69 3.1 5.5l.34 3.7L1 12l2.44 2.79-.34 3.7 3.61.82L8.6 22.5l3.4-1.47 3.4 1.46 1.89-3.19 3.61-.82-.34-3.69z"/>
      <path fill="#0B0B0C" d="M10.09 16.72l-3.8-3.81 1.48-1.48 2.32 2.33 5.85-5.87 1.48 1.48z"/>
    </svg>
  );
}
window.VerifiedSeal = VerifiedSeal;
const { useState: moUse, useRef: moRef } = React;
const playMuted = (el) => { if (el) { el.muted = true; el.defaultMuted = true; const p = el.play(); if (p && p.catch) p.catch(() => {}); } };
window.playMuted = playMuted;

/* nice Tappt-branded "make an account" popup */
function AuthGateModal({ onClose, action }) {
  return (
    <div className="sheet-bg authgate-bg" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="authgate" role="dialog" aria-modal="true">
        <button className="authgate-x" onClick={onClose} aria-label="Close">{MI.close ? MI.close({ width: 16, height: 16 }) : '✕'}</button>
        <div className="authgate-logo">
          <img className="ag-logo dark-logo" src="assets/logo-white.png" alt="Tappt" />
          <img className="ag-logo light-logo" src="assets/logo-black.png" alt="Tappt" />
        </div>
        <div className="authgate-t">Join the conversation</div>
        <div className="authgate-s">Create a free Tappt account to {action || 'comment'} — and start building your own profile.</div>
        <a className="authgate-cta" href="app.html">Create free account</a>
        <a className="authgate-alt" href="app.html">I already have one</a>
      </div>
    </div>
  );
}

function CommentRow({ c, small, onLike, onReply }) {
  const when = window.momentWhen ? window.momentWhen(c.ts) : 'now';
  return (
    <div className={'cm-row' + (small ? ' cm-row-sm' : '')}>
      <span className="cm-av"><Avatar user={c} size={small ? 26 : 30} coverFallback /></span>
      <div className="cm-body">
        <div className="cm-meta"><b>{c.name || 'Someone'}</b> <span className="cm-when">{when}</span></div>
        <div className="cm-text">{c.text}</div>
        <div className="cm-acts">
          <button className={'cm-like' + (c.liked ? ' on' : '')} onClick={onLike}>{MI.heart({ width: 13, height: 13 })}{c.likes ? ' ' + c.likes : ''}</button>
          {onReply && <button className="cm-replybtn" onClick={onReply}>Reply</button>}
        </div>
      </div>
    </div>
  );
}

/* moment / shout card.
   props:
     user     – profile owner (for avatar + author identity)
     moment   – { id, cap, img, imgKind, ts, editedTs, taps, comments[] }
     owner    – true ⇒ the logged-in owner is viewing their own moment (edit/delete)
     viewer   – the account interacting (null on public ⇒ auth gate)
     onEdit, onDelete, onComment – persistence callbacks (owner moments)
     toast
*/
function MomentCard({ user, moment, owner, viewer, onEdit, onDelete, onComments, autoOpen, toast, bfDelay }) {
  const [menu, setMenu] = moUse(false);
  const [editing, setEditing] = moUse(false);
  const [draft, setDraft] = moUse(moment.cap || '');
  const [open, setOpen] = moUse(false);            // comments expanded
  React.useEffect(() => { if (autoOpen) setOpen(true); }, [autoOpen]);
  const [ctext, setCtext] = moUse('');
  const [gate, setGate] = moUse(null);             // null | 'comment' | 'like'
  const [liked, setLiked] = moUse(false);
  const [localC, setLocalC] = moUse(moment.comments || []);   // ephemeral comments (community posts)
  const [replyTo, setReplyTo] = moUse(null);
  const [replyText, setReplyText] = moUse('');

  const persist = !!onComments;
  const comments = persist ? (moment.comments || []) : localC;
  const commit = (arr) => { if (persist) onComments(arr); else setLocalC(arr); };
  const hasImg = moment.img && String(moment.img).indexOf('idb:') !== 0;
  const when = window.momentWhen ? window.momentWhen(moment.ts) : (moment.when || 'now');
  const edited = moment.editedTs ? ' · edited' : '';
  const likeN = (moment.taps || 0) + (liked ? 1 : 0);
  const commentCount = comments.reduce((n, c) => n + 1 + ((c.replies || []).length), 0);

  const newC = (text) => ({ id: 'c' + Date.now() + Math.random().toString(36).slice(2, 5), name: (viewer && viewer.name) || 'You', handle: (viewer && viewer.handle) || 'you', avatar: viewer && viewer.avatar, avatarColor: viewer && viewer.avatarColor, cover: viewer && viewer.cover, coverKind: viewer && viewer.coverKind, text: text, ts: Date.now(), likes: 0, liked: false, replies: [] });

  const saveEdit = () => {
    if (!draft.trim()) { toast && toast("Moment can't be empty"); return; }
    onEdit && onEdit({ cap: draft.trim(), editedTs: Date.now() });
    setEditing(false); setMenu(false); toast && toast('Moment updated');
  };
  const del = () => { setMenu(false); onDelete && onDelete(); toast && toast('Moment deleted'); };
  const toggleLike = () => { if (!viewer) { setGate('like'); return; } setLiked((v) => !v); };
  const addComment = () => {
    if (!ctext.trim()) return;
    if (!viewer) { setGate('comment'); return; }
    commit([...comments, newC(ctext.trim())]);
    setCtext(''); if (!open) setOpen(true);
  };
  const likeComment = (id) => {
    if (!viewer) { setGate('like'); return; }
    commit(comments.map((c) => c.id === id ? { ...c, liked: !c.liked, likes: (c.likes || 0) + (c.liked ? -1 : 1) } : c));
  };
  const startReply = (id, name) => {
    if (!viewer) { setGate('comment'); return; }
    setReplyTo(replyTo === id ? null : id); setReplyText('');
  };
  const submitReply = (parentId) => {
    if (!replyText.trim()) return;
    if (!viewer) { setGate('comment'); return; }
    commit(comments.map((c) => c.id === parentId ? { ...c, replies: [...(c.replies || []), newC(replyText.trim())] } : c));
    setReplyText(''); setReplyTo(null);
  };
  const likeReply = (parentId, rid) => {
    if (!viewer) { setGate('like'); return; }
    commit(comments.map((c) => c.id === parentId ? { ...c, replies: (c.replies || []).map((r) => r.id === rid ? { ...r, liked: !r.liked, likes: (r.likes || 0) + (r.liked ? -1 : 1) } : r) } : c));
  };

  return (
    <div className={'feed-card' + (bfDelay != null ? ' mc-enter' : '')} data-moment-id={moment.id} style={bfDelay != null ? { '--bf-delay': bfDelay + 's' } : undefined}>
      <div className="feed-head">
        <Avatar user={user} size={40} coverFallback />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div className="feed-name">{user.name || 'You'}{user.pro && <VerifiedSeal size={15} />}</div>
          <div className="feed-handle">@{user.handle || 'you'} · {when}{edited}</div>
        </div>
        {owner && (
          <div className="feed-menu-wrap">
            <button className="icon-btn" style={{ width: 32, height: 32 }} onClick={() => setMenu((v) => !v)} aria-label="More">{MI.dots ? MI.dots({ width: 18, height: 18 }) : '⋯'}</button>
            {menu && (
              <React.Fragment>
                <div className="feed-menu-veil" onClick={() => setMenu(false)} />
                <div className="feed-menu">
                  <button onClick={() => { setEditing(true); setMenu(false); setDraft(moment.cap || ''); }}>{MI.edit({ width: 15, height: 15 })} Edit</button>
                  <button className="fm-del" onClick={del}>{MI.trash ? MI.trash({ width: 15, height: 15 }) : '🗑'} Delete</button>
                </div>
              </React.Fragment>
            )}
          </div>
        )}
      </div>

      {editing ? (
        <div className="feed-edit">
          <textarea className="feed-edit-input" value={draft} rows={3} maxLength={400} onChange={(e) => setDraft(e.target.value)} />
          <div className="feed-edit-actions">
            <button className="fe-cancel" onClick={() => { setEditing(false); setDraft(moment.cap || ''); }}>Cancel</button>
            <button className="fe-save" onClick={saveEdit}>Save</button>
          </div>
        </div>
      ) : (moment.cap && <div className="feed-cap">{moment.cap}</div>)}

      {hasImg && (moment.imgKind === 'video'
        ? <video ref={window.playMuted} className="feed-media" src={moment.img} muted autoPlay loop playsInline />
        : <img className="feed-media" src={moment.img} alt="" />)}

      <div className="feed-actions">
        <button className={'fa-btn' + (liked ? ' liked' : '')} onClick={toggleLike}>{MI.heart({ width: 17, height: 17 })} {likeN}</button>
        <button className="fa-btn" onClick={() => setOpen((v) => !v)}>{MI.comment ? MI.comment({ width: 16, height: 16 }) : MI.message({ width: 16, height: 16 })} {commentCount}</button>
        <button className="fa-btn" onClick={() => { if (navigator.clipboard) { navigator.clipboard.writeText(location.href).catch(() => {}); } toast && toast('Link copied'); }}>{MI.link({ width: 15, height: 15 })} Share</button>
      </div>

      {open && (
        <div className="cm-wrap">
          {comments.length === 0 && <div className="cm-empty">Be the first to comment.</div>}
          {comments.map((c) => (
            <div className="cm-thread" key={c.id}>
              <CommentRow c={c} onLike={() => likeComment(c.id)} onReply={() => startReply(c.id, c.name)} />
              {(c.replies || []).length > 0 && (
                <div className="cm-replies">
                  {c.replies.map((r) => <CommentRow key={r.id} c={r} small onLike={() => likeReply(c.id, r.id)} />)}
                </div>
              )}
              {replyTo === c.id && (
                <div className="cm-compose cm-reply-compose">
                  <span className="cm-av cm-av-me">{viewer ? <Avatar user={viewer} size={30} coverFallback /> : <span className="cm-av-anon">?</span>}</span>
                  <input className="cm-input" autoFocus value={replyText} placeholder={'Reply to ' + (c.name || '') + '…'} onChange={(e) => setReplyText(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') submitReply(c.id); }} />
                  <button className={'cm-send' + (replyText.trim() ? ' ready' : '')} onClick={() => submitReply(c.id)} aria-label="Send reply">{MI.arrow ? MI.arrow({ width: 16, height: 16 }) : '→'}</button>
                </div>
              )}
            </div>
          ))}
          <div className="cm-compose">
            <span className="cm-av cm-av-me">{viewer ? <Avatar user={viewer} size={30} coverFallback /> : <span className="cm-av-anon">{MI.users ? MI.users({ width: 14, height: 14 }) : '?'}</span>}</span>
            <input className="cm-input" value={ctext} placeholder={viewer ? 'Add a comment…' : 'Sign in to comment…'} onChange={(e) => setCtext(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') addComment(); }} onFocus={() => { if (!viewer) { setGate('comment'); document.activeElement.blur(); } }} />
            <button className={'cm-send' + (ctext.trim() ? ' ready' : '')} onClick={addComment} aria-label="Send">{MI.arrow ? MI.arrow({ width: 16, height: 16 }) : '→'}</button>
          </div>
        </div>
      )}

      {gate && <AuthGateModal action={gate === 'like' ? 'like this' : 'comment'} onClose={() => setGate(null)} />}
    </div>
  );
}

window.AuthGateModal = AuthGateModal;
window.MomentCard = MomentCard;

/* =========================================================
   NOTIFICATIONS — bell panel on Moments.
   Builds a live feed from the user's own moment activity
   (likes, comments, replies) + seeded social events, sorts
   by time, tracks unread via localStorage.
   ========================================================= */
const NOTIF_SEEN_KEY = 'tappt_notifs_seen';
const NOTIF_DISMISS_KEY = 'tappt_notifs_dismissed';
function notifSeenTs() { try { return parseInt(localStorage.getItem(NOTIF_SEEN_KEY) || '0', 10) || 0; } catch (e) { return 0; } }
function markNotifsSeen() { try { localStorage.setItem(NOTIF_SEEN_KEY, String(Date.now())); } catch (e) {} }
function notifDismissed() { try { return JSON.parse(localStorage.getItem(NOTIF_DISMISS_KEY) || '{}') || {}; } catch (e) { return {}; } }
function saveNotifDismissed(m) { try { localStorage.setItem(NOTIF_DISMISS_KEY, JSON.stringify(m)); } catch (e) {} }

/* seeded social actors (people who engage with your Moments) */
const NOTIF_PEOPLE = [
  { name: 'Sofia Marchetti', handle: 'sofiaa', color: 'linear-gradient(135deg,#f58529,#dd2a7b)' },
  { name: 'Daniel Osei', handle: 'd.osei', color: 'linear-gradient(135deg,#5CC8FF,#1f6a8a)' },
  { name: 'Mia Chen', handle: 'miacreates', color: 'linear-gradient(135deg,#2BB8C4,#176b6b)' },
  { name: 'Jayden Brooks', handle: 'jaydn', color: 'linear-gradient(135deg,#8AFF6B,#1a7a3a)' },
  { name: 'Amara Okafor', handle: 'amara.o', color: 'linear-gradient(135deg,#FF6BC8,#a82e7a)' },
  { name: 'Leo Fournier', handle: 'leo.f', color: 'linear-gradient(135deg,#FFD66B,#c8920a)' },
  { name: 'Priya Nair', handle: 'priya', color: 'linear-gradient(135deg,#6BFFE0,#0a8a78)' },
];

/* seeded ambient activity beyond Moments — taps, follows, tips, saves, milestones.
   Demo-flavoured but reads like a live creator feed. Minutes-ago offsets. */
const NOTIF_EVENTS = [
  { type: 'follow', p: 1, mins: 3, text: 'started following you' },
  { type: 'tap', p: 2, mins: 11, text: 'tapped your Joker card' },
  { type: 'tip', p: 0, mins: 24, text: 'sent you a £5 tip 🎉' },
  { type: 'save', p: 3, mins: 47, text: 'saved your contact' },
  { type: 'follow', p: 4, mins: 96, text: 'started following you' },
  { type: 'tap', p: 5, mins: 140, text: 'tapped your profile in York' },
  { type: 'tip', p: 6, mins: 320, text: 'sent you a £3 tip' },
  { type: 'milestone', p: 1, mins: 600, text: 'Your profile passed 10K taps this month 🚀', solo: true },
];

/* Moments-only notifications: likes (grouped per moment, IG-style), comments and replies. */
function buildNotifs(user) {
  const out = [];
  const now = Date.now();
  const isDemo = user.handle === 'maxxharland';
  (user.moments || []).forEach((m, mi) => {
    // comments + replies = real engagement (shown individually, like IG)
    (m.comments || []).forEach((c, ci) => {
      out.push({ id: 'cn' + m.id + c.id, type: 'comment', who: c.name, handle: c.handle, color: c.avatarColor, avatar: c.avatar, cover: c.cover, coverKind: c.coverKind, ts: c.ts || (now - (ci + 1) * 1800000), text: 'commented: “' + (c.text || '').slice(0, 40) + '”', momentId: m.id, commentId: c.id });
      (c.replies || []).forEach((r) => {
        out.push({ id: 'rn' + r.id, type: 'reply', who: r.name, handle: r.handle, color: r.avatarColor, avatar: r.avatar, cover: r.cover, coverKind: r.coverKind, ts: r.ts || now, text: 'replied to your comment', momentId: m.id, commentId: c.id });
      });
    });
    // likes — ONE grouped row per moment ("Sofia and 434 others liked your Moment")
    const likeTotal = m.taps || 0;
    if (likeTotal > 0) {
      const face = NOTIF_PEOPLE[mi % NOTIF_PEOPLE.length];
      const others = likeTotal - 1;
      const txt = others > 0
        ? 'and ' + others.toLocaleString() + (others === 1 ? ' other liked your Moment' : ' others liked your Moment')
        : 'liked your Moment';
      out.push({ id: 'ln' + m.id, type: 'like', who: face.name, handle: face.handle, color: face.color, ts: m.likedTs || m.ts || (now - mi * 120000), text: txt, momentId: m.id });
    }
  });
  // ambient seeded activity (follows / taps / tips / saves / milestones) — DEMO ONLY.
  // Real accounts only see notifications from genuine engagement on their own moments.
  if (isDemo) NOTIF_EVENTS.forEach((e, i) => {
    const who = NOTIF_PEOPLE[e.p % NOTIF_PEOPLE.length];
    out.push({
      id: 'ev' + i, type: e.type,
      who: e.solo ? 'Tappt' : who.name, handle: who.handle,
      color: e.solo ? 'linear-gradient(135deg,var(--brand),var(--brand-2))' : who.color,
      ts: now - e.mins * 60000, text: e.text, solo: e.solo,
    });
  });
  out.sort((a, b) => b.ts - a.ts);
  return out;
}

function NotifIcon({ type }) {
  // type-coloured badge sitting on the avatar
  if (type === 'like') return <span className="nt-badge"><span className="nt-heart">{MI.heart({ width: 12, height: 12 })}</span></span>;
  if (type === 'tip') return <span className="nt-badge nt-badge-tip">{MI.dollar ? MI.dollar({ width: 12, height: 12 }) : '£'}</span>;
  if (type === 'follow') return <span className="nt-badge nt-badge-follow">{MI.userPlus ? MI.userPlus({ width: 12, height: 12 }) : (MI.user ? MI.user({ width: 12, height: 12 }) : '+')}</span>;
  if (type === 'tap') return <span className="nt-badge nt-badge-tap">{MI.spark ? MI.spark({ width: 12, height: 12 }) : '⚡'}</span>;
  if (type === 'save') return <span className="nt-badge">{MI.check ? MI.check({ width: 12, height: 12 }) : '✓'}</span>;
  if (type === 'milestone') return <span className="nt-badge nt-badge-tap">{MI.spark ? MI.spark({ width: 12, height: 12 }) : '✦'}</span>;
  return <span className="nt-badge">{MI.comment ? MI.comment({ width: 12, height: 12 }) : MI.message({ width: 12, height: 12 })}</span>;
}

function NotificationsSheet({ user, onClose, onOpenMoment, toast }) {
  const seenAt = React.useRef(notifSeenTs()).current;   // snapshot BEFORE marking seen
  const all = React.useMemo(() => buildNotifs(user), [user]);
  const [dismissed, setDismissed] = React.useState(notifDismissed);
  const [justOpened, setJustOpened] = React.useState(true);
  React.useEffect(() => { markNotifsSeen(); const t = setTimeout(() => setJustOpened(false), 2300); return () => clearTimeout(t); }, []);
  const dismiss = (id, e) => { if (e) { e.stopPropagation(); e.preventDefault(); } setDismissed((d) => { const n = { ...d, [id]: 1 }; saveNotifDismissed(n); return n; }); };
  const notifs = all.filter((n) => !dismissed[n.id]);
  const when = (ts) => window.momentWhen ? window.momentWhen(ts) : 'now';
  return (
    <div className="sheet-bg" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className={'sheet notif-sheet' + (justOpened ? ' nt-justopened' : '')}>
        <div className="sheet-head">
          <h3>Notifications</h3>
          <button className="icon-btn" onClick={onClose} aria-label="Close">{MI.close ? MI.close({ width: 18, height: 18 }) : '✕'}</button>
        </div>
        <div className="sheet-scroll">
          {notifs.length === 0 && <div className="sec-empty" style={{ border: 'none' }}><span className="se-ic">{MI.spark({ width: 26, height: 26 })}</span><div className="se-t">You're all caught up</div><div className="se-s">Likes, comments, taps and tips on your profile show up here.</div></div>}
          {notifs.map((n) => {
            const unread = n.ts > seenAt;
            const tappable = !!n.momentId;
            return (
              <button className={'nt-row' + (unread ? ' unread' : '') + (n.solo ? ' nt-solo' : '')} key={n.id} disabled={!tappable} onClick={() => { if (!tappable) return; onClose(); if (onOpenMoment) onOpenMoment(n.momentId, n.type === 'comment' || n.type === 'reply'); }}>
                <span className="nt-av-wrap">
                  <span className="nt-av"><Avatar user={{ name: n.who, avatarColor: n.color, avatar: n.avatar, cover: n.cover, coverKind: n.coverKind }} size={44} coverFallback /></span>
                  <NotifIcon type={n.type} />
                </span>
                <span className="nt-body">
                  <span className="nt-text"><b>{n.who}</b> {n.text}</span>
                  <span className="nt-when">{when(n.ts)}</span>
                </span>
                {unread && <span className="nt-dot" />}
                <span className="nt-dismiss" role="button" tabIndex={0} aria-label="Dismiss" onClick={(e) => dismiss(n.id, e)}>{MI.close ? MI.close({ width: 13, height: 13 }) : '✕'}</span>
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

/* count of notifs newer than last-seen — for the bell badge */
function unreadNotifCount(user) {
  const seen = notifSeenTs();
  const dis = notifDismissed();
  return buildNotifs(user).filter((n) => n.ts > seen && !dis[n.id]).length;
}

window.NotificationsSheet = NotificationsSheet;
window.unreadNotifCount = unreadNotifCount;
