/* global React, ReactDOM */
// OrgAdminPage — Console interne "Mon organisation" (Audits Énergies)
// 4 onglets : Équipe · Messagerie · Documents · Paramètres
// Voir docs/ORG-ADMIN.md + docs/DOC-INTAKE.md

(function () {
  const { useState, useEffect, useMemo, useRef } = React;
  const API = () => (window.AE_API && window.AE_API.BASE) || '';

  function OrgAdminPage() {
    const [tab, setTab] = useState('team'); // team | chat | docs | settings
    const [me, setMe] = useState(null);
    const [members, setMembers] = useState([]);

    useEffect(() => {
      fetch(`${API()}/api/org/members/me`).then(r => r.json()).then(d => setMe(d?.me || null));
      fetch(`${API()}/api/org/members`).then(r => r.json()).then(d => setMembers(d?.members || []));
    }, []);

    return (
      <div style={{ padding: '16px 24px 80px' }}>
        {/* Header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
          <h1 style={{ fontSize: 20, fontWeight: 600, letterSpacing: '-0.02em', margin: 0 }}>🏢 Mon organisation</h1>
          <span className="mono" style={{ fontSize: 11, color: 'var(--ink-4)', padding: '2px 8px', border: '1px solid var(--line)', borderRadius: 999 }}>
            Audits Énergies · {members.length} collaborateurs
          </span>
          <span style={{ flex: 1 }} />
          {me && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 10px', background: 'var(--paper-2)', border: '1px solid var(--hairline)', borderRadius: 999 }}>
              <span style={{ width: 22, height: 22, borderRadius: '50%', background: me.meta?.color || 'var(--signal)', color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 700 }}>
                {(me.firstName || '').charAt(0)}{(me.lastName || '').charAt(0)}
              </span>
              <div style={{ fontSize: 11, lineHeight: 1.1 }}>
                <div style={{ fontWeight: 600 }}>{me.firstName} {me.lastName}</div>
                <div style={{ color: 'var(--ink-4)', fontSize: 9 }}>{me.role}</div>
              </div>
            </div>
          )}
        </div>

        {/* Tabs */}
        <div style={{ display: 'flex', gap: 2, padding: 2, background: 'var(--paper-2)', border: '1px solid var(--line)', borderRadius: 6, width: 'fit-content', marginBottom: 16 }}>
          {[
            { k: 'team', l: `👥 Équipe (${members.length})` },
            { k: 'chat', l: '💬 Messagerie' },
            { k: 'docs', l: '📥 Documents' },
            { k: 'settings', l: '⚙️ Paramètres' },
          ].map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} style={{
              padding: '6px 14px', fontSize: 12, fontWeight: 500,
              background: tab === t.k ? 'var(--paper)' : 'transparent',
              color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)',
              border: tab === t.k ? '1px solid var(--line)' : '1px solid transparent',
              borderRadius: 4,
            }}>{t.l}</button>
          ))}
        </div>

        {tab === 'team' && <TeamTab members={members} me={me} onRefresh={async () => {
          const r = await fetch(`${API()}/api/org/members`).then(r => r.json()); setMembers(r?.members || []);
        }} />}
        {tab === 'chat' && <ChatTab me={me} members={members} />}
        {tab === 'docs' && <DocsTab me={me} members={members} />}
        {tab === 'settings' && <SettingsTab me={me} />}
      </div>
    );
  }

  // ─── Équipe ─────────────────────────────────────────────────────
  function TeamTab({ members, me, onRefresh }) {
    const [selected, setSelected] = useState(null);
    const [stats, setStats] = useState(null);
    const [showAdd, setShowAdd] = useState(false);

    useEffect(() => {
      if (!selected) { setStats(null); return; }
      fetch(`${API()}/api/org/members/${selected.id}`).then(r => r.json()).then(d => setStats(d?.stats || null));
    }, [selected?.id]);

    return (
      <>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
          <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>Gère les collaborateurs, leurs rôles, leurs profils et leurs stats.</div>
          <button onClick={() => setShowAdd(true)} style={{ padding: '6px 12px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600 }}>+ Inviter un collaborateur</button>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 14 }}>
          <div style={{ border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)', maxHeight: 'calc(100vh - 260px)', overflowY: 'auto' }}>
            {members.map(m => (
              <button key={m.id} onClick={() => setSelected(m)} style={{
                display: 'grid', gridTemplateColumns: 'auto 1fr auto', gap: 10, alignItems: 'center',
                width: '100%', padding: '10px 12px', textAlign: 'left',
                background: selected?.id === m.id ? 'var(--paper)' : 'transparent',
                borderBottom: '1px solid var(--hairline)',
                borderLeft: selected?.id === m.id ? '2px solid var(--signal)' : '2px solid transparent',
              }}>
                <span style={{ width: 30, height: 30, borderRadius: '50%', background: m.meta?.color || 'var(--signal-soft)', color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 700 }}>
                  {(m.firstName || '').charAt(0)}{(m.lastName || '').charAt(0)}
                </span>
                <div>
                  <div style={{ fontSize: 12, fontWeight: 600 }}>{m.firstName} {m.lastName}</div>
                  <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{m.title || m.role} · {m.email}</div>
                </div>
                {m.isMonopoly && <span style={{ fontSize: 8, padding: '1px 5px', background: 'var(--plasma-tint)', color: 'var(--plasma)', borderRadius: 3, fontWeight: 700 }}>OWNER</span>}
              </button>
            ))}
          </div>

          <div style={{ border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)', padding: 20 }}>
            {!selected && <div style={{ display: 'grid', placeItems: 'center', height: '100%', color: 'var(--ink-4)', fontSize: 12 }}>Sélectionne un membre pour voir son profil, ses stats, et pouvoir le contacter.</div>}
            {selected && <MemberDetail member={selected} stats={stats} me={me} onRefresh={onRefresh} />}
          </div>
        </div>

        {showAdd && <InviteModal onClose={() => setShowAdd(false)} onCreated={() => { setShowAdd(false); onRefresh(); }} />}
      </>
    );
  }

  function MemberDetail({ member, stats, me, onRefresh }) {
    const [edit, setEdit] = useState(false);
    const [draft, setDraft] = useState({});
    const [saving, setSaving] = useState(false);

    const start = () => { setDraft({ firstName: member.firstName, lastName: member.lastName || '', phone: member.phone || '', title: member.title || '', role: member.role, color: member.meta?.color || '', avatar: member.meta?.avatar || '' }); setEdit(true); };
    const save = async () => {
      setSaving(true);
      const url = me?.id === member.id ? `${API()}/api/org/members/me` : `${API()}/api/org/members/${member.id}`;
      await fetch(url, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me?.id || 0) }, body: JSON.stringify(draft) });
      setSaving(false); setEdit(false); onRefresh();
    };
    const startDM = async () => {
      const body = `Bonjour ${member.firstName}, je t'envoie un message depuis le cockpit 👋`;
      await fetch(`${API()}/api/org/messages`, {
        method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me?.id || 0) },
        body: JSON.stringify({ recipientId: member.id, body }),
      });
      alert('Message envoyé — ouvre l\'onglet 💬 Messagerie');
    };
    const startCall = async (media) => {
      const r = await fetch(`${API()}/api/org/calls/start`, {
        method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me?.id || 0) },
        body: JSON.stringify({ recipientId: member.id, media }),
      }).then(r => r.json());
      if (r?.externalUrl) window.open(r.externalUrl, '_blank', 'noopener');
      else alert('Appel démarré — rejoins depuis la messagerie');
    };

    return (
      <>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14, borderBottom: '1px solid var(--hairline)', paddingBottom: 14, marginBottom: 14 }}>
          <span style={{ width: 54, height: 54, borderRadius: '50%', background: member.meta?.color || 'var(--signal-soft)', color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 18, fontWeight: 700 }}>
            {(member.firstName || '').charAt(0)}{(member.lastName || '').charAt(0)}
          </span>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 18, fontWeight: 700 }}>{member.firstName} {member.lastName}</div>
            <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>{member.title || member.role}</div>
            <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 3 }}>📧 {member.email}{member.phone ? ` · ☎ ${member.phone}` : ''}</div>
          </div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {me?.id !== member.id && (
              <>
                <button onClick={startDM} title="Message direct" style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>💬 Message</button>
                <button onClick={() => startCall('audio')} title="Appel audio" style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>📞 Audio</button>
                <button onClick={() => startCall('video')} title="Appel vidéo" style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>📹 Vidéo</button>
              </>
            )}
            {!edit
              ? <button onClick={start} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>✏️ Éditer</button>
              : <>
                  <button onClick={() => setEdit(false)} disabled={saving} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>Annuler</button>
                  <button onClick={save} disabled={saving} style={{ padding: '5px 12px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600 }}>{saving ? '…' : '✓ Enregistrer'}</button>
                </>}
          </div>
        </div>

        {!edit ? (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10 }}>
            <StatBox label="Opportunités" value={stats?.opportunities ?? '—'} color="signal" />
            <StatBox label="Visites terrain" value={stats?.visites ?? '—'} color="plasma" />
            <StatBox label="Dossiers CEE" value={stats?.dossiers ?? '—'} color="copper" />
            <StatBox label="Études thermiques" value={stats?.etudes ?? '—'} color="amber" />
          </div>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Field label="Prénom" v={draft.firstName} onChange={v => setDraft(d => ({ ...d, firstName: v }))} />
            <Field label="Nom" v={draft.lastName} onChange={v => setDraft(d => ({ ...d, lastName: v }))} />
            <Field label="Titre affiché" v={draft.title} onChange={v => setDraft(d => ({ ...d, title: v }))} full />
            <Field label="Téléphone" v={draft.phone} onChange={v => setDraft(d => ({ ...d, phone: v }))} />
            <Field label="Rôle" v={draft.role} onChange={v => setDraft(d => ({ ...d, role: v }))} />
            <Field label="Couleur pastille (hex)" v={draft.color} onChange={v => setDraft(d => ({ ...d, color: v }))} />
            <Field label="Avatar (emoji ou URL)" v={draft.avatar} onChange={v => setDraft(d => ({ ...d, avatar: v }))} />
          </div>
        )}
      </>
    );
  }

  function StatBox({ label, value, color }) {
    return (
      <div style={{ padding: 12, background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 5 }}>
        <div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>{label}</div>
        <div style={{ fontSize: 22, fontWeight: 700, color: `var(--${color}-deep, var(--ink))` }}>{value}</div>
      </div>
    );
  }

  function InviteModal({ onClose, onCreated }) {
    const [f, setF] = useState({ firstName: '', lastName: '', email: '', role: 'commercial', title: '' });
    const [busy, setBusy] = useState(false);
    const [err, setErr] = useState(null);
    const save = async () => {
      setBusy(true); setErr(null);
      try {
        const r = await fetch(`${API()}/api/org/members`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(f) }).then(r => r.json());
        if (!r.ok) throw new Error(r.error || 'échec');
        await fetch(`${API()}/api/org/members/${r.member.id}/invite`, { method: 'POST' }).catch(() => {});
        onCreated();
      } catch (e) { setErr(e.message); } finally { setBusy(false); }
    };
    const ROLES = ['pdg', 'chef-de-projet', 'commercial', 'technicien', 'bureau-etude', 'administratif', 'direction', 'observateur'];
    return (
      <div style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(14,16,16,0.6)', display: 'grid', placeItems: 'center', backdropFilter: 'blur(3px)', padding: 16 }} onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
        <div style={{ width: 'min(500px, 100%)', background: 'var(--paper)', borderRadius: 12, boxShadow: 'var(--shadow-3)', border: '1px solid var(--line-2)' }}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
            <div style={{ fontSize: 14, fontWeight: 600 }}>+ Inviter un collaborateur</div>
          </div>
          <div style={{ padding: 18, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Field label="Prénom" v={f.firstName} onChange={v => setF(s => ({ ...s, firstName: v }))} />
            <Field label="Nom" v={f.lastName} onChange={v => setF(s => ({ ...s, lastName: v }))} />
            <Field label="Email" v={f.email} onChange={v => setF(s => ({ ...s, email: v }))} full />
            <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
              <span style={lblS}>Rôle</span>
              <select value={f.role} onChange={e => setF(s => ({ ...s, role: e.target.value }))} style={inpS}>
                {ROLES.map(r => <option key={r} value={r}>{r}</option>)}
              </select>
            </div>
            <Field label="Titre affiché" v={f.title} onChange={v => setF(s => ({ ...s, title: v }))} />
            {err && <div style={{ gridColumn: '1 / -1', fontSize: 11, color: 'var(--rouge)' }}>⚠ {err}</div>}
            <div style={{ gridColumn: '1 / -1', display: 'flex', justifyContent: 'flex-end', gap: 6 }}>
              <button onClick={onClose} disabled={busy} style={{ padding: '6px 12px', fontSize: 11 }}>Annuler</button>
              <button onClick={save} disabled={busy || !f.firstName || !f.email} style={{ padding: '6px 14px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600 }}>{busy ? '…' : 'Créer & inviter'}</button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  // ─── Messagerie ─────────────────────────────────────────────────
  function ChatTab({ me, members }) {
    const [threads, setThreads] = useState([]);
    const [active, setActive] = useState(null); // { threadId, kind, channelKey, targetKind, targetId, recipientId }
    const [messages, setMessages] = useState([]);
    const [body, setBody] = useState('');
    const [channels, setChannels] = useState([]);
    const pollRef = useRef(null);

    useEffect(() => {
      fetch(`${API()}/api/org/messages/channels`).then(r => r.json()).then(d => setChannels(d?.channels || []));
      refreshThreads();
    }, []);
    const refreshThreads = () => fetch(`${API()}/api/org/messages/threads`, { headers: { 'X-Collaborator-Id': String(me?.id || 0) } }).then(r => r.json()).then(d => setThreads(d?.threads || []));

    useEffect(() => {
      if (!active) return;
      loadMessages();
      pollRef.current = setInterval(loadMessages, 8000);
      return () => clearInterval(pollRef.current);
    }, [active?.threadId]);

    const loadMessages = async () => {
      if (!active) return;
      const p = new URLSearchParams();
      if (active.channelKey) p.set('channel', active.channelKey);
      else if (active.targetKind) { p.set('targetKind', active.targetKind); p.set('targetId', active.targetId); }
      else if (active.recipientId) p.set('dmWith', active.recipientId);
      else if (active.threadId) p.set('threadId', active.threadId);
      const r = await fetch(`${API()}/api/org/messages?${p.toString()}`, { headers: { 'X-Collaborator-Id': String(me?.id || 0) } }).then(r => r.json()).catch(() => null);
      setMessages(r?.messages || []);
    };

    const send = async () => {
      if (!body.trim() || !active) return;
      const payload = { body };
      if (active.channelKey) payload.channelKey = active.channelKey;
      else if (active.targetKind) { payload.targetKind = active.targetKind; payload.targetId = active.targetId; }
      else if (active.recipientId) payload.recipientId = active.recipientId;
      await fetch(`${API()}/api/org/messages`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me?.id || 0) }, body: JSON.stringify(payload) });
      setBody(''); loadMessages(); refreshThreads();
    };

    const startCall = async (media) => {
      if (!active) return;
      const payload = { media };
      if (active.channelKey) payload.channelKey = active.channelKey;
      else if (active.targetKind) { payload.targetKind = active.targetKind; payload.targetId = active.targetId; }
      else if (active.recipientId) payload.recipientId = active.recipientId;
      const r = await fetch(`${API()}/api/org/calls/start`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me?.id || 0) }, body: JSON.stringify(payload) }).then(r => r.json());
      if (r?.externalUrl) window.open(r.externalUrl, '_blank', 'noopener');
      loadMessages();
    };

    const senderName = (id) => {
      const m = members.find(x => x.id === id);
      return m ? `${m.firstName} ${m.lastName || ''}`.trim() : `#${id}`;
    };
    const senderColor = (id) => {
      const m = members.find(x => x.id === id);
      return m?.meta?.color || 'var(--signal-soft)';
    };

    return (
      <div style={{ display: 'grid', gridTemplateColumns: '280px 1fr', gap: 14, height: 'calc(100vh - 220px)' }}>
        <div style={{ border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)', overflow: 'auto' }}>
          <div style={{ padding: '8px 12px', fontSize: 9, fontWeight: 700, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, borderBottom: '1px solid var(--hairline)' }}>Canaux</div>
          {channels.map(c => (
            <button key={c.key} onClick={() => setActive({ threadId: `thread-${c.key}`, kind: 'channel', channelKey: c.key })} style={{
              display: 'block', width: '100%', textAlign: 'left', padding: '8px 12px', fontSize: 12,
              background: active?.channelKey === c.key ? 'var(--paper)' : 'transparent',
              borderLeft: active?.channelKey === c.key ? '2px solid var(--signal)' : '2px solid transparent',
              borderBottom: '1px solid var(--hairline)',
            }}>
              <div style={{ fontWeight: 500 }}>{c.label}</div>
              <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{c.description}</div>
            </button>
          ))}
          <div style={{ padding: '8px 12px', fontSize: 9, fontWeight: 700, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, borderBottom: '1px solid var(--hairline)' }}>Messages directs</div>
          {members.filter(m => m.id !== me?.id).map(m => {
            const ids = [me?.id, m.id].filter(Boolean).sort((x, y) => x - y);
            const tid = ids.length === 2 ? `thread-dm-${ids[0]}-${ids[1]}` : null;
            return (
              <button key={m.id} onClick={() => setActive({ threadId: tid, kind: 'dm', recipientId: m.id })} style={{
                display: 'flex', gap: 8, alignItems: 'center', width: '100%', textAlign: 'left', padding: '8px 12px', fontSize: 12,
                background: active?.recipientId === m.id ? 'var(--paper)' : 'transparent',
                borderLeft: active?.recipientId === m.id ? '2px solid var(--signal)' : '2px solid transparent',
                borderBottom: '1px solid var(--hairline)',
              }}>
                <span style={{ width: 22, height: 22, borderRadius: '50%', background: m.meta?.color || 'var(--signal-soft)', color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 9, fontWeight: 700 }}>{(m.firstName || '').charAt(0)}</span>
                <span>{m.firstName} {m.lastName}</span>
              </button>
            );
          })}
          <div style={{ padding: '8px 12px', fontSize: 9, fontWeight: 700, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, borderBottom: '1px solid var(--hairline)' }}>Threads entités</div>
          {threads.filter(t => t.kind === 'entity').slice(0, 20).map(t => (
            <button key={t.threadId} onClick={() => setActive({ threadId: t.threadId, kind: 'entity', targetKind: t.targetKind, targetId: t.targetId })} style={{
              display: 'block', width: '100%', textAlign: 'left', padding: '8px 12px', fontSize: 12,
              background: active?.threadId === t.threadId ? 'var(--paper)' : 'transparent',
              borderLeft: active?.threadId === t.threadId ? '2px solid var(--signal)' : '2px solid transparent',
              borderBottom: '1px solid var(--hairline)',
            }}>
              <div style={{ fontWeight: 500 }}>{t.targetKind} #{t.targetId}</div>
              <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{t.lastBody || ''}</div>
            </button>
          ))}
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          {!active && <div style={{ flex: 1, display: 'grid', placeItems: 'center', color: 'var(--ink-4)', fontSize: 12 }}>Sélectionne un canal, un collègue ou une entité pour commencer à discuter.</div>}
          {active && (
            <>
              <div style={{ padding: '10px 14px', borderBottom: '1px solid var(--hairline)', display: 'flex', alignItems: 'center', gap: 10 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>
                  {active.channelKey ? channels.find(c => c.key === active.channelKey)?.label : null}
                  {active.recipientId ? senderName(active.recipientId) : null}
                  {active.targetKind ? `💬 Commentaires ${active.targetKind} #${active.targetId}` : null}
                </div>
                <span style={{ flex: 1 }} />
                <button onClick={() => startCall('audio')} style={{ padding: '4px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>📞 Audio</button>
                <button onClick={() => startCall('video')} style={{ padding: '4px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>📹 Vidéo</button>
              </div>

              <div style={{ flex: 1, overflowY: 'auto', padding: 14, display: 'flex', flexDirection: 'column', gap: 8 }}>
                {messages.length === 0 && <div style={{ color: 'var(--ink-4)', fontSize: 11, textAlign: 'center', paddingTop: 40 }}>Aucun message encore — envoie le premier 👋</div>}
                {messages.map(m => (
                  <div key={m.id} style={{ display: 'flex', gap: 8, alignItems: 'flex-start', flexDirection: m.senderId === me?.id ? 'row-reverse' : 'row' }}>
                    <span style={{ width: 26, height: 26, borderRadius: '50%', background: senderColor(m.senderId), color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 700, flexShrink: 0 }}>
                      {senderName(m.senderId).slice(0, 2)}
                    </span>
                    <div style={{ maxWidth: '70%', padding: '7px 11px', borderRadius: 8, background: m.senderId === me?.id ? 'var(--signal-tint)' : 'var(--paper)', border: '1px solid ' + (m.senderId === me?.id ? 'var(--signal-soft)' : 'var(--hairline)') }}>
                      <div style={{ fontSize: 9, color: 'var(--ink-4)', marginBottom: 2 }}>{senderName(m.senderId)} · {new Date(m.createdAt).toLocaleString('fr-FR', { hour: '2-digit', minute: '2-digit' })}</div>
                      {(m.kind === 'call_video' || m.kind === 'call_audio') ? (
                        <div>
                          <div style={{ fontSize: 12 }}>{m.body}</div>
                          {m.meta?.externalUrl && <a href={m.meta.externalUrl} target="_blank" rel="noreferrer" style={{ fontSize: 11, color: 'var(--signal-deep)', fontWeight: 600 }}>🔗 Rejoindre l'appel</a>}
                        </div>
                      ) : (
                        <div style={{ fontSize: 12, whiteSpace: 'pre-wrap' }}>{m.body}</div>
                      )}
                    </div>
                  </div>
                ))}
              </div>

              <div style={{ padding: 10, borderTop: '1px solid var(--hairline)', display: 'flex', gap: 8 }}>
                <input value={body} onChange={e => setBody(e.target.value)} onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }} placeholder="Écrire un message…" style={{ flex: 1, padding: '8px 12px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)' }} />
                <button onClick={send} disabled={!body.trim()} style={{ padding: '8px 16px', fontSize: 12, fontWeight: 600, background: body.trim() ? 'var(--signal)' : 'var(--paper-3)', color: body.trim() ? 'var(--ink)' : 'var(--ink-4)', border: 'none', borderRadius: 4 }}>Envoyer</button>
              </div>
            </>
          )}
        </div>
      </div>
    );
  }

  // ─── Documents ──────────────────────────────────────────────────
  function DocsTab({ me, members }) {
    const [docs, setDocs] = useState([]);
    const [filter, setFilter] = useState({ category: '', source: '', q: '' });
    const [stats, setStats] = useState(null);
    const [busy, setBusy] = useState(false);
    const fileRef = useRef(null);

    const load = async () => {
      const p = new URLSearchParams();
      if (filter.category) p.set('category', filter.category);
      if (filter.source) p.set('source', filter.source);
      const r = await fetch(`${API()}/api/org/documents?${p}`).then(r => r.json());
      setDocs(r?.documents || []);
      const s = await fetch(`${API()}/api/org/documents/stats`).then(r => r.json());
      setStats(s || null);
    };
    useEffect(() => { load(); }, [filter.category, filter.source]);

    const onUpload = async (file) => {
      if (!file) return;
      setBusy(true);
      const reader = new FileReader();
      reader.onload = async () => {
        const base64 = reader.result.split(',')[1];
        await fetch(`${API()}/api/org/documents/upload`, {
          method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me?.id || 0) },
          body: JSON.stringify({ filename: file.name, mime: file.type, size: file.size, dataBase64: base64 }),
        });
        setBusy(false); load();
      };
      reader.readAsDataURL(file);
    };

    const ingestEmail = async () => {
      setBusy(true);
      const r = await fetch(`${API()}/api/org/documents/ingest-email-attachments`, { method: 'POST' }).then(r => r.json());
      setBusy(false);
      alert(`Scan terminé : ${r.created || 0} créés, ${r.skipped || 0} ignorés sur ${r.scanned || 0} attachments.`);
      load();
    };

    const CATS = ['client', 'admin', 'compta', 'rh', 'legal', 'tech', 'autre'];
    const catColor = { client: 'signal', admin: 'plasma', compta: 'amber', rh: 'copper', legal: 'rouge', tech: 'signal', autre: 'ink-4' };
    const filtered = docs.filter(d => !filter.q || [d.title, d.description, JSON.stringify(d.tags)].join(' ').toLowerCase().includes(filter.q.toLowerCase()));

    return (
      <div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12 }}>
          <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>Pièces jointes reçues par email + uploads manuels, classées par catégorie.</div>
          <span style={{ flex: 1 }} />
          <button onClick={ingestEmail} disabled={busy} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>📥 Scanner emails</button>
          <input ref={fileRef} type="file" hidden onChange={e => onUpload(e.target.files?.[0])} />
          <button onClick={() => fileRef.current?.click()} disabled={busy} style={{ padding: '5px 12px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600 }}>{busy ? '…' : '+ Uploader un fichier'}</button>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 8, marginBottom: 14 }}>
          <button onClick={() => setFilter(f => ({ ...f, category: '' }))} style={{ padding: '8px 4px', fontSize: 11, background: !filter.category ? 'var(--paper)' : 'var(--paper-2)', border: '1px solid ' + (!filter.category ? 'var(--signal-soft)' : 'var(--hairline)'), borderRadius: 5, fontWeight: 600 }}>
            Tous<br /><span style={{ fontSize: 10, color: 'var(--ink-4)' }}>{stats?.total ?? '—'}</span>
          </button>
          {CATS.map(c => (
            <button key={c} onClick={() => setFilter(f => ({ ...f, category: c }))} style={{ padding: '8px 4px', fontSize: 11, background: filter.category === c ? 'var(--paper)' : 'var(--paper-2)', border: '1px solid ' + (filter.category === c ? 'var(--signal-soft)' : 'var(--hairline)'), borderRadius: 5, fontWeight: 600, color: `var(--${catColor[c]}-deep, var(--ink))` }}>
              {c}<br /><span style={{ fontSize: 10, color: 'var(--ink-4)' }}>{stats?.byCategory?.[c] ?? 0}</span>
            </button>
          ))}
        </div>

        <input value={filter.q} onChange={e => setFilter(f => ({ ...f, q: e.target.value }))} placeholder="Rechercher dans les titres / tags…" style={{ width: '100%', padding: '8px 12px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)', marginBottom: 12 }} />

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 10 }}>
          {filtered.length === 0 && <div style={{ gridColumn: '1 / -1', padding: 30, textAlign: 'center', color: 'var(--ink-4)', fontSize: 12 }}>Aucun document. Clique « + Uploader » ou « 📥 Scanner emails ».</div>}
          {filtered.map(d => (
            <div key={d.id} style={{ padding: 10, background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 5, display: 'flex', flexDirection: 'column', gap: 6 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <span style={{ fontSize: 16 }}>{docIcon(d.mimeType)}</span>
                <span style={{ fontSize: 12, fontWeight: 600, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={d.title}>{d.title}</span>
                <span style={{ fontSize: 8, padding: '1px 5px', background: `var(--${catColor[d.category]}-tint, var(--paper-2))`, color: `var(--${catColor[d.category]}-deep, var(--ink-3))`, borderRadius: 3, fontWeight: 700, textTransform: 'uppercase' }}>{d.category}</span>
              </div>
              <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{d.source} · {formatSize(d.size)} · {new Date(d.createdAt).toLocaleDateString('fr-FR')}</div>
              <div style={{ display: 'flex', gap: 6 }}>
                <a href={`${API()}/api/org/documents/${d.id}/download`} target="_blank" rel="noreferrer" style={{ fontSize: 10, padding: '3px 7px', background: 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3, color: 'var(--ink-2)' }}>↓ Télécharger</a>
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ─── Paramètres ────────────────────────────────────────────────
  function SettingsTab({ me }) {
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Identité de l'organisation</div>
          <div style={{ fontSize: 12, lineHeight: 1.6, color: 'var(--ink-2)' }}>
            <div><b>Audits Énergies SAS</b></div>
            <div>SIRET — à compléter (prochainement éditable)</div>
            <div>Délégataire CEE · FR-2026</div>
          </div>
          <div style={{ marginTop: 10, fontSize: 11, color: 'var(--ink-4)' }}>Prochaine version : identité + branding éditables.</div>
        </div>
        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Cloisonnement des dossiers</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5 }}>
            Par défaut, chaque collaborateur ne voit que ses propres dossiers (opps, visites, études, CEE). Les rôles <span className="mono" style={{ fontSize: 10 }}>pdg</span> / <span className="mono" style={{ fontSize: 10 }}>direction</span> / <span className="mono" style={{ fontSize: 10 }}>chef-de-projet</span> voient tout.
          </div>
          <div style={{ marginTop: 10, fontSize: 11, color: 'var(--signal-deep)' }}>🛡 Actif par défaut · configurable par rôle prochainement.</div>
        </div>
        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Appels audio/vidéo</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5 }}>
            v1 : provider <span className="mono" style={{ fontSize: 10 }}>Jitsi Meet</span> public (meet.jit.si). Aucune donnée sortie en dehors du navigateur. Pour v1.1 : serveur Jitsi interne auto-hébergé.
          </div>
        </div>
        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Ingestion documents</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5 }}>
            Scan auto des pièces jointes email : heuristique (nom de fichier + domaine expéditeur). Classification Claude à venir (v1.1 — cf <span className="mono" style={{ fontSize: 10 }}>docs/DOC-INTAKE.md</span>).
          </div>
        </div>
      </div>
    );
  }

  // ─── helpers ────────────────────────────────────────────────────
  const inpS = { padding: '6px 8px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)', color: 'var(--ink)', fontFamily: 'inherit', width: '100%', boxSizing: 'border-box' };
  const lblS = { fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 };
  function Field({ label, v, onChange, full }) {
    return (
      <div style={{ gridColumn: full ? '1 / -1' : 'auto', display: 'flex', flexDirection: 'column', gap: 3 }}>
        <span style={lblS}>{label}</span>
        <input value={v || ''} onChange={e => onChange(e.target.value)} style={inpS} />
      </div>
    );
  }
  function docIcon(mime) {
    if (!mime) return '📄';
    if (mime.startsWith('image/')) return '🖼';
    if (mime.includes('pdf')) return '📕';
    if (mime.includes('word')) return '📘';
    if (mime.includes('sheet') || mime.includes('excel')) return '📗';
    if (mime.includes('zip')) return '🗜';
    if (mime.startsWith('text/')) return '📝';
    return '📄';
  }
  function formatSize(b) {
    if (!b) return '—';
    if (b < 1024) return b + ' B';
    if (b < 1024 * 1024) return Math.round(b / 1024) + ' KB';
    return (b / 1024 / 1024).toFixed(1) + ' MB';
  }

  // ─── EntityCommentsPanel ──────────────────────────────────────────
  // Panneau réutilisable — commentaires internes + appels Jitsi sur
  // TOUTE entité du SaaS (dossier, visite, opportunité, étude, devis…).
  //
  // Usage depuis n'importe quel fichier :
  //   window.EntityCommentsPanel &&
  //   <window.EntityCommentsPanel targetKind="dossier" targetId={id} />
  //
  // Props :
  //   targetKind  string  — "dossier" | "visite" | "opportunite" | "etude" | …
  //   targetId    any     — ID entité (number ou string ref)
  //   compact     bool    — hauteur réduite 300 vs 440 px
  function EntityCommentsPanel({ targetKind, targetId, compact }) {
    const [me2, setMe2] = useState(null);
    const [mbrs, setMbrs] = useState([]);
    const [msgs, setMsgs] = useState([]);
    const [body, setBody] = useState('');
    const [sending, setSending] = useState(false);
    const pollRef = useRef(null);

    // Charger me + membres une fois
    useEffect(() => {
      fetch(`${API()}/api/org/members/me`).then(r => r.json()).then(d => setMe2(d?.me || null)).catch(() => {});
      fetch(`${API()}/api/org/members`).then(r => r.json()).then(d => setMbrs(d?.members || [])).catch(() => {});
    }, []);

    // Charger + polluer les messages de ce thread entité
    useEffect(() => {
      if (!targetKind || targetId === undefined || targetId === null) return;
      load();
      pollRef.current = setInterval(load, 12000);
      return () => clearInterval(pollRef.current);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [targetKind, String(targetId)]);

    const load = async () => {
      const r = await fetch(
        `${API()}/api/org/messages?targetKind=${encodeURIComponent(targetKind)}&targetId=${encodeURIComponent(targetId)}`,
        { headers: { 'X-Collaborator-Id': String(me2?.id || 0) } }
      ).then(r => r.json()).catch(() => null);
      setMsgs(r?.messages || []);
    };

    const send = async () => {
      if (!body.trim()) return;
      setSending(true);
      await fetch(`${API()}/api/org/messages`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me2?.id || 0) },
        body: JSON.stringify({ targetKind, targetId: Number(targetId) || targetId, body }),
      }).catch(() => {});
      setBody(''); setSending(false); load();
    };

    const startCall = async (media) => {
      const r = await fetch(`${API()}/api/org/calls/start`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Collaborator-Id': String(me2?.id || 0) },
        body: JSON.stringify({ targetKind, targetId: Number(targetId) || targetId, media }),
      }).then(r => r.json()).catch(() => null);
      if (r?.externalUrl) window.open(r.externalUrl, '_blank', 'noopener');
      load();
    };

    const nm  = (id) => { const m = mbrs.find(x => x.id === id); return m ? `${m.firstName} ${m.lastName || ''}`.trim() : `#${id}`; };
    const ini = (id) => { const m = mbrs.find(x => x.id === id); return m ? `${(m.firstName||'').charAt(0)}${(m.lastName||'').charAt(0)}` : '??'; };
    const col = (id) => { const m = mbrs.find(x => x.id === id); return m?.meta?.color || 'var(--signal-soft)'; };
    const h   = compact ? 300 : 440;

    return (
      <div style={{ display: 'flex', flexDirection: 'column', border: '1px solid var(--line)', borderRadius: 8, background: 'var(--paper-2)', height: h }}>
        {/* ── Header ── */}
        <div style={{ padding: '8px 14px', borderBottom: '1px solid var(--hairline)', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0 }}>
          <span style={{ fontSize: 12, fontWeight: 600 }}>💬 Discussion interne</span>
          <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)', padding: '1px 6px', border: '1px solid var(--hairline)', borderRadius: 999 }}>
            {targetKind} · {targetId}
          </span>
          <span style={{ flex: 1 }} />
          <span style={{ fontSize: 10, color: 'var(--ink-4)' }}>{msgs.length} msg</span>
          <button
            onClick={() => startCall('audio')}
            title="Appel audio Jitsi"
            style={{ padding: '3px 8px', fontSize: 10, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 3, display: 'flex', alignItems: 'center', gap: 3 }}>
            📞 <span>Audio</span>
          </button>
          <button
            onClick={() => startCall('video')}
            title="Appel vidéo Jitsi"
            style={{ padding: '3px 8px', fontSize: 10, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 3, display: 'flex', alignItems: 'center', gap: 3 }}>
            📹 <span>Vidéo</span>
          </button>
        </div>

        {/* ── Messages ── */}
        <div style={{ flex: 1, overflowY: 'auto', padding: '10px 14px', display: 'flex', flexDirection: 'column', gap: 7 }}>
          {msgs.length === 0 && (
            <div style={{ flex: 1, display: 'grid', placeItems: 'center', color: 'var(--ink-4)', fontSize: 11, textAlign: 'center', lineHeight: 1.6, padding: '30px 20px' }}>
              Pas encore de commentaires sur ce {targetKind}.<br />
              <span style={{ color: 'var(--ink-5)', fontSize: 10 }}>Lance la discussion ou un appel audio/vidéo ↑</span>
            </div>
          )}
          {msgs.map(m => (
            <div key={m.id} style={{ display: 'flex', gap: 7, alignItems: 'flex-start', flexDirection: m.senderId === me2?.id ? 'row-reverse' : 'row' }}>
              <span
                title={nm(m.senderId)}
                style={{ width: 22, height: 22, borderRadius: '50%', background: col(m.senderId), color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 9, fontWeight: 700, flexShrink: 0, marginTop: 2 }}>
                {ini(m.senderId)}
              </span>
              <div style={{ maxWidth: '76%', padding: '6px 10px', borderRadius: 7, background: m.senderId === me2?.id ? 'var(--signal-tint)' : 'var(--paper)', border: '1px solid ' + (m.senderId === me2?.id ? 'var(--signal-soft)' : 'var(--hairline)') }}>
                <div style={{ fontSize: 9, color: 'var(--ink-4)', marginBottom: 2 }}>
                  {nm(m.senderId)} · {new Date(m.createdAt).toLocaleString('fr-FR', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit' })}
                </div>
                {(m.kind === 'call_video' || m.kind === 'call_audio') ? (
                  <div>
                    <div style={{ fontSize: 11 }}>{m.body}</div>
                    {m.meta?.externalUrl && (
                      <a href={m.meta.externalUrl} target="_blank" rel="noreferrer" style={{ fontSize: 10, color: 'var(--signal-deep)', fontWeight: 600 }}>
                        🔗 Rejoindre l'appel
                      </a>
                    )}
                  </div>
                ) : (
                  <div style={{ fontSize: 11, whiteSpace: 'pre-wrap' }}>{m.body}</div>
                )}
              </div>
            </div>
          ))}
        </div>

        {/* ── Compose ── */}
        <div style={{ padding: '8px 10px', borderTop: '1px solid var(--hairline)', display: 'flex', gap: 6, flexShrink: 0 }}>
          <input
            value={body}
            onChange={e => setBody(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }}
            placeholder={`Commenter ce ${targetKind}… (⏎ pour envoyer)`}
            style={{ flex: 1, padding: '7px 10px', fontSize: 11, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)' }}
          />
          <button
            onClick={send}
            disabled={sending || !body.trim()}
            style={{ padding: '7px 14px', fontSize: 11, fontWeight: 600, background: body.trim() ? 'var(--signal)' : 'var(--paper-3)', color: body.trim() ? 'var(--ink)' : 'var(--ink-4)', border: 'none', borderRadius: 4 }}>
            {sending ? '…' : '↑ Envoyer'}
          </button>
        </div>
      </div>
    );
  }

  window.OrgAdminPage = OrgAdminPage;
  window.EntityCommentsPanel = EntityCommentsPanel;
})();
