// FOOTPASS Messenger v2 · scene shell, screen routing, tweaks
const { useState: useStateM, useEffect: useEffectM } = React;

// Accent de marque · verrouillé sur le vert FOOTPASS. La démo n'expose aucune
// autre couleur : l'identité visuelle ne se change pas depuis le panneau.
const FP_ACCENT = { acc: '#00A37E', bright: '#00C49A' };

function dispatchFp(detail) {
  window.dispatchEvent(new CustomEvent('fp:event', { detail }));
}

function Scene() {
  // Le theme suit la bascule mobile/desktop : si l'autre page nous envoie une
  // consigne dans l'URL (?theme=dark), on demarre dessus. Sinon, clair.
  const urlTheme = window.fpThemeFromUrl ? window.fpThemeFromUrl() : null;
  const [tw, setTw] = useTweaks({
    dark: urlTheme === null ? false : urlTheme,
    lang: 'fr',
    state: 'default',
    sysState: 'none',
  });
  const dark = tw.dark;
  const lang = tw.lang;
  window.FP_LANG = lang;
  const accent = FP_ACCENT;

  // Sync du Tweak quand un état système est levé depuis l'écran (Réessayer, Déverrouiller…)
  useEffectM(() => {
    const on = (e) => { const d = (e && e.detail) || {}; if (d.source === 'clear') setTw('sysState', 'none'); };
    window.addEventListener('fp:sys', on);
    return () => window.removeEventListener('fp:sys', on);
  }, []);

  // screen: 'chat' | 'voice-out' | 'voice-active' | 'incoming' | 'incoming-video' | 'video'
  const [screen, setScreen] = useStateM('chat');

  // Conversation active (persistée) + interlocuteur de l'appel en cours
  const [activePid, setActivePidRaw] = useStateM(() => {
    try { const p = localStorage.getItem('fp_v2_convo'); if (p && FP_PEERS[p]) return p; } catch (e) { /* ignore */ }
    return 'lucas';
  });
  const setActivePid = (pid) => {
    setActivePidRaw(pid);
    try { localStorage.setItem('fp_v2_convo', pid); } catch (e) { /* ignore */ }
  };
  const activePeer = FP_PEERS[activePid] || FP_PEERS.lucas;
  const [callPid, setCallPid] = useStateM('lucas');
  const callPeer = FP_PEERS[callPid] || FP_PEERS.lucas;
  const [callRoom, setCallRoom] = useStateM(null);

  // phase: 'onboarding' (avant le messager) | 'app'
  const [phase, setPhaseRaw] = useStateM(() => {
    try { return localStorage.getItem('fp_v2_phase') || 'onboarding'; } catch (e) { return 'onboarding'; }
  });
  // view dans la phase app : accueil / messages / agenda / appels / menu / conversation
  const [view, setViewRaw] = useStateM(() => {
    try { return localStorage.getItem('fp_v2_view') || 'home'; } catch (e) { return 'home'; }
  });
  const setView = (v) => {
    setViewRaw(v);
    try { localStorage.setItem('fp_v2_view', v); } catch (e) { /* ignore */ }
  };
  const [obEntry, setObEntry] = useStateM('self');
  const [obKey, setObKey] = useStateM(0);
  // booting: splash de démarrage au-dessus de tout, se retire seul
  const [booting, setBooting] = useStateM(true);
  const [bootKey, setBootKey] = useStateM(0);
  const replaySplash = () => { try { localStorage.removeItem('fp_splash_seen'); } catch (e) { /* ignore */ } setBootKey((k) => k + 1); setBooting(true); };
  const setPhase = (p) => {
    setPhaseRaw(p);
    try { localStorage.setItem('fp_v2_phase', p); } catch (e) { /* ignore */ }
  };
  const startOnboarding = (entry) => {
    setObEntry(entry);
    try { localStorage.setItem('fp_onb_v2', JSON.stringify({ flow: entry, idx: 0 })); } catch (e) { /* ignore */ }
    setObKey((k) => k + 1);
    setPhase('onboarding');
  };

  // Fin de l'onboarding : le portail d'entrée est joué pendant la certification, on va direct à l'accueil
  const finishOnboarding = () => {
    // Audit R-02 · le compte vient de naître : la checklist « Bien démarrer » s'active
    try { localStorage.setItem('fp_growth_steps', JSON.stringify({ msg: false, invite: false, auth: false, off: false })); } catch (e) { /* ignore */ }
    window.dispatchEvent(new CustomEvent('fp:growth', { detail: { kind: 'checklist' } }));
    setView('home');
    setPhase('app');
  };

  // Navigation depuis les Tweaks (états système) · ouvre un onglet ou une sous-page
  const goScreen = (opts) => {
    setPhase('app');
    if (opts.view) setView(opts.view);
    if (opts.sub) { setView('menu'); setTimeout(() => window.dispatchEvent(new CustomEvent('fp:opensub', { detail: { sub: opts.sub } })), 0); }
  };

  // Composer overlay states forced by tweaks
  const forcedFocused = tw.state === 'default' ? undefined : (tw.state === 'keyboard' || tw.state === 'plus');
  const forcedMode = tw.state === 'default' ? undefined
    : tw.state === 'plus' ? 'plus'
    : tw.state === 'recording' ? 'recording'
    : tw.state === 'transcribe' ? 'transcribe'
    : null;

  const endCall = (kind, secs) => {
    setScreen('chat');
    if (secs === null || secs === undefined) {
      dispatchFp({ type: 'calllog', kind: 'missed', pid: callPid });
    } else {
      dispatchFp({ type: 'calllog', kind, dur: fmtDur(secs), pid: callPid });
    }
  };

  // Ouvrir une conversation : devient la conversation active, remet ses non-lus à zéro
  const openChat = (pid) => {
    if (pid && FP_PEERS[pid]) {
      setActivePid(pid);
      const m = window.FP_CONVOS.find((c) => c.id === pid);
      if (m) m.unread = 0;
      if (window.m4ReadConvo) window.m4ReadConvo(pid); // liste vivante : la pastille non-lu s'éteint
    }
    setView('chat');
  };

  // Ouverture DIRECTE d'une conversation depuis n'importe quelle feuille (page structure, mini-fiches…)
  // detail: { pid } pour un contact existant · { peer } pour créer le contact à la volée (roster d'une structure)
  useEffectM(() => {
    const f = (e) => {
      const d = (e && e.detail) || {};
      if (d.peer && d.peer.id && !FP_PEERS[d.peer.id]) {
        FP_PEERS[d.peer.id] = d.peer;
        window.FP_THREADS = window.FP_THREADS || {};
        window.FP_THREADS[d.peer.id] = window.FP_THREADS[d.peer.id] || [{ id: 1, kind: 'day', label: "AUJOURD'HUI" }];
      }
      const pid = d.pid || (d.peer && d.peer.id);
      if (pid && FP_PEERS[pid]) { setPhase('app'); openChat(pid); }
    };
    window.addEventListener('fp:openchat', f);
    return () => window.removeEventListener('fp:openchat', f);
  }, []);

  // Ajout aux contacts SANS ouvrir la conversation (fiche d'une carte partagée)
  useEffectM(() => {
    const f = (e) => {
      const pr = ((e && e.detail) || {}).peer;
      if (pr && pr.id && !FP_PEERS[pr.id]) {
        FP_PEERS[pr.id] = pr;
        window.FP_THREADS = window.FP_THREADS || {};
        window.FP_THREADS[pr.id] = window.FP_THREADS[pr.id] || [{ id: 1, kind: 'day', label: "AUJOURD'HUI" }];
        if (window.m4TouchConvo) window.m4TouchConvo(pr.id, 'Nouveau contact', '');
      }
    };
    window.addEventListener('fp:addcontact', f);
    return () => window.removeEventListener('fp:addcontact', f);
  }, []);

  // Appel direct depuis une fiche (même logique : crée le contact si besoin, puis lance l'appel)
  useEffectM(() => {
    const f = (e) => {
      const d = (e && e.detail) || {};
      if (d.peer && d.peer.id && !FP_PEERS[d.peer.id]) {
        FP_PEERS[d.peer.id] = d.peer;
        window.FP_THREADS = window.FP_THREADS || {};
        window.FP_THREADS[d.peer.id] = window.FP_THREADS[d.peer.id] || [{ id: 1, kind: 'day', label: "AUJOURD'HUI" }];
      }
      const pid = d.pid || (d.peer && d.peer.id);
      if (pid && FP_PEERS[pid]) { setPhase('app'); startCall(pid, d.kind || 'voice-out'); }
    };
    window.addEventListener('fp:call', f);
    return () => window.removeEventListener('fp:call', f);
  }, []);

  // Démarrer un appel avec n'importe quel contact vérifié
  const startCall = (pid, kind) => {
    const target = pid && FP_PEERS[pid] ? pid : activePid;
    setCallPid(target);
    setActivePid(target);
    setView('chat');
    setScreen(kind);
  };

  // Appel de salon (groupe) · l'écran d'appel recouvre l'app, le shell reste en place
  const startRoomCall = (room) => {
    if (!room) return;
    setCallRoom(room);
    setCallPid(room.pids[0]);
    setScreen('salon');
  };
  const endRoomCall = (secs) => {
    setScreen('chat');
    if (callRoom) dispatchFp({ type: 'calllog', kind: 'voice', dur: fmtDur(secs || 0), pid: callRoom.pids[0] });
  };

  const screenEl = (() => {
    switch (screen) {
      case 'voice-out':
        return <VoiceCall lang={lang} peer={callPeer} onEnd={(s) => endCall('voice', s)} onVideo={() => setScreen('video')} />;
      case 'voice-active':
        return <VoiceCall lang={lang} peer={callPeer} startActive onEnd={(s) => endCall('voice', s)} onVideo={() => setScreen('video')} />;
      case 'incoming':
        return <IncomingCall lang={lang} peer={callPeer} onAccept={() => setScreen('voice-active')} onDecline={() => endCall('voice', null)} />;
      case 'incoming-video':
        return <IncomingCall lang={lang} peer={callPeer} video onAccept={() => setScreen('video')} onDecline={() => endCall('video', null)} />;
      case 'video':
        return <VideoCall lang={lang} peer={callPeer} onEnd={(s) => endCall('video', s)} />;
      case 'salon':
        return <SalonCall lang={lang} room={callRoom} onEnd={endRoomCall} />;
      default:
        return null;
    }
  })();

  return (
    <div className={`scene ${dark ? 'dark' : ''}`}>
      <div className="backdrop"></div>
      <div className="grid-overlay"></div>

      <div className="scene-chrome">
        <div className="scene-brand">
          <img className="brand-logo" src="assets/logotype_white.png" alt="FOOTPASS®" />
          <span className="scene-meta">PROTOTYPE</span>
        </div>
        <div className="scene-actions">
          <FPDeviceSwitch current="mobile" dark={dark} />
          <button className="theme-toggle" onClick={() => setTw('dark', !dark)} aria-label="Thème">
            <div className="toggle-track">
              <div className={`toggle-thumb ${dark ? 'right' : ''}`}>
                {dark ? <FPIcon.Moon c="#EAEAEA" /> : <FPIcon.Sun c="#0F0F0F" />}
              </div>
            </div>
          </button>
        </div>
      </div>

      <div className="phone-wrap">
        <div className={`phone ${dark ? 'dark' : ''}`}>
          <div className="phone-bezel"></div>
          <div className="dynamic-island"></div>
          <div className="phone-screen" style={{ '--acc': accent.acc, '--acc-bright': accent.bright }}>
            {/* Chat stays mounted permanently · call screens overlay it (position:absolute) */}
            <ChatScreen
              dark={dark} lang={lang} peer={activePeer}
              forcedFocused={forcedFocused} forcedMode={forcedMode}
              onVoice={() => startCall(activePid, 'voice-out')}
              onVideo={() => startCall(activePid, 'video')}
              onBack={() => setView('messages')}
            />
            {/* Shell (accueil / messages / menu / agenda / appels) au-dessus du chat */}
            {phase === 'app' && view !== 'chat' ? (
              <FPShell
                dark={dark} lang={lang} tab={view}
                onTab={(tb) => setView(tb)}
                onOpenChat={openChat}
                onVoice={(pid) => startCall(pid, 'voice-out')}
                onVideo={(pid) => startCall(pid, 'video')}
                onRoomCall={startRoomCall}
                onReplayOnboarding={() => startOnboarding('self')}
                appearance={{ dark, setDark: (v) => setTw('dark', v), lang, setLang: (v) => setTw('lang', v) }}
              />
            ) : null}
            {screenEl}
            {phase === 'onboarding' ? (
              <OnboardingFlow key={`${obEntry}-${obKey}`} entry={obEntry} dark={dark} onFinish={finishOnboarding} />
            ) : null}
            {booting ? (
              <FPSplash key={bootKey} onDone={() => setBooting(false)} />
            ) : null}
          </div>
          <div className="home-indicator"></div>
        </div>
        <div className="phone-shadow"></div>
      </div>

      {/* Panneau de démonstration · uniquement des scénarios à jouer devant
          quelqu'un. Aucune variante d'apparence : pas de couleur d'accent, pas
          de version d'accueil, pas de style de Pass ID. Le rendu FOOTPASS est
          celui de la marque, il ne se règle pas depuis ici. */}
      <TweaksPanel title="Démo">
        <TweakSection label="Reprendre à zéro" />
        <TweakButton label="Réinitialiser la démo" onClick={() => { try { localStorage.clear(); } catch (e) {} location.reload(); }} />
        <TweakButton label="Rejouer l'écran d'ouverture" onClick={replaySplash} />
        <TweakSection label="Parcours d'entrée" />
        <TweakButton label="Inscription libre" onClick={() => startOnboarding('self')} />
        <TweakButton label="Invité par un club" onClick={() => startOnboarding('invite')} />
        <TweakButton label="Aller à l'accueil" onClick={() => { setView('home'); setPhase('app'); }} />
        <TweakButton label="Aller à la conversation" onClick={() => { setView('chat'); setPhase('app'); }} />
        <TweakSection label="Appels" />
        <TweakButton label="Appel vocal sortant" onClick={() => startCall(activePid, 'voice-out')} />
        <TweakButton label="Appel vidéo sortant" onClick={() => startCall(activePid, 'video')} />
        <TweakButton label="Recevoir un appel" onClick={() => startCall(activePid, 'incoming')} />
        <TweakButton label="Recevoir un appel vidéo" onClick={() => startCall(activePid, 'incoming-video')} />
        <TweakButton label="Appel de salon (groupe)" onClick={() => { setPhase('app'); startRoomCall(window.CL2_ROOMS && window.CL2_ROOMS[0]); }} />
        <TweakSection label="Messages" />
        <TweakButton label="Recevoir un message" onClick={() => { setScreen('chat'); dispatchFp({ type: 'incomingMsg', pid: activePid }); }} />
        <TweakButton label="Demande d'un agent inconnu" onClick={() => { window.fpReqSet && window.fpReqSet('new'); setPhase('app'); setView('messages'); }} />
        <TweakButton label="Retirer cette demande" onClick={() => { window.fpReqSet && window.fpReqSet('off'); }} />
        <TweakSelect
          label="État du composer"
          value={tw.state}
          onChange={(v) => { setScreen('chat'); setTw('state', v); }}
          options={[
            { value: 'default', label: 'Par défaut' },
            { value: 'keyboard', label: 'Clavier ouvert' },
            { value: 'plus', label: 'Menu +' },
            { value: 'recording', label: 'Enregistrement audio' },
            { value: 'transcribe', label: 'Transcription en direct' },
          ]}
        />
        <TweakSection label="Structure" />
        <TweakButton label="Réinitialiser la structure" onClick={() => { try { localStorage.removeItem('fp_structure'); localStorage.removeItem('fp_structure_hide'); localStorage.removeItem('fp_structures'); } catch (e) {} if (window.FP_ME) window.FP_ME.org = null; setView('home'); setPhase('app'); window.dispatchEvent(new CustomEvent('fp:growth', { detail: { kind: 'structure' } })); }} />
        <TweakButton label="Tunnel · créer une structure" onClick={() => { setView('home'); setPhase('app'); window.dispatchEvent(new CustomEvent('fp:growth', { detail: { kind: 'sheet', sheet: 'structure', mode: 'create' } })); }} />
        <TweakSection label="Rétention" />
        <TweakButton label="Simuler un retour d'absence" onClick={() => { try { localStorage.setItem('fp_growth_absence', '1'); } catch (e) {} setView('home'); setPhase('app'); window.dispatchEvent(new CustomEvent('fp:growth', { detail: { kind: 'absence' } })); }} />
        <TweakButton label="Simuler : un invité rejoint" onClick={() => { setPhase('app'); window.dispatchEvent(new CustomEvent('fp:growth', { detail: { kind: 'joined' } })); }} />
        <TweakButton label="Checklist « Bien démarrer »" onClick={() => { try { localStorage.setItem('fp_growth_steps', JSON.stringify({ msg: false, invite: false, auth: false, off: false })); } catch (e) {} setView('home'); setPhase('app'); window.dispatchEvent(new CustomEvent('fp:growth', { detail: { kind: 'checklist' } })); }} />
        <TweakSection label="États système" />
        <TweakSelect
          label="État de l'écran actif"
          value={tw.sysState}
          onChange={(v) => { setTw('sysState', v); window.dispatchEvent(new CustomEvent('fp:sys', { detail: { state: v } })); }}
          options={[
            { value: 'none', label: 'Aucun (écran réel)' },
            { value: 'loading', label: 'Chargement · squelette' },
            { value: 'empty', label: 'Vide · premier usage' },
            { value: 'offline', label: 'Hors ligne' },
            { value: 'error', label: 'Erreur' },
            { value: 'unauthorized', label: 'Non autorisé' },
            { value: 'locked', label: 'Verrouillé · coffre' },
          ]}
        />
        <TweakButton label="→ Messages" onClick={() => goScreen({ view: 'messages' })} />
        <TweakButton label="→ Coffre-fort" onClick={() => goScreen({ sub: 'vault' })} />
        <TweakButton label="→ Autorisations" onClick={() => goScreen({ sub: 'mandates' })} />
        <TweakButton label="Galerie d'états" onClick={() => goScreen({ sub: 'states' })} />
        <TweakButton label="Écran « À propos »" onClick={() => goScreen({ sub: 'about' })} />
        <TweakSection label="Langue" />
        <TweakRadio
          label="Langue de l'app"
          value={lang}
          onChange={(v) => setTw('lang', v)}
          options={[{ value: 'fr', label: 'FR' }, { value: 'en', label: 'EN' }]}
        />
      </TweaksPanel>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Scene />);
