// FOOTPASS Messenger v2 · app shell: tab bar, accueil, liste des messages, menu latéral, agenda, appels
// V2 simple : pas de rooms ni mur d'activité. Entre l'onboarding et la conversation.
const { useState: useStateH, useEffect: useEffectH } = React;

// ── i18n local ──
const HM_T = {
  fr: {
    home: 'Accueil', messages: 'Messages', agenda: 'Agenda', calls: 'Appels', menu: 'Menu',
    hello: 'Bonjour, Alexandre', sub: 'Votre réseau vérifié vous attend.',
    todo: 'À traiter', recents: 'Conversations récentes', seeAll: 'Tout voir',
    search: 'Rechercher un membre, un club…',
    notProto: "Cette partie n'est pas couverte par ce prototype.",
    verified: 'Pass ID vérifié', online: 'en ligne',
    todayAgenda: 'Demain', thisWeek: 'Cette semaine',
  },
  en: {
    home: 'Home', messages: 'Messages', agenda: 'Agenda', calls: 'Calls', menu: 'Menu',
    hello: 'Hello, Alexandre', sub: 'Your verified network awaits.',
    todo: 'To handle', recents: 'Recent conversations', seeAll: 'See all',
    search: 'Search a member, a club…',
    notProto: 'This part is not covered by this prototype.',
    verified: 'Pass ID verified', online: 'online',
    todayAgenda: 'Tomorrow', thisWeek: 'This week',
  },
};
const hmT = (lang, k) => (HM_T[lang] || HM_T.fr)[k] || k;

