// Vocal API Docs — single-page React app.
// Sidebar (sections) | Contenu Markdown-like | Right rail (Auth + clé API).
// "Try it" intégré : utilise la clé API saisie (ou récupérée depuis my.vocal.ch
// via localStorage si le user vient de là) pour exécuter les requêtes en live.

const { useState, useEffect, useMemo, useCallback } = React;

const API_BASE = 'https://api.vocal.ch';
const MY_BASE  = 'https://my.vocal.ch';

const LS = {
  apiKey:  'vocal_docs_apikey',
  myToken: 'vocal_my_token', // partagé avec my.vocal.ch (même origin .vocal.ch)
};

// ============================================================================
// Auth context : on garde la clé API saisie (apiKey) ET le bearer my.vocal.ch
// (myToken) pour récupérer automatiquement les clés API du user connecté.
// ============================================================================
// Récupère un éventuel ?apikey=... ou #apikey=... passé depuis my.vocal.ch
// pour faciliter le pré-remplissage à la première visite.
function readPrefilledKey() {
  try {
    const search = new URLSearchParams(location.search);
    if (search.get('apikey')) return search.get('apikey');
    const h = (location.hash || '').replace(/^#/, '');
    const params = new URLSearchParams(h.includes('=') ? h : '');
    if (params.get('apikey')) return params.get('apikey');
  } catch (e) {}
  return null;
}

const useAuth = () => {
  const prefilled = readPrefilledKey();
  const [apiKey, setApiKey] = useState(() => prefilled || localStorage.getItem(LS.apiKey) || '');
  const [myToken, setMyToken] = useState(() => localStorage.getItem(LS.myToken) || '');
  // Nettoie l'URL après extraction (on garde la clé seulement en localStorage).
  useEffect(() => {
    if (prefilled) {
      const url = new URL(location.href); url.searchParams.delete('apikey');
      history.replaceState(null, '', url.pathname + url.search);
    }
  }, []);
  const [me, setMe] = useState(null);
  const [keys, setKeys] = useState([]);

  useEffect(() => { localStorage.setItem(LS.apiKey, apiKey || ''); }, [apiKey]);

  // Charge le profil + les clés API du user via my.vocal.ch si le token y est.
  const refresh = useCallback(async () => {
    if (!myToken) { setMe(null); setKeys([]); return; }
    try {
      const meRes = await fetch(`${API_BASE}/me`, { headers: { Authorization: `Bearer ${myToken}` } });
      if (!meRes.ok) { setMe(null); setKeys([]); return; }
      const meData = await meRes.json();
      setMe(meData?.user || null);
      const kRes = await fetch(`${API_BASE}/my/api-keys`, { headers: { Authorization: `Bearer ${myToken}` } });
      if (kRes.ok) {
        const kData = await kRes.json();
        setKeys(kData?.api_keys || kData?.keys || []);
      }
    } catch (e) { /* silent */ }
  }, [myToken]);

  useEffect(() => { refresh(); }, [refresh]);

  return { apiKey, setApiKey, myToken, setMyToken, me, keys, refresh };
};

// ============================================================================
// Sidebar : navigation par section.
// ============================================================================
const SECTIONS = [
  { group: 'Démarrage', items: [
    { id: 'intro',   label: 'Introduction' },
    { id: 'auth',    label: 'Authentification' },
    { id: 'errors',  label: 'Codes d\'erreur' },
  ]},
  { group: 'WhatsApp', items: [
    { id: 'wa-template', label: 'Envoyer un template' },
    { id: 'wa-flows',    label: 'Conversations entrantes' },
  ]},
  { group: 'Référence', items: [
    { id: 'sdk',       label: 'Exemples (curl / Node / Python / PHP)' },
    { id: 'changelog', label: 'Changelog' },
  ]},
];

const Sidebar = ({ active, onNavigate }) => (
  <aside className="sidebar">
    <div className="sidebar-brand">
      <img src="https://my.vocal.ch/assets/img/vocal-logotype.svg" alt="Vocal" />
      <span className="tag">DOCS</span>
    </div>
    {SECTIONS.map(s => (
      <div key={s.group}>
        <div className="sidebar-section-title">{s.group}</div>
        {s.items.map(it => (
          <a key={it.id}
             className={`sidebar-link ${active === it.id ? 'active' : ''}`}
             onClick={() => onNavigate(it.id)}>
            {it.label}
          </a>
        ))}
      </div>
    ))}
    <div className="sidebar-section-title">Liens</div>
    <a className="sidebar-link" href={MY_BASE} target="_blank" rel="noopener">↗ Espace client</a>
    <a className="sidebar-link" href="mailto:support@vocal.ch">↗ Support</a>
  </aside>
);

// ============================================================================
// Right rail : auth + clé API rapide.
// ============================================================================
const RightRail = ({ auth }) => {
  const { apiKey, setApiKey, me, keys, myToken } = auth;
  const isConnected = !!me;
  return (
    <aside className="right-rail">
      <h4>Authentification</h4>
      {isConnected ? (
        <div className="banner-auth banner-ok">
          <div>
            <strong>Connecté</strong><br/>
            <span className="muted">{me.email}</span>
          </div>
          <a className="btn btn-sm" href={MY_BASE} target="_blank" rel="noopener">Espace ↗</a>
        </div>
      ) : (
        <div className="banner-auth">
          <div>
            <strong>Non connecté</strong><br/>
            <span className="muted">Connectez-vous pour récupérer vos clés API automatiquement.</span>
          </div>
          <a className="btn btn-sm btn-primary" href={MY_BASE}>Se connecter</a>
        </div>
      )}

      <h4 style={{ marginTop: '1.25rem' }}>Clé API</h4>
      <input
        type="text" value={apiKey} placeholder="vk_..." autoComplete="off"
        onChange={e => setApiKey(e.target.value.trim())} />
      {isConnected && keys.length > 0 && (
        <>
          <div className="muted" style={{ marginTop: '0.5rem' }}>Choisir parmi vos clés :</div>
          {keys.filter(k => k.is_active).map(k => (
            <button key={k.id} className="btn btn-sm" style={{ marginTop: '0.3rem', width: '100%', textAlign: 'left' }}
              onClick={() => setApiKey(k.key_value || k.key || '')}>
              {k.label || `Clé #${k.id}`}
              <div className="muted" style={{ fontSize: '0.7rem' }}>
                {(k.key_value || k.key || '').slice(0, 14)}…
              </div>
            </button>
          ))}
        </>
      )}
      {isConnected && keys.length === 0 && (
        <div className="muted" style={{ marginTop: '0.5rem' }}>
          Aucune clé pour l'instant.{' '}
          <a href={`${MY_BASE}/#api-keys`} target="_blank" rel="noopener">Créer une clé →</a>
        </div>
      )}
      <div className="muted" style={{ marginTop: '0.75rem', fontSize: '0.78rem' }}>
        Cette clé est utilisée localement pour les boutons « Tester en live » de cette doc.
      </div>
    </aside>
  );
};

// ============================================================================
// Composant Try-it : panneau live de test d'un endpoint.
// ============================================================================
const TryIt = ({ apiKey, defaults, schema }) => {
  // schema : [{ key, label, placeholder, type?: 'text'|'textarea'|'select', options? }]
  const [form, setForm] = useState(defaults || {});
  const [resp, setResp] = useState(null);
  const [busy, setBusy] = useState(false);
  const [reqPreview, setReqPreview] = useState(false);

  const run = async () => {
    setBusy(true); setResp(null);
    try {
      const body = {};
      for (const f of schema) {
        const v = form[f.key];
        if (v === undefined || v === '') continue;
        if (f.key === 'variables') {
          try { body[f.key] = JSON.parse(v); }
          catch (e) { setResp({ status: 0, body: { error: `Variables JSON invalide : ${e.message}` } }); setBusy(false); return; }
        } else { body[f.key] = v; }
      }
      const r = await fetch(`${API_BASE}/v1/messages/whatsapp/template`, {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${apiKey || ''}`, 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      const text = await r.text();
      let parsed; try { parsed = JSON.parse(text); } catch { parsed = { raw: text }; }
      setResp({ status: r.status, body: parsed });
    } catch (e) {
      setResp({ status: 0, body: { error: e.message || String(e) } });
    } finally { setBusy(false); }
  };

  const curlSnippet = useMemo(() => {
    const body = {};
    for (const f of schema) {
      const v = form[f.key];
      if (v === undefined || v === '') continue;
      if (f.key === 'variables') {
        try { body[f.key] = JSON.parse(v); } catch { body[f.key] = v; }
      } else body[f.key] = v;
    }
    return `curl -X POST '${API_BASE}/v1/messages/whatsapp/template' \\
  -H 'Authorization: Bearer ${apiKey || '<YOUR_API_KEY>'}' \\
  -H 'Content-Type: application/json' \\
  -d '${JSON.stringify(body, null, 2)}'`;
  }, [form, apiKey, schema]);

  return (
    <div className="tryit">
      <div className="tryit-title">
        <span>🧪 Tester en live</span>
        <span className="tag">POST /v1/messages/whatsapp/template</span>
      </div>
      {!apiKey && (
        <div className="callout callout-warning" style={{ marginBottom: '0.75rem' }}>
          Renseignez votre <strong>clé API</strong> à droite pour activer le test.
        </div>
      )}
      {schema.map(f => (
        <div key={f.key}>
          <label>{f.label}{f.required && <span style={{ color: 'var(--danger)' }}> *</span>}</label>
          {f.type === 'textarea' ? (
            <textarea rows={f.rows || 4} value={form[f.key] || ''}
              placeholder={f.placeholder}
              onChange={e => setForm({ ...form, [f.key]: e.target.value })} />
          ) : f.type === 'select' ? (
            <select value={form[f.key] || ''} onChange={e => setForm({ ...form, [f.key]: e.target.value })}>
              {(f.options || []).map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
            </select>
          ) : (
            <input type="text" value={form[f.key] || ''}
              placeholder={f.placeholder}
              onChange={e => setForm({ ...form, [f.key]: e.target.value })} />
          )}
        </div>
      ))}
      <div className="tryit-actions">
        <button className="btn btn-primary" disabled={busy || !apiKey} onClick={run}>
          {busy ? 'Envoi…' : 'Envoyer'}
        </button>
        <button className="btn btn-sm" onClick={() => setReqPreview(p => !p)}>{reqPreview ? 'Masquer' : 'Voir'} la requête</button>
      </div>
      {reqPreview && <div className="response-box"><pre><code>{curlSnippet}</code></pre></div>}
      {resp && (
        <div className="response-box">
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <strong>Réponse</strong>
            <span className={`tag`} style={{ background: resp.status >= 200 && resp.status < 300 ? '#dcfce7' : '#fee2e2', color: resp.status >= 200 && resp.status < 300 ? '#166534' : '#991b1b' }}>
              HTTP {resp.status}
            </span>
          </div>
          <pre><code>{JSON.stringify(resp.body, null, 2)}</code></pre>
        </div>
      )}
    </div>
  );
};

// ============================================================================
// Contenu des sections.
// ============================================================================
const SectionIntro = () => (
  <>
    <h1>API Vocal</h1>
    <p className="muted">REST API JSON, endpoints stables, authentifiés par clé API. Idéal pour automatiser l'envoi de notifications WhatsApp transactionnelles depuis votre back-office.</p>
    <h2>Base URL</h2>
    <pre><code>{API_BASE}</code></pre>
    <h2>Format</h2>
    <p>Toutes les requêtes et réponses sont en JSON. Les requêtes qui modifient des données prennent un body <code>Content-Type: application/json</code>.</p>
    <h2>Conventions</h2>
    <ul>
      <li>Tous les numéros de téléphone sont au format <strong>E.164</strong> (ex: <code>+41225394800</code>).</li>
      <li>Les horodatages sont en <strong>UTC ISO 8601</strong>.</li>
      <li>Les montants sont en <strong>CHF</strong> sauf indication contraire.</li>
    </ul>
  </>
);

const SectionAuth = () => (
  <>
    <h1>Authentification</h1>
    <p>Toutes les requêtes API doivent inclure un header <code>Authorization</code> avec votre clé API en Bearer token :</p>
    <pre><code>{`Authorization: Bearer vk_XXXXXXXXXXXXXXXXXXXXXXXX`}</code></pre>
    <h2>Où trouver ma clé ?</h2>
    <p>Dans <a href={`${MY_BASE}/#api-keys`} target="_blank" rel="noopener">l'espace client → API</a>, créez une clé et choisissez les lignes auxquelles elle a accès. Une clé peut être révoquée ou limitée à tout moment.</p>
    <div className="callout callout-warning">
      <strong>Ne partagez jamais votre clé.</strong> Elle a accès à vos lignes et peut envoyer des messages facturés.
    </div>
  </>
);

const SectionErrors = () => (
  <>
    <h1>Codes d'erreur</h1>
    <p>Les erreurs renvoient un statut HTTP standard et un body JSON <code>{`{ "error": "...", "code": ... }`}</code>.</p>
    <table>
      <thead><tr><th>HTTP</th><th>Signification</th><th>Action</th></tr></thead>
      <tbody>
        <tr><td><code>400</code></td><td>Paramètres invalides</td><td>Vérifier le body de la requête (format E.164, JSON valide…).</td></tr>
        <tr><td><code>401</code></td><td>Clé API manquante / invalide</td><td>Header <code>Authorization: Bearer …</code>.</td></tr>
        <tr><td><code>403</code></td><td>Ligne non autorisée par cette clé</td><td>Ajouter la ligne au scope de la clé dans my.vocal.ch.</td></tr>
        <tr><td><code>404</code></td><td>Ligne ou template introuvable</td><td>Vérifier l'orthographe du <code>template</code> et de <code>from</code>.</td></tr>
        <tr><td><code>409</code></td><td>Template non approuvé</td><td>Soumettre le template à WhatsApp et attendre l'approbation.</td></tr>
        <tr><td><code>502</code></td><td>Erreur opérateur (Twilio / Meta)</td><td>Détail dans le champ <code>detail</code>. Réessayer plus tard.</td></tr>
      </tbody>
    </table>
  </>
);

const SectionWATemplate = ({ apiKey, defaultFrom, defaultTemplate }) => (
  <>
    <h1>Envoyer un template WhatsApp</h1>
    <p>Envoie un message en utilisant un <strong>template approuvé</strong> par WhatsApp (Content Template). Permet d'écrire à un client hors fenêtre 24h (rappel, confirmation, notification).</p>
    <div className="endpoint"><span className="badge badge-post">POST</span><code>{API_BASE}/v1/messages/whatsapp/template</code></div>

    <h2>Body</h2>
    <table>
      <thead><tr><th>Paramètre</th><th>Type</th><th>Description</th></tr></thead>
      <tbody>
        <tr><td><code>from</code> *</td><td>string</td><td>Numéro Vocal expéditeur (E.164). Doit être une ligne WhatsApp active autorisée par votre clé.</td></tr>
        <tr><td><code>to</code> *</td><td>string</td><td>Numéro destinataire (E.164).</td></tr>
        <tr><td><code>template</code> *</td><td>string</td><td>Nom interne du template (<code>friendly_name</code>) ou <code>content_sid</code> (HX…).</td></tr>
        <tr><td><code>variables</code></td><td>object</td><td>Map <code>{`{ "1": "valeur1", "2": "valeur2" }`}</code> pour remplir les placeholders <code>{`{{1}}`}, {`{{2}}`}</code> du template.</td></tr>
      </tbody>
    </table>

    <h2>Exemple</h2>
    <pre><code>{`curl -X POST '${API_BASE}/v1/messages/whatsapp/template' \\
  -H 'Authorization: Bearer vk_XXXX' \\
  -H 'Content-Type: application/json' \\
  -d '{
    "from":     "${defaultFrom || '+41225394800'}",
    "to":       "+41XXXXXXXXX",
    "template": "${defaultTemplate || 'rey_confirmation_v1'}",
    "variables": {
      "1": "Yannick",
      "2": "Genève → CDG",
      "3": "27 mai 2026",
      "4": "Genève Aéroport T1"
    }
  }'`}</code></pre>

    <h3>Réponse 200</h3>
    <pre><code>{`{
  "ok": true,
  "message_sid": "SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "queued",
  "content_sid": "HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "template": "rey_confirmation_v1",
  "from": "${defaultFrom || '+41225394800'}",
  "to": "+41XXXXXXXXX"
}`}</code></pre>

    <TryIt
      apiKey={apiKey}
      defaults={{
        from: defaultFrom || '+41225394800',
        to: '',
        template: defaultTemplate || '',
        variables: '{\n  "1": "Yannick",\n  "2": "10:30"\n}',
      }}
      schema={[
        { key: 'from',     label: 'from (votre ligne WhatsApp)', placeholder: '+41225394800', required: true },
        { key: 'to',       label: 'to (destinataire)', placeholder: '+41XXXXXXXXX', required: true },
        { key: 'template', label: 'template (friendly_name ou content_sid)', placeholder: 'rey_confirmation_v1', required: true },
        { key: 'variables', label: 'variables (JSON)', type: 'textarea', rows: 6, placeholder: '{ "1": "Yannick" }' },
      ]}
    />

    <h2>Bonnes pratiques</h2>
    <ul>
      <li>Donnez des <strong>exemples réalistes</strong> dans les variables lors de la création du template (sinon Meta rejette).</li>
      <li>Vérifiez le <code>status</code> via le webhook delivery ou en interrogeant <code>/api/whatsapp</code>.</li>
      <li>Idempotence : si vous envoyez deux fois la même requête, deux messages partiront. Gérez l'idempotence côté client (clé déduplication interne).</li>
    </ul>
  </>
);

const SectionWAFlows = () => (
  <>
    <h1>Conversations entrantes</h1>
    <p>Quand un utilisateur envoie un WhatsApp à votre ligne Vocal, le message arrive dans votre <strong>inbox</strong> sur my.vocal.ch et un bot IA peut répondre automatiquement si activé.</p>
    <h2>Activer le bot IA pour une ligne</h2>
    <ol>
      <li>Ouvrir <a href={`${MY_BASE}/#lines`} target="_blank" rel="noopener">my.vocal.ch → Mes lignes</a></li>
      <li>Cliquer <strong>💬 Activer WhatsApp</strong> sur la ligne</li>
      <li>Vocal détecte automatiquement le sender chez l'opérateur, synchronise les webhooks, active le bot.</li>
    </ol>
    <p>Le bot utilise le même <code>voice_ai_prompt</code> + <code>ai_knowledge</code> + <code>ai_name</code> que votre bot vocal — vous ne configurez qu'une fois.</p>
    <h2>Webhook entrant (avancé)</h2>
    <p>Si vous voulez recevoir les messages dans votre propre application, configurez un <code>webhook_url</code> sur la ligne (à venir).</p>
  </>
);

const SectionSdk = () => (
  <>
    <h1>Exemples</h1>
    <h2>Node.js</h2>
    <pre><code>{`const resp = await fetch('${API_BASE}/v1/messages/whatsapp/template', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.VOCAL_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    from: '+41225394800',
    to: '+41XXXXXXXXX',
    template: 'rey_confirmation_v1',
    variables: { 1: 'Yannick', 2: '10:30' },
  }),
});
const data = await resp.json();
console.log(data);`}</code></pre>

    <h2>Python</h2>
    <pre><code>{`import requests, os
r = requests.post(
  '${API_BASE}/v1/messages/whatsapp/template',
  headers={'Authorization': f'Bearer {os.environ["VOCAL_API_KEY"]}'},
  json={
    'from': '+41225394800',
    'to': '+41XXXXXXXXX',
    'template': 'rey_confirmation_v1',
    'variables': {'1': 'Yannick', '2': '10:30'},
  },
)
print(r.status_code, r.json())`}</code></pre>

    <h2>PHP</h2>
    <pre><code>{`<?php
$ch = curl_init('${API_BASE}/v1/messages/whatsapp/template');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('VOCAL_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'from' => '+41225394800',
    'to' => '+41XXXXXXXXX',
    'template' => 'rey_confirmation_v1',
    'variables' => ['1' => 'Yannick', '2' => '10:30'],
  ]),
]);
$resp = curl_exec($ch);
echo $resp;`}</code></pre>
  </>
);

const SectionChangelog = () => (
  <>
    <h1>Changelog</h1>
    <h3>27 mai 2026</h3>
    <ul>
      <li>Premier endpoint public : <code>POST /v1/messages/whatsapp/template</code>.</li>
      <li>Documentation interactive : <strong>docs.vocal.ch</strong>.</li>
    </ul>
  </>
);

// ============================================================================
// App principale.
// ============================================================================
const App = () => {
  const auth = useAuth();
  const [active, setActive] = useState(() => {
    const h = (location.hash || '#intro').replace('#', '');
    return SECTIONS.flatMap(s => s.items).some(i => i.id === h) ? h : 'intro';
  });
  useEffect(() => {
    const onHash = () => {
      const h = (location.hash || '#intro').replace('#', '');
      if (SECTIONS.flatMap(s => s.items).some(i => i.id === h)) setActive(h);
    };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  const navigate = (id) => { location.hash = '#' + id; setActive(id); window.scrollTo(0, 0); };

  // Defaults pour Try-it : on tente d'extraire la première ligne WhatsApp + template approuvé du user.
  const [defaults, setDefaults] = useState({ from: '', template: '' });
  useEffect(() => {
    (async () => {
      if (!auth.myToken) return;
      try {
        const lr = await fetch(`${API_BASE}/my/lines`, { headers: { Authorization: `Bearer ${auth.myToken}` } });
        if (lr.ok) {
          const ld = await lr.json();
          const waLine = (ld.lines || []).find(l => l.wa_bot_enabled || l.whatsapp_enabled);
          if (waLine) setDefaults(d => ({ ...d, from: waLine.phone_number }));
        }
      } catch (e) {}
    })();
  }, [auth.myToken]);

  return (
    <div className="layout">
      <Sidebar active={active} onNavigate={navigate} />
      <main className="content">
        {active === 'intro'        && <SectionIntro />}
        {active === 'auth'         && <SectionAuth />}
        {active === 'errors'       && <SectionErrors />}
        {active === 'wa-template'  && <SectionWATemplate apiKey={auth.apiKey} defaultFrom={defaults.from} defaultTemplate={defaults.template} />}
        {active === 'wa-flows'     && <SectionWAFlows />}
        {active === 'sdk'          && <SectionSdk />}
        {active === 'changelog'    && <SectionChangelog />}
      </main>
      <RightRail auth={auth} />
    </div>
  );
};

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