// ── Icônes propres au shell (formes simples, trait 1.5) ──
const HMI = {
  Home: ({ s = 22, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none">
      <path d="M4 10.2L12 3.8l8 6.4V20a1 1 0 01-1 1h-4.6v-6.2h-4.8V21H5a1 1 0 01-1-1v-9.8z" stroke={c} strokeWidth="1.7" strokeLinejoin="round"></path>
    </svg>
  ),
  Calendar: ({ s = 22, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none">
      <rect x="3.5" y="5" width="17" height="15.5" rx="3" stroke={c} strokeWidth="1.7"></rect>
      <path d="M3.5 9.8h17M8 3v3.4M16 3v3.4" stroke={c} strokeWidth="1.7" strokeLinecap="round"></path>
    </svg>
  ),
  Phone: ({ s = 22, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none">
      <path d="M6.8 3.8L9 6.1a1.6 1.6 0 01.1 2.1l-1 1.3a13.5 13.5 0 006.4 6.4l1.3-1a1.6 1.6 0 012.1.1l2.3 2.2a1.6 1.6 0 010 2.3l-1.2 1.2c-.9.9-2.2 1.2-3.4.8C9.9 19.6 4.4 14.1 2.5 8.4c-.4-1.2-.1-2.5.8-3.4l1.2-1.2a1.6 1.6 0 012.3 0z" stroke={c} strokeWidth="1.6" strokeLinejoin="round"></path>
    </svg>
  ),
  Bubble: ({ s = 22, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none">
      <path d="M12 3.8c4.9 0 8.7 3.3 8.7 7.7S16.9 19.2 12 19.2c-.9 0-1.8-.1-2.6-.3l-4.2 1.9.9-3.6c-1.7-1.4-2.8-3.4-2.8-5.7 0-4.4 3.8-7.7 8.7-7.7z" stroke={c} strokeWidth="1.7" strokeLinejoin="round"></path>
    </svg>
  ),
  Menu: ({ s = 22, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none">
      <path d="M4 6.5h16M4 12h16M4 17.5h10" stroke={c} strokeWidth="1.8" strokeLinecap="round"></path>
    </svg>
  ),
  Search: ({ s = 16, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 16 16" fill="none">
      <circle cx="7" cy="7" r="4.6" stroke={c} strokeWidth="1.5"></circle>
      <path d="M10.6 10.6L14 14" stroke={c} strokeWidth="1.5" strokeLinecap="round"></path>
    </svg>
  ),
  Chevron: ({ s = 14, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 14 14" fill="none">
      <path d="M5 2.8L9.4 7 5 11.2" stroke={c} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"></path>
    </svg>
  ),
  Bell: ({ s = 20, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 20 20" fill="none">
      <path d="M10 2.6a5 5 0 00-5 5v2.6l-1.4 2.9a.7.7 0 00.6 1h11.6a.7.7 0 00.6-1L15 10.2V7.6a5 5 0 00-5-5zM8.2 16.2a1.9 1.9 0 003.6 0" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
    </svg>
  ),
  Vault: ({ s = 18, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 18 18" fill="none">
      <rect x="2.2" y="2.8" width="13.6" height="11" rx="2.2" stroke={c} strokeWidth="1.5"></rect>
      <circle cx="9" cy="8.3" r="2.6" stroke={c} strokeWidth="1.4"></circle>
      <path d="M9 6.6v1.7l1.2 1.2M5 16.2v-1.4M13 16.2v-1.4" stroke={c} strokeWidth="1.4" strokeLinecap="round"></path>
    </svg>
  ),
  Mandate: ({ s = 18, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 18 18" fill="none">
      <path d="M5.4 2.5h5.8L14.6 6v9.5a1 1 0 01-1 1H5.4a1 1 0 01-1-1V3.5a1 1 0 011-1z" stroke={c} strokeWidth="1.5" strokeLinejoin="round"></path>
      <path d="M6.8 9.4h4.4M6.8 12h3" stroke={c} strokeWidth="1.4" strokeLinecap="round"></path>
      <path d="M10.9 2.7V6h3.4" stroke={c} strokeWidth="1.4" strokeLinejoin="round"></path>
    </svg>
  ),
  Gear: ({ s = 18, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="2.4" stroke={c} strokeWidth="1.5"></circle>
      <path d="M9 1.8l.9 2 2.1-.6 1 1.7 2.1.5-.3 2.2 1.7 1.4-1.7 1.4.3 2.2-2.1.5-1 1.7-2.1-.6-.9 2-.9-2-2.1.6-1-1.7-2.1-.5.3-2.2L1.5 9l1.7-1.4-.3-2.2 2.1-.5 1-1.7 2.1.6.9-2z" stroke={c} strokeWidth="1.2" strokeLinejoin="round"></path>
    </svg>
  ),
  Help: ({ s = 18, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="7" stroke={c} strokeWidth="1.5"></circle>
      <path d="M7.2 7a1.9 1.9 0 113 1.5c-.7.5-1.2.9-1.2 1.8" stroke={c} strokeWidth="1.4" strokeLinecap="round"></path>
      <circle cx="9" cy="12.8" r="0.9" fill={c}></circle>
    </svg>
  ),
  Card: ({ s = 18, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 18 18" fill="none">
      <rect x="1.8" y="3.6" width="14.4" height="10.8" rx="2" stroke={c} strokeWidth="1.5"></rect>
      <rect x="3.8" y="6" width="3.4" height="4.2" rx="0.8" stroke={c} strokeWidth="1.2"></rect>
      <path d="M9.4 6.6h4.6M9.4 9h3.2M3.8 12.2h6" stroke={c} strokeWidth="1.2" strokeLinecap="round"></path>
    </svg>
  ),
  Alert: ({ s = 15, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 15 15" fill="none">
      <path d="M7.5 1.8L14 13H1L7.5 1.8z" stroke={c} strokeWidth="1.4" strokeLinejoin="round"></path>
      <path d="M7.5 6v3.2" stroke={c} strokeWidth="1.4" strokeLinecap="round"></path>
      <circle cx="7.5" cy="11" r="0.8" fill={c}></circle>
    </svg>
  ),
  Pen: ({ s = 15, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 15 15" fill="none">
      <path d="M2.2 12.8l.7-2.9 7.2-7.2a1.4 1.4 0 012 0l.2.2a1.4 1.4 0 010 2l-7.2 7.2-2.9.7z" stroke={c} strokeWidth="1.3" strokeLinejoin="round"></path>
    </svg>
  ),
  VideoCam: ({ s = 16, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 16 16" fill="none">
      <rect x="1.6" y="4" width="9" height="8" rx="2" stroke={c} strokeWidth="1.4"></rect>
      <path d="M10.6 7l3.8-2.2v6.4L10.6 9" stroke={c} strokeWidth="1.4" strokeLinejoin="round"></path>
    </svg>
  ),
  ArrowUR: ({ s = 13, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 13 13" fill="none">
      <path d="M3.5 9.5l6-6M5 3.2h4.8V8" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
    </svg>
  ),
  ArrowDL: ({ s = 13, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 13 13" fill="none">
      <path d="M9.5 3.5l-6 6M8 9.8H3.2V5" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
    </svg>
  ),
  Logout: ({ s = 18, c = 'currentColor' }) => (
    <svg width={s} height={s} viewBox="0 0 18 18" fill="none">
      <path d="M7 2.5H4a1.5 1.5 0 00-1.5 1.5v10A1.5 1.5 0 004 15.5h3M12 12.2L15.2 9 12 5.8M15 9H7.2" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
    </svg>
  ),
};

// ── Données des conversations : méta mutable dans v2/convos.js (FP_CONVOS), identités dans FP_PEERS ──
const hmConvos = () => window.FP_CONVOS.map((m) => ({ ...FP_PEERS[m.id], ...m }));
const hmBadge = () => (window.m4GlobalUnread ? window.m4GlobalUnread() : window.FP_CONVOS.filter((c) => c.unread).length);
const hmBadgeLabel = (n) => (n > 99 ? '99+' : n);

function HMAvatar({ c, size = 46 }) {
  if (c.photo) return <FPAvatar size={size} initials={c.initials} src={c.photo} />;
  return <span className="hm-avatar" style={{ width: size, height: size, fontSize: Math.round(size * 0.34) }}>{c.initials}</span>;
}

// ── Tab bar ──
function FPTabBar({ active, onTab, lang }) {
  const t = (k) => hmT(lang, k);
  const badge = hmBadge();
  // Présences à confirmer → badge ambre sur l'onglet Agenda
  const abadge = (window.FP_EVENTS || []).filter((e) => e.status === 'pending').length;
  const tabs = [
    { id: 'agenda', label: t('agenda'), icon: HMI.Calendar, badge: abadge, amber: true },
    { id: 'calls', label: t('calls'), icon: HMI.Phone },
    { id: 'home', label: t('home'), icon: HMI.Home },
    { id: 'messages', label: t('messages'), icon: HMI.Bubble, badge },
    { id: 'menu', label: t('menu'), icon: HMI.Menu },
  ];
  return (
    <div className="hm-tabbar">
      {tabs.map((tb) => (
        <button key={tb.id} className={`hm-tab ${active === tb.id ? 'on' : ''}`} onClick={() => onTab(tb.id)}>
          <span className="hm-tab-ic">
            <tb.icon s={22} />
            {tb.badge ? <span className={`hm-tab-badge ${tb.amber ? 'amber' : ''}`}>{hmBadgeLabel(tb.badge)}</span> : null}
          </span>
          <span className="hm-tab-lbl">{tb.label}</span>
        </button>
      ))}
    </div>
  );
}

// ── Toast partagé ──
function useHmToast() {
  const [toast, setToast] = useStateH(null);
  const show = (msg) => { setToast(msg); setTimeout(() => setToast(null), 2200); };
  return [toast, show];
}

// ── ACCUEIL ──
function HMHome({ lang, onOpenChat, onTab, onOpenSub, hasUnreadNotifs }) {
  const t = (k) => hmT(lang, k);
  const recents = hmConvos().slice(0, 3);
  return (
    <div className="hm-page" data-screen-label="Accueil">
      <div className="hm-apphead">
        <img className="hm-logo" src="assets/logotype_white.png" alt="FOOTPASS®" />
        <div className="hm-apphead-actions">
          <button className="hm-iconbtn" onClick={() => onOpenSub('notifs')} aria-label="Notifications">
            <HMI.Bell />
            {hasUnreadNotifs ? <span className="hm-dot"></span> : null}
          </button>
          <button className="hm-avatarbtn" onClick={() => onTab('menu')} aria-label="Profil"><img src={FP_ME.photo} alt="AD" /></button>
        </div>
      </div>

      <div className="hm-scroll">
        <h1 className="hm-h1">{t('hello')}</h1>

        {/* Pass ID : statut compact, or · tap = carte complète + QR */}
        <button className="hm-pass" onClick={() => onOpenSub('passid')}>
          <span className="hm-pass-ic"><HMI.Card s={20} /></span>
          <span className="hm-pass-txt">
            <b>PASS ID · VERIFIED</b>
            <em>2480 1196 0049 · Agent</em>
          </span>
          <span className="hm-pass-chev"><HMI.Chevron /></span>
        </button>

        {/* À traiter */}
        <div className="hm-sechead"><span>{t('todo')}</span></div>
        <div className="hm-cardlist">
          <button className="hm-row" onClick={() => onOpenChat('amadou')}>
            <span className="hm-row-ic amber"><HMI.Pen s={15} /></span>
            <span className="hm-row-txt">
              <b>Autorisation · Co-représentation</b>
              <em>Prête pour signature · Amadou Mbaye</em>
            </span>
            <HMI.Chevron c="#A1A1AA" />
          </button>
          <button className="hm-row" onClick={() => onTab('agenda')}>
            <span className="hm-row-ic green"><HMI.Calendar s={16} /></span>
            <span className="hm-row-txt">
              <b>Real Madrid · Valdebebas</b>
              <em>Demain, 15:00 · présence confirmée</em>
            </span>
            <HMI.Chevron c="#A1A1AA" />
          </button>
        </div>

        {/* Conversations récentes */}
        <div className="hm-sechead">
          <span>{t('recents')}</span>
          <button className="hm-seclink" onClick={() => onTab('messages')}>{t('seeAll')}</button>
        </div>
        <div className="hm-cardlist">
          {recents.map((c) => (
            <button key={c.id} className="hm-row" onClick={() => onOpenChat(c.id)}>
              <HMAvatar c={c} size={40} />
              <span className="hm-row-txt">
                <b>{window.fpUpperLast(c.name)}</b>
                <em>{c.preview}</em>
              </span>
              {c.unread ? <span className="hm-unread">{c.unread}</span> : <span className="hm-time">{c.time}</span>}
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── MESSAGES · liste type WhatsApp : Nom – Rôle – Structure, recherche réelle + filtres ──
const MSG_FILTERS_KEY = 'fp_v2_msgfilters';
const loadMsgFilters = () => {
  try { const v = JSON.parse(localStorage.getItem(MSG_FILTERS_KEY)); return Array.isArray(v) ? v : []; } catch (e) { return []; }
};
function HMMessages({ lang, onOpenChat, onSheet }) {
  const t = (k) => hmT(lang, k);
  const [q, setQ] = useStateH('');
  const [cat, setCatRaw] = useStateH('all');   // 'all' | 'role:<role>' | '<filterId>'
  const [sub, setSub] = useStateH(null);        // contact id (sous-filtre d'un rôle)
  const [custom, setCustom] = useStateH(loadMsgFilters);
  const [fsheet, setFsheet] = useStateH(null);  // null | { editing } | { editing: filter }
  const setCat = (k) => { setCatRaw(k); setSub(null); };
  useEffectH(() => {
    try { localStorage.setItem(MSG_FILTERS_KEY, JSON.stringify(custom)); } catch (e) { /* ignore */ }
  }, [custom]);

  const all = hmConvos();
  const norm = (s) => s.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
  const roleCats = msgRoleCats(all);
  const customWithBadge = custom.map((f) => ({
    ...f,
    _badge: all.filter((c) => f.members.includes(c.id)).reduce((n, c) => n + (c.unread || 0), 0),
  }));

  // Liste filtrée : d'abord le filtre actif, puis la recherche par-dessus
  let base = all;
  const activeRole = roleCats.find((c) => c.key === cat);
  if (activeRole) {
    base = all.filter((c) => c.role === activeRole.role);
    if (sub) base = base.filter((c) => c.id === sub);
  } else if (cat !== 'all') {
    const f = custom.find((x) => x.id === cat);
    if (f) base = all.filter((c) => f.members.includes(c.id));
  }
  const list = q.trim()
    ? base.filter((c) => norm(`${c.name} ${c.role} ${c.org}`).includes(norm(q.trim())))
    : base;

  const saveFilter = (f) => {
    setCustom((arr) => {
      const exists = arr.some((x) => x.id === f.id);
      return exists ? arr.map((x) => (x.id === f.id ? f : x)) : [...arr, f];
    });
    setCatRaw(f.id); setSub(null);
  };
  const deleteFilter = (id) => { setCustom((arr) => arr.filter((x) => x.id !== id)); if (cat === id) setCat('all'); };

  return (
    <div className="hm-page" data-screen-label="Messages · liste">
      <div className="hm-pagehead">
        <h1 className="hm-h1">{t('messages')}</h1>
        <button className="hm-iconbtn" onClick={() => onSheet({ kind: 'newmsg' })} aria-label="Nouveau message">
          <HMI.Pen s={16} />
        </button>
      </div>
      <div className="hm-search">
        <HMI.Search />
        <input value={q} onChange={(e) => setQ(e.target.value)} placeholder={t('search')} />
        {q ? (
          <button className="hm-search-clear" onClick={() => setQ('')} aria-label="Effacer">
            <svg width="13" height="13" viewBox="0 0 22 22" fill="none"><path d="M16 6L6 16M6 6l10 10" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round"></path></svg>
          </button>
        ) : null}
      </div>
      <MsgFilters
        roleCats={roleCats} custom={customWithBadge} cat={cat} sub={sub}
        onCat={setCat} onSub={setSub}
        onAdd={() => setFsheet({ editing: null })}
        onEdit={(f) => setFsheet({ editing: f })}
      />
      <div className="hm-scroll">
        <div className="hm-convos">
          {list.map((c) => (
            <button key={c.id} className="hm-convo" onClick={() => onOpenChat(c.id)}>
              <span className="hm-convo-av">
                <HMAvatar c={c} size={46} />
                {c.online ? <span className="hm-online"></span> : null}
              </span>
              <span className="hm-convo-main">
                <span className="hm-convo-top">
                  <b>{window.fpUpperLast(c.name)}</b>
                  <span className={`hm-convo-time ${c.unread ? 'acc' : ''}`}>{c.time}</span>
                </span>
                <span className="hm-convo-id">{c.role} – {c.org} <FPIcon.Shield s={9} /></span>
                <span className="hm-convo-prev">
                  <em>{c.preview}</em>
                  {c.unread ? <span className="hm-unread">{c.unread}</span> : null}
                </span>
              </span>
            </button>
          ))}
          {list.length === 0 ? (
            <div className="hm-empty">{q.trim() ? ('Aucun membre ne correspond à « ' + q + ' ».') : 'Aucune conversation dans ce filtre.'}</div>
          ) : null}
        </div>
        <div className="hm-listfoot"><FPIcon.Shield s={10} /> Chiffré de bout en bout · identités vérifiées PASS ID</div>
      </div>
      {fsheet ? (
        <MsgFilterSheet
          editing={fsheet.editing}
          allContacts={all}
          onClose={() => setFsheet(null)}
          onSave={saveFilter}
          onDelete={deleteFilter}
        />
      ) : null}
    </div>
  );
}

// ── MENU latéral (plein écran, simple) ──
function HMMenu({ lang, onOpenSub, onTab, onReplayOnboarding }) {
  const t = (k) => hmT(lang, k);
  const item = (Icon, label, sub, target, badge) => (
    <button className="hm-row" key={label} onClick={() => (typeof target === 'function' ? target() : onOpenSub(target))}>
      <span className="hm-row-ic"><Icon s={17} /></span>
      <span className="hm-row-txt"><b>{label}</b>{sub ? <em>{sub}</em> : null}</span>
      {badge ? <span className="hm-unread">{badge}</span> : null}
      <HMI.Chevron c="#A1A1AA" />
    </button>
  );
  return (
    <div className="hm-page" data-screen-label="Menu">
      <div className="hm-pagehead">
        <h1 className="hm-h1">{t('menu')}</h1>
        <button className="hm-iconbtn" onClick={() => onOpenSub('notifs')} aria-label="Notifications"><HMI.Bell s={16} /></button>
        <button className="hm-iconbtn" onClick={() => onOpenSub('settings')} aria-label="Réglages"><HMI.Gear s={16} /></button>
      </div>
      <div className="hm-scroll">
        {/* Profil + Pass */}
        <button className="hm-profile" onClick={() => onOpenSub('passid')}>
          <span className="hm-avatar big"><img src={FP_ME.photo} alt="AD" /></span>
          <span className="hm-row-txt">
            <b>Alexandre Da Costa</b>
            {(() => { const st = window.fpGetStructure ? fpGetStructure() : null; return (
              <em className="hm-verif"><FPIcon.Shield s={10} /> {FP_ME.role || 'Agent'}{st ? <span className="hm-orgname"> · {st.name}</span> : <span className="hm-nostr"> · {TX('Structure à ajouter')}</span>}</em>
            ); })()}
          </span>
          <HMI.Chevron c="#A1A1AA" />
        </button>

        <div className="hm-sechead"><span>Espace de travail</span></div>
        <div className="hm-cardlist">
          {item(HMI.Card, 'Mon Pass ID', 'Carte, QR et partage', 'passid')}
          {window.FPStructureMenuRow ? <FPStructureMenuRow /> : null}
          {item(HMI.Vault, 'Coffre-fort', 'Documents chiffrés', 'vault', ((window.CF_DOCS_INIT || []).concat(window.CF3_DOCS_EXTRA || []).filter((d) => d.state === 'sign' || d.state === 'review' || d.request).length) || null)}
          {item(HMI.Mandate, 'Autorisations', 'Représentation, délégations, accès', 'mandates', ((window.FP_MANDATES || []).filter((m) => m.status === 'pending').length) || null)}
          {item(HMI.Calendar, 'Agenda', 'Rendez-vous et échéances', () => onTab('agenda'), ((window.FP_EVENTS || []).filter((e) => e.status !== 'done').length) || null)}
        </div>

        <div className="hm-sechead"><span>Compte</span></div>
        <div className="hm-cardlist">
          {item(HMI.Bell, 'Notifications', null, 'notifs')}
          {item(HMI.Gear, 'Réglages', 'Sécurité, langue, confidentialité', 'settings')}
          {item(HMI.Help, 'Aide & support', null, 'help')}
          {window.StI ? item(window.StI.Info, 'À propos', 'Version, sécurité, mentions légales', 'about') : null}
        </div>

        <button className="hm-logout" onClick={onReplayOnboarding}>
          <HMI.Logout s={16} /> Se déconnecter
        </button>
        <div className="hm-version">FOOTPASS® V2.2</div>
      </div>
    </div>
  );
}

// ── AGENDA · événements vivants : détail, confirmation, création ──
function HMAgenda({ lang, events, onSheet }) {
  const t = (k) => hmT(lang, k);
  const section = (key, label) => {
    const list = events.filter((e) => e.sect === key);
    if (!list.length) return null;
    return (
      <div key={key}>
        <div className="hm-sechead"><span>{label}</span></div>
        <div className="hm-cardlist">
          {list.map((e) => (
            <button key={e.id} className="hm-event" onClick={() => onSheet({ kind: 'event', ev: e })}>
              <span className="hm-event-when"><b>{e.whenB}</b><em>{e.whenE}</em></span>
              <span className="hm-row-txt">
                <b>{e.title}</b>
                <em>{e.sub}{e.who ? ` · avec ${e.who}` : ''}</em>
              </span>
              <span className={`hm-event-tag ${e.status === 'ok' ? 'ok' : ''}`}>{e.status === 'ok' ? 'Confirmé' : 'À confirmer'}</span>
            </button>
          ))}
        </div>
      </div>
    );
  };
  return (
    <div className="hm-page" data-screen-label="Agenda">
      <div className="hm-pagehead">
        <h1 className="hm-h1">{t('agenda')}</h1>
        <button className="hm-iconbtn" onClick={() => onSheet({ kind: 'newevent' })} aria-label="Nouvel événement"><HMI.Pen s={16} /></button>
      </div>
      <div className="hm-scroll">
        {section('tomorrow', t('todayAgenda'))}
        {section('week', t('thisWeek'))}
      </div>
    </div>
  );
}

// ── APPELS (journal · chaque ligne rappelle vraiment) ──
function HMCalls({ lang, onSheet, onVoice, onVideo }) {
  const t = (k) => hmT(lang, k);
  const LOGS = [
    { id: 1, pid: 'lucas', meta: 'Appel vocal · 24:12', time: '12 mars', dir: 'out' },
    { id: 2, pid: 'karim', meta: 'Appel vidéo · 08:47', time: 'Hier', dir: 'in', video: true },
    { id: 3, pid: 'amadou', meta: 'Appel manqué', time: 'Hier', dir: 'missed' },
    { id: 4, pid: 'sira', meta: 'Appel vocal · 03:05', time: 'Lundi', dir: 'out' },
    { id: 5, pid: 'david', meta: 'Appel vidéo · 31:08', time: '28 mai', dir: 'out', video: true },
    { id: 6, pid: 'mathis', meta: 'Appel vocal · 06:51', time: '17 déc', dir: 'in' },
    { id: 7, pid: 'marco', meta: 'Appel vocal · 12:44', time: '14 févr', dir: 'in' },
  ];
  return (
    <div className="hm-page" data-screen-label="Appels">
      <div className="hm-pagehead">
        <h1 className="hm-h1">{t('calls')}</h1>
        <button className="hm-iconbtn" onClick={() => onSheet({ kind: 'newcall' })} aria-label="Nouvel appel"><HMI.Phone s={16} /></button>
      </div>
      <div className="hm-scroll">
        <div className="hm-cardlist">
          {LOGS.map((l) => {
            const p = FP_PEERS[l.pid];
            return (
              <div key={l.id} className="hm-row static">
                <HMAvatar c={p} size={40} />
                <span className="hm-row-txt">
                  <b className={l.dir === 'missed' ? 'missed' : ''}>{window.fpUpperLast(p.name)}</b>
                  <em>
                    <span className={`hm-calldir ${l.dir}`}>{l.dir === 'in' ? <HMI.ArrowDL /> : l.dir === 'missed' ? <HMI.ArrowDL /> : <HMI.ArrowUR />}</span>
                    {l.meta} · {l.time}
                  </em>
                </span>
                <button className="hm-iconbtn plain" aria-label={l.video ? 'Rappeler en vidéo' : 'Rappeler'}
                  onClick={() => (l.video ? onVideo(l.pid) : onVoice(l.pid))}>
                  {l.video ? <HMI.VideoCam s={18} /> : <HMI.Phone s={17} />}
                </button>
              </div>
            );
          })}
        </div>
        <div className="hm-listfoot"><FPIcon.Shield s={10} /> Appels chiffrés de bout en bout</div>
      </div>
    </div>
  );
}

// ── SHELL : page active + tab bar + sous-pages + feuilles ──
function FPShell({ dark, lang, tab, onTab, onOpenChat, onVoice, onVideo, onRoomCall, onReplayOnboarding, appearance }) {
  const [toast, showToast] = useHmToast();
  const [sub, setSub] = useStateH(null); // 'passid' | 'vault' | 'mandates' | 'settings' | 'notifs' | 'help'
  const [sheet, setSheet] = useStateH(null); // { kind: 'newmsg' | 'newcall' | 'event' | 'newevent', ev? }
  // Stores module (convos.js) : l'état survit aux démontages du shell
  const [notifs, setNotifsRaw] = useStateH(window.FP_NOTIFS);
  const setNotifs = (next) => { window.FP_NOTIFS = next; setNotifsRaw(next); };
  const [events, setEventsRaw] = useStateH(window.FP_EVENTS);
  const setEvents = (next) => { window.FP_EVENTS = next; setEventsRaw(next); };
  const openSub = (id) => {
    // Les notifications glissent en feuille au-dessus de l'écran courant · on ne quitte pas l'app ;
    // 'contacts' ouvre l'annuaire vérifié (même feuille que Nouveau message).
    if (id === 'notifs') { setSheet({ kind: 'notifs' }); return; }
    if (id === 'contacts') { setSheet({ kind: 'newmsg' }); return; }
    setSub(id);
  };
  const closeSub = () => setSub(null);

  // Couche d'états système (forcée via Tweaks) · s'applique à l'écran actif, sans le modifier
  const [sysState, setSysState] = useStateH('none');
  useEffectH(() => {
    const on = (e) => setSysState(((e && e.detail) || {}).state || 'none');
    const onNav = (e) => { const d = (e && e.detail) || {}; if (d.sub) setSub(d.sub); };
    window.addEventListener('fp:sys', on);
    window.addEventListener('fp:opensub', onNav);
    return () => { window.removeEventListener('fp:sys', on); window.removeEventListener('fp:opensub', onNav); };
  }, []);
  const clearSys = () => window.dispatchEvent(new CustomEvent('fp:sys', { detail: { state: 'none', source: 'clear' } }));
  const sysFlow = (k) => {
    if (k === 'newmsg' || k === 'newcall' || k === 'newevent') setSheet({ kind: k });
    else if (k === 'mandates-new') openSub('mandates-new');
  };

  // Audit R-11 · un invité certifié = notification + toast (la récompense réelle de la boucle virale)
  useEffectH(() => {
    const onGrowth = (e) => {
      const d = (e && e.detail) || {};
      // Ouverture d'un vrai flux depuis la checklist / les états vides (audit R-02, R-03)
      if (d.kind === 'sheet' && d.sheet) { setSheet({ kind: d.sheet, name: d.name, mode: d.mode }); return; }
      if (d.kind !== 'joined') return;
      const n = { id: 'nj' + Date.now(), kind: 'sec', title: 'Théo Lemaire a rejoint FOOTPASS', sub: 'Via votre lien d\u2019invitation · Pass ID vérifié', time: TX('À l\u2019instant'), read: false };
      window.FP_NOTIFS = [n, ...window.FP_NOTIFS];
      setNotifsRaw(window.FP_NOTIFS);
      showToast(TX('Théo Lemaire a rejoint votre réseau vérifié'));
    };
    window.addEventListener('fp:growth', onGrowth);
    return () => window.removeEventListener('fp:growth', onGrowth);
  }, []);

  const page = (() => {
    switch (tab) {
      case 'messages': { const MsgScreen = window.HMMessagesM4 || HMMessages; return <MsgScreen lang={lang} onOpenChat={onOpenChat} onSheet={setSheet} />; }
      case 'menu': return <HMMenu lang={lang} onOpenSub={openSub} onTab={onTab} onReplayOnboarding={onReplayOnboarding} />;
      case 'agenda': { const Ag = window.HMAgendaV2 || HMAgenda; return <Ag lang={lang} events={events} onSheet={setSheet} onOpenChat={onOpenChat} />; }
      case 'calls': { const Cl = window.HMCallsV2 || HMCalls; return <Cl lang={lang} onSheet={setSheet} onVoice={onVoice} onVideo={onVideo} onRoomCall={onRoomCall} onOpenChat={onOpenChat} onOpenSub={openSub} showToast={showToast} events={events} onAddEvent={(ev) => setEvents([...events, ev])} onRemoveEvent={(id) => setEvents(events.filter((e) => e.id !== id))} />; }
      default: {
        // Accueil : v3 (refonte) par défaut · l'ancien accueil reste comparable via le tweak « Version »
        const homeV = (() => { try { return localStorage.getItem('fp_home_v') || 'v3'; } catch (e) { return 'v3'; } })();
        const Home = (homeV === 'v2' ? window.HMHomeV2 : window.HMHomeV3) || window.HMHomeV2 || HMHome;
        return <Home lang={lang} onOpenChat={onOpenChat} onTab={onTab} onOpenSub={openSub} hasUnreadNotifs={notifs.some((n) => !n.read)} events={events} onOpenEvent={(ev) => setSheet({ kind: 'event', ev })}
          onConfirmEvent={(id) => { setEvents(events.map((e) => (e.id === id ? { ...e, status: 'ok' } : e))); showToast((window.TX || ((s) => s))('Présence confirmée')); }} />;
      }
    }
  })();

  const subEl = (() => {
    switch (sub) {
      case 'passid': return <PassIdPage onBack={closeSub} showToast={showToast} />;
      case 'vault': return <VaultPage onBack={closeSub} showToast={showToast} dark={dark} />;
      case 'mandates': return <MandatesPage onBack={closeSub} showToast={showToast} />;
      case 'mandates-new': return <MandatesPage onBack={closeSub} showToast={showToast} startCreate />;
      case 'stpanel': { const S = window.StructurePanelPage; return S ? <S onBack={closeSub} showToast={showToast} onOpenSub={openSub} /> : null; }
      case 'settings': return <SettingsPage onBack={closeSub} showToast={showToast} appearance={appearance} />;
      case 'help': return <HelpPage onBack={closeSub} showToast={showToast} />;
      case 'about': { const A = window.AboutPage; return A ? <A onBack={closeSub} showToast={showToast} dark={dark} onOpenStates={() => openSub('states')} /> : null; }
      case 'states': { const G = window.StatesGalleryPage; return G ? <G onBack={closeSub} /> : null; }
      case 'passi': return <PassiPage onBack={closeSub} showToast={showToast} onAddEvent={(ev) => setEvents([...events, ev])} onConfirmEvent={(id) => setEvents(events.map((e) => (e.id === id ? { ...e, status: 'ok' } : e)))} />;
      default: return null;
    }
  })();

  const sheetEl = (() => {
    if (!sheet) return null;
    const close = () => setSheet(null);
    switch (sheet.kind) {
      case 'newmsg': return <NewMessageSheet onClose={close} onPick={onOpenChat} showToast={showToast} />;
      case 'notifs': return <NotifsSheet onClose={close} notifs={notifs} setNotifs={setNotifs} onOpenChat={onOpenChat} showToast={showToast} />;
      case 'invite': return window.InviteSheet ? <InviteSheet onClose={close} name={sheet.name} /> : null;
      case 'sttunnel':
      case 'structure': {
        // Audit structure P0-1 · « créer » ouvre le tunnel plein écran ; la feuille garde rejoindre / gérer
        if ((sheet.kind === 'sttunnel' || sheet.mode === 'create') && window.StructureTunnel) return <StructureTunnel dark={dark} onClose={close} showToast={showToast} onOpenSub={openSub} />;
        return window.StructureSheet ? <StructureSheet onClose={close} mode={sheet.mode} showToast={showToast} onOpenSub={openSub} /> : null;
      }
      case 'newcall': return <NewCallSheet onClose={close} onVoice={onVoice} onVideo={onVideo} onOpenChat={onOpenChat} showToast={showToast} />;
      case 'newevent': { const NE = window.NewEventSheetV2 || NewEventSheet; return <NE onClose={close} showToast={showToast} initDay={sheet.day} initM={sheet.month} onAdd={(ev) => setEvents([...events, ev])} />; }
      case 'event': {
        const ES = window.EventSheetV2 || EventSheet;
        return (
          <ES ev={sheet.ev} onClose={close} showToast={showToast} onOpenChat={onOpenChat}
            onConfirm={(id) => setEvents(events.map((e) => (e.id === id ? { ...e, status: 'ok' } : e)))}
            onRemove={(id) => setEvents(events.filter((e) => e.id !== id))} />
        );
      }
      default: return null;
    }
  })();

  return (
    <div className={`hm ${dark ? 'dark' : 'light'}`}>
      <FPStatusBar light={dark} />
      {page}
      <FPTabBar active={tab} onTab={(id) => { closeSub(); onTab(id); }} lang={lang} />
      {subEl}
      {window.FPSysLayer ? <FPSysLayer context={sub || tab} state={sysState} onClear={clearSys} onFlow={sysFlow} showToast={showToast} /> : null}
      {sheetEl}
      {toast ? <div className="hm-toast">{toast}</div> : null}
    </div>
  );
}

Object.assign(window, { FPShell, FPTabBar, HMI });
