/* GTI SMS — Main React app
   Globals expected: API_DATA, GTI_CODE
*/

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

/* ============================================
   Icons (inline SVG)
   ============================================ */
const Icon = ({ name, size = 16 }) => {
  const paths = {
    search: <><circle cx="11" cy="11" r="7" /><path d="m21 21-4.3-4.3" /></>,
    copy:   <><rect x="9" y="9" width="11" height="11" rx="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" /></>,
    check:  <path d="M5 12l4.5 4.5L19 7" />,
    play:   <path d="M6 4l14 8-14 8V4z" fill="currentColor" stroke="none" />,
    close:  <><path d="M6 6l12 12" /><path d="M18 6l-12 12" /></>,
    chev:   <path d="M9 6l6 6-6 6" />,
    link:   <><path d="M10 14a4 4 0 0 0 5.5 0l3-3a4 4 0 0 0-5.5-5.5l-1 1" /><path d="M14 10a4 4 0 0 0-5.5 0l-3 3a4 4 0 1 0 5.5 5.5l1-1" /></>,
    bolt:   <path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z" fill="currentColor" stroke="none" />,
    book:   <><path d="M4 4v16h16V4z" /><path d="M4 4l8 4 8-4" /></>,
    key:    <><circle cx="8" cy="15" r="4" /><path d="M11 12l9-9" /><path d="M17 6l3 3" /></>,
    alert:  <><path d="M12 2 2 22h20L12 2z" /><path d="M12 10v5" /><path d="M12 18v.5" /></>,
    gauge:  <><path d="M12 14l5-5" /><circle cx="12" cy="14" r="8" /></>,
    send:   <><path d="M22 2L11 13" /><path d="M22 2l-7 20-4-9-9-4z" /></>,
    wallet: <><rect x="3" y="6" width="18" height="14" rx="2" /><path d="M16 14a2 2 0 0 0 0-4h4v4z" /></>,
    chart:  <><path d="M4 20V8" /><path d="M10 20V4" /><path d="M16 20v-7" /><path d="M22 20H2" /></>,
    moon:   <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z" />,
    sun:    <><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
         stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      {paths[name]}
    </svg>
  );
};

/* ============================================
   Top bar
   ============================================ */
function TopBar({ onOpenSearch, theme, onToggleTheme }) {
  const logoSrc = theme === "dark" ? "assets/logo-gtisms-dark.png" : "assets/logo-gtisms-light.png";
  return (
    <header className="topbar">
      <a href="#overview" className="brand" onClick={(e) => { e.preventDefault(); window.GTI_NAV?.("overview"); }}>
        <span className="brand-mark">
          <img src={logoSrc} alt="GTI SMS" />
        </span>
        <span className="brand-version">API v3</span>
      </a>
      <div className="topbar-right">
        <button className="search-trigger" onClick={onOpenSearch}>
          <Icon name="search" size={14} />
          <span>Buscar na documentação...</span>
          <span className="kbd">⌘K</span>
        </button>
        <button
          className="theme-toggle"
          onClick={onToggleTheme}
          title={theme === "dark" ? "Mudar para tema claro" : "Mudar para tema escuro"}
          aria-label="Alternar tema"
        >
          <Icon name={theme === "dark" ? "sun" : "moon"} size={16} />
        </button>
        <a className="btn-status" href="https://status.gtisms.com/" target="_blank" rel="noopener" title="Status da API">
          <span className="status-dot"></span>
          <span className="status-label">Status</span>
        </a>
        <a className="btn btn-primary" href="https://sms.gtisms.com" target="_blank" rel="noopener">Dashboard</a>
      </div>
    </header>
  );
}

/* ============================================
   Sidebar
   ============================================ */
function Sidebar({ current, onNavigate }) {
  return (
    <aside className="sidebar">
      {API_DATA.groups.map(group => (
        <div className="nav-group" key={group.id}>
          <div className="nav-group-title">{group.title}</div>
          {group.items.map(item => (
            <div
              key={item.id}
              className={"nav-item " + (current === item.id ? "active" : "")}
              onClick={() => onNavigate(item.id)}
            >
              {item.method && (
                <span className={"nav-method " + item.method.toLowerCase()}>
                  {item.method}
                </span>
              )}
              <span>{item.title}</span>
            </div>
          ))}
        </div>
      ))}
    </aside>
  );
}

/* ============================================
   Search modal (Cmd+K)
   ============================================ */
function SearchModal({ open, onClose, onNavigate }) {
  const [q, setQ] = useState("");
  const [selIdx, setSelIdx] = useState(0);
  const inputRef = useRef(null);

  useEffect(() => {
    if (open) {
      setQ("");
      setSelIdx(0);
      setTimeout(() => inputRef.current?.focus(), 30);
    }
  }, [open]);

  const flatItems = useMemo(() => {
    const items = [];
    API_DATA.groups.forEach(g => {
      g.items.forEach(it => items.push({ ...it, group: g.title, groupId: g.id }));
    });
    return items;
  }, []);

  const results = useMemo(() => {
    if (!q.trim()) return flatItems;
    const term = q.toLowerCase();
    return flatItems.filter(it =>
      it.title.toLowerCase().includes(term) ||
      (it.path || "").toLowerCase().includes(term) ||
      (it.method || "").toLowerCase().includes(term) ||
      it.group.toLowerCase().includes(term)
    );
  }, [q, flatItems]);

  // Reset selIdx if it overflows
  useEffect(() => { setSelIdx(0); }, [q]);

  const onKey = (e) => {
    if (e.key === "Escape") onClose();
    if (e.key === "ArrowDown") { e.preventDefault(); setSelIdx(i => Math.min(i + 1, results.length - 1)); }
    if (e.key === "ArrowUp")   { e.preventDefault(); setSelIdx(i => Math.max(i - 1, 0)); }
    if (e.key === "Enter" && results[selIdx]) {
      onNavigate(results[selIdx].id);
      onClose();
    }
  };

  if (!open) return null;
  return (
    <div className="search-overlay" onClick={onClose}>
      <div className="search-modal" onClick={(e) => e.stopPropagation()}>
        <div className="search-input-wrap">
          <Icon name="search" size={16} />
          <input
            ref={inputRef}
            className="search-input"
            placeholder="Buscar endpoints, parâmetros, métodos…"
            value={q}
            onChange={(e) => setQ(e.target.value)}
            onKeyDown={onKey}
          />
          <span className="kbd" style={{ fontSize: 11, color: "var(--fg-subtle)", fontFamily: "var(--font-mono)" }}>ESC</span>
        </div>
        <div className="search-results">
          {results.length === 0 ? (
            <div className="search-empty">Nenhum resultado para "{q}"</div>
          ) : (
            <>
              {results.map((it, i) => (
                <div
                  key={it.id}
                  className={"search-result " + (i === selIdx ? "active" : "")}
                  onMouseEnter={() => setSelIdx(i)}
                  onClick={() => { onNavigate(it.id); onClose(); }}
                >
                  {it.method ? (
                    <span className={"nav-method " + it.method.toLowerCase()}>{it.method}</span>
                  ) : (
                    <Icon name="book" size={14} />
                  )}
                  <span style={{ flex: 1 }}>{it.title}</span>
                  <span style={{ fontSize: 11, color: "var(--fg-subtle)" }}>{it.group}</span>
                </div>
              ))}
            </>
          )}
        </div>
      </div>
    </div>
  );
}

/* ============================================
   Code Panel (right side of endpoint)
   ============================================ */
function CodePanel({ sample, response, lang, onLangChange, onTryIt }) {
  const [tab, setTab] = useState("req"); // req | resp
  const [copied, setCopied] = useState(false);

  const reqCode = useMemo(() => GTI_CODE.generateCode(lang, sample), [lang, sample]);
  const respCode = useMemo(() => GTI_CODE.responseSnippet(response), [response]);

  const displayed = tab === "req" ? reqCode : respCode;
  const html = tab === "req"
    ? GTI_CODE.highlightCode(reqCode, lang)
    : GTI_CODE.highlightJson(respCode);

  const onCopy = () => {
    navigator.clipboard.writeText(displayed).then(() => {
      setCopied(true);
      window.GTI_TOAST?.("Copiado para a área de transferência");
      setTimeout(() => setCopied(false), 1200);
    });
  };

  return (
    <div className="code-panel">
      {tab === "req" ? (
        <div className="code-tabs">
          {GTI_CODE.LANGS.map(l => (
            <button
              key={l.id}
              className={"lang-tab " + (lang === l.id ? "active" : "")}
              onClick={() => onLangChange(l.id)}
            >
              {l.label}
            </button>
          ))}
          <div className="code-toolbar">
            <button className="icon-btn" title="Try it" onClick={onTryIt}>
              <Icon name="play" size={13} />
            </button>
            <button className="icon-btn" title="Copiar" onClick={onCopy}>
              <Icon name={copied ? "check" : "copy"} size={14} />
            </button>
          </div>
        </div>
      ) : (
        <div className="code-tabs">
          <button className="lang-tab active">Response</button>
          <div className="code-toolbar">
            <button className="icon-btn" title="Copiar" onClick={onCopy}>
              <Icon name={copied ? "check" : "copy"} size={14} />
            </button>
          </div>
        </div>
      )}
      <div className="code-body">
        <pre dangerouslySetInnerHTML={{ __html: html }} />
      </div>
      <div className="response-block">
        <div className="response-head" style={{ cursor: "pointer" }} onClick={() => setTab(tab === "req" ? "resp" : "req")}>
          <span style={{ color: "var(--fg-muted)" }}>
            {tab === "req" ? "Ver resposta" : "Ver requisição"}
          </span>
          {tab === "req" && (
            <span className={"status-pill " + statusClass(response.status)}>
              {response.status}
            </span>
          )}
          <span style={{ marginLeft: "auto" }}>
            <Icon name="chev" size={14} />
          </span>
        </div>
      </div>
    </div>
  );
}

function statusClass(code) {
  if (code >= 200 && code < 300) return "s2xx";
  if (code >= 400 && code < 500) return "s4xx";
  return "s5xx";
}

/* ============================================
   Endpoint view
   ============================================ */
function EndpointView({ endpoint, lang, onLangChange, onTryIt }) {
  const { method, path, title, desc, params, response, sample } = endpoint;

  const renderUrl = () => {
    // colorize path variables
    const parts = path.split(/(\{[^}]+\})/g);
    return (
      <span>
        <span className="url-base">{API_DATA.baseUrl.replace(/^https?:\/\//, "")}</span>
        {parts.map((p, i) =>
          p.startsWith("{") ? <span key={i} className="url-var">{p}</span> : <span key={i}>{p}</span>
        )}
      </span>
    );
  };

  return (
    <article className="endpoint" id={"ep-" + path.replace(/\W+/g, "-")}>
      <div className="endpoint-left">
        <h2 className="endpoint-h">{title}</h2>
        <p className="endpoint-desc">{desc}</p>

        <div className="url-row">
          <span className={"url-method " + method.toLowerCase()}>{method}</span>
          <div className="url-path">{renderUrl()}</div>
          <button className="try-btn" onClick={onTryIt}>
            <Icon name="play" size={11} /> &nbsp;Testar
          </button>
        </div>

        {renderParamGroup("Path parameters", params.path)}
        {renderParamGroup("Query parameters", params.query)}
        {renderParamGroup("Body parameters", params.body)}

        {endpoint.note && (
          <div className={"callout " + (endpoint.note.kind || "info")}>
            <Icon name="alert" size={16} />
            <div>
              {endpoint.note.text}
              {endpoint.note.link && (
                <> <a href={endpoint.note.link} target="_blank" rel="noopener">{endpoint.note.link.replace(/^https?:\/\//, "")}</a></>
              )}
            </div>
          </div>
        )}

        <div className="params-h">Headers obrigatórios</div>
        <div className="param">
          <div className="param-key">
            <span className="param-name">Authorization</span>
            <span className="param-type">string</span>
            <div className="param-flags"><span className="param-flag required">obrigatório</span></div>
          </div>
          <div className="param-desc">
            Token de acesso no formato <code className="inline-code">Bearer {`{seu_token}`}</code>.
          </div>
        </div>
        <div className="param">
          <div className="param-key">
            <span className="param-name">Accept</span>
            <span className="param-type">string</span>
            <div className="param-flags"><span className="param-flag required">obrigatório</span></div>
          </div>
          <div className="param-desc">
            <code className="inline-code">application/json</code>
          </div>
        </div>
        {params.body && (
          <div className="param">
            <div className="param-key">
              <span className="param-name">Content-Type</span>
              <span className="param-type">string</span>
              <div className="param-flags"><span className="param-flag required">obrigatório</span></div>
            </div>
            <div className="param-desc">
              <code className="inline-code">application/json</code>
            </div>
          </div>
        )}

        {endpoint.errorResponse && (
          <>
            <div className="params-h">Resposta de erro</div>
            <p className="muted" style={{ fontSize: 13.5, marginBottom: 12 }}>
              Em caso de falha, a API responde com <code className="inline-code">status: "error"</code> e uma mensagem detalhada:
            </p>
            <pre className="code-block">
              <code dangerouslySetInnerHTML={{ __html: GTI_CODE.highlightJson(JSON.stringify(endpoint.errorResponse.body, null, 2)) }} />
            </pre>
          </>
        )}
      </div>

      <div className="endpoint-right">
        <CodePanel
          sample={sample}
          response={response}
          lang={lang}
          onLangChange={onLangChange}
          onTryIt={onTryIt}
        />
      </div>
    </article>
  );
}

function renderParamGroup(label, list) {
  if (!list || !list.length) return null;
  return (
    <>
      <div className="params-h">{label}</div>
      {list.map(p => (
        <div className="param" key={p.name}>
          <div className="param-key">
            <span className="param-name">{p.name}</span>
            <span className="param-type">{p.type}</span>
            <div className="param-flags">
              <span className={"param-flag " + (p.required ? "required" : "optional")}>
                {p.required ? "obrigatório" : "opcional"}
              </span>
            </div>
          </div>
          <div className="param-desc">{p.desc}</div>
        </div>
      ))}
    </>
  );
}

/* ============================================
   Try-it Drawer
   ============================================ */
function TryItDrawer({ endpoint, onClose }) {
  const [token, setToken] = useState("");
  const [pathVars, setPathVars] = useState(() => {
    const out = {};
    (endpoint.params.path || []).forEach(p => { out[p.name] = ""; });
    return out;
  });
  const [queryVars, setQueryVars] = useState(() => {
    const out = {};
    (endpoint.params.query || []).forEach(p => { out[p.name] = ""; });
    return out;
  });
  const [bodyText, setBodyText] = useState(() => {
    return endpoint.sample.body ? JSON.stringify(endpoint.sample.body, null, 2) : "";
  });
  const [busy, setBusy] = useState(false);
  const [resp, setResp] = useState(null);

  const buildUrl = () => {
    let url = API_DATA.baseUrl + endpoint.path;
    Object.entries(pathVars).forEach(([k, v]) => {
      url = url.replace(`{${k}}`, encodeURIComponent(v || `{${k}}`));
    });
    const qs = Object.entries(queryVars).filter(([_, v]) => v).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
    if (qs) url += "?" + qs;
    return url;
  };

  const onSend = async () => {
    setBusy(true);
    setResp(null);
    const url = buildUrl();
    const started = performance.now();

    // SIMULATED RESPONSE — the API endpoint is not callable from the browser
    // (CORS + auth). We mock based on the endpoint's documented response.
    await new Promise(r => setTimeout(r, 420 + Math.random() * 280));

    let simulated;
    if (!token.trim()) {
      simulated = {
        status: 401,
        body: { error: "AUTH_MISSING", message: "Header Authorization ausente." },
      };
    } else if (token.trim().length < 8) {
      simulated = {
        status: 401,
        body: { error: "AUTH_INVALID", message: "Token de acesso inválido ou expirado." },
      };
    } else {
      // Inject body when applicable
      let respBody = JSON.parse(JSON.stringify(endpoint.response.body));
      try {
        const parsed = bodyText ? JSON.parse(bodyText) : null;
        if (parsed && respBody && respBody.data && typeof respBody.data === "object") {
          if (parsed.recipient) respBody.data.to = String(parsed.recipient).split(",")[0].trim();
          if (parsed.message)   respBody.data.message = parsed.message;
        }
      } catch {}
      simulated = { status: endpoint.response.status, body: respBody };
    }

    const elapsed = Math.round(performance.now() - started);
    setResp({ ...simulated, elapsed, url, method: endpoint.method });
    setBusy(false);
  };

  return (
    <>
      <div className="tryit-overlay" onClick={onClose} />
      <aside className="tryit-drawer">
        <div className="tryit-head">
          <span className={"url-method " + endpoint.method.toLowerCase()} style={{ padding: "4px 10px", borderRadius: 4 }}>
            {endpoint.method}
          </span>
          <div className="tryit-title">{endpoint.title}</div>
          <button className="icon-btn" onClick={onClose}><Icon name="close" size={16} /></button>
        </div>
        <div className="tryit-body">
          <div className="callout info">
            <Icon name="alert" size={16} />
            <div>
              Esta é uma execução <strong>simulada</strong> baseada nos exemplos da documentação — usada para preview de UX.
              Chamadas reais à API GTI SMS devem partir do seu backend (não há CORS público).
            </div>
          </div>

          <div className="field">
            <label className="field-label">
              <code>Authorization</code>
              <span style={{ color: "var(--fg-subtle)" }}>· Bearer token</span>
            </label>
            <input
              type="text"
              placeholder="seu_token_de_acesso"
              value={token}
              onChange={(e) => setToken(e.target.value)}
            />
          </div>

          {(endpoint.params.path || []).map(p => (
            <div className="field" key={p.name}>
              <label className="field-label">
                <code>{p.name}</code>
                <span style={{ color: "var(--fg-subtle)" }}>· path · {p.type}</span>
              </label>
              <input
                type="text"
                placeholder={p.desc}
                value={pathVars[p.name]}
                onChange={(e) => setPathVars(v => ({ ...v, [p.name]: e.target.value }))}
              />
            </div>
          ))}

          {(endpoint.params.query || []).map(p => (
            <div className="field" key={p.name}>
              <label className="field-label">
                <code>{p.name}</code>
                <span style={{ color: "var(--fg-subtle)" }}>· query · {p.type}</span>
              </label>
              <input
                type="text"
                placeholder={p.desc}
                value={queryVars[p.name]}
                onChange={(e) => setQueryVars(v => ({ ...v, [p.name]: e.target.value }))}
              />
            </div>
          ))}

          {endpoint.params.body && (
            <div className="field">
              <label className="field-label">
                Body <span style={{ color: "var(--fg-subtle)" }}>· JSON</span>
              </label>
              <textarea
                value={bodyText}
                onChange={(e) => setBodyText(e.target.value)}
                rows={10}
              />
            </div>
          )}

          {resp && (
            <div className="tryit-response">
              <div className="tryit-resp-head">
                <span className={"status-pill " + statusClass(resp.status)}>{resp.status}</span>
                <span style={{ color: "var(--fg-subtle)", fontFamily: "var(--font-mono)" }}>
                  {resp.method} {resp.url.replace(/^https?:\/\//, "")}
                </span>
                <span style={{ marginLeft: "auto", color: "var(--fg-subtle)", fontFamily: "var(--font-mono)" }}>
                  {resp.elapsed}ms
                </span>
              </div>
              <pre className="tryit-resp-body"
                   dangerouslySetInnerHTML={{ __html: GTI_CODE.highlightJson(JSON.stringify(resp.body, null, 2)) }} />
            </div>
          )}
        </div>
        <div className="tryit-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn btn-primary" onClick={onSend} disabled={busy}>
            {busy ? "Enviando…" : <>Enviar requisição <Icon name="send" size={13} /></>}
          </button>
        </div>
      </aside>
    </>
  );
}

/* ============================================
   Overview / intro pages
   ============================================ */
function OverviewPage({ onNavigate }) {
  return (
    <>
      <div className="hero">
        <div className="hero-eyebrow">
          <span className="dot"></span>
          API v3 · ativa
        </div>
        <h1 className="page-title">Documentação da API GTI SMS</h1>
        <p className="page-lede">
          Esta documentação descreve como integrar o envio de SMS via API. O sistema deve realizar
          uma chamada para a nossa URL enviando os parâmetros via <strong>POST</strong> ou <strong>GET</strong>,
          conforme o endpoint. O retorno é sempre um objeto JSON, detalhado em cada seção.
        </p>
        <div style={{ display: "flex", gap: 10 }}>
          <button className="btn btn-primary" onClick={() => onNavigate("send-single")}>
            Começar com um envio <Icon name="chev" size={13} />
          </button>
          <button className="btn" onClick={() => onNavigate("auth")}>
            Autenticação
          </button>
        </div>
      </div>

      <div className="feature-grid">
        {[
          { i: "send",   t: "Enviar SMS",            d: "Envio direto a um ou múltiplos números separados por vírgula.", id: "send-single" },
          { i: "book",   t: "Envio para grupos",     d: "Disparo para um grupo de contatos via ID, cadastrado no painel.", id: "send-campaign" },
          { i: "gauge",  t: "Status / DLR",          d: "Consulte o status de uma mensagem pelo UID ou liste por período.", id: "status-uid" },
          { i: "wallet", t: "Saldo de créditos",     d: "Consulte créditos restantes e data de expiração da sua conta.",   id: "balance" },
        ].map(f => (
          <div className="feature" key={f.t} onClick={() => onNavigate(f.id)}>
            <div className="feature-icon"><Icon name={f.i} size={16} /></div>
            <div className="feature-title">{f.t}</div>
            <div className="feature-desc">{f.d}</div>
          </div>
        ))}
      </div>

      <h2 className="section-h">Quickstart</h2>
      <p>Em 3 passos você envia seu primeiro SMS:</p>

      <div className="quickstart">
        <ol className="quickstart-steps">
          <li>
            <strong>Obtenha seu token</strong> de acesso na página{" "}
            <a href={API_DATA.developersUrl} target="_blank" rel="noopener">{API_DATA.developersUrl.replace(/^https?:\/\//, "")}</a>.
          </li>
          <li>
            <strong>Configure os headers</strong> em todas as suas requisições:
            <pre className="code-block" style={{ marginTop: 10, padding: 12, fontSize: 12.5 }}>
<code><span className="tok-prop">Authorization</span>: <span className="tok-kw">Bearer</span> <span className="tok-str">SEU_TOKEN</span>
<span className="tok-prop">Content-Type</span>: <span className="tok-str">application/json</span>
<span className="tok-prop">Accept</span>: <span className="tok-str">application/json</span></code>
            </pre>
          </li>
          <li>
            <strong>Faça o primeiro envio</strong> chamando <code className="inline-code">POST /sms/send</code> com os campos{" "}
            <code className="inline-code">recipient</code> e <code className="inline-code">message</code>.
            <div style={{ marginTop: 10 }}>
              <button className="btn btn-primary" onClick={() => onNavigate("send-single")}>Ver endpoint de envio</button>
            </div>
          </li>
        </ol>
      </div>

      <h2 className="section-h">Formato de resposta</h2>
      <p>Toda resposta da API retorna um JSON com a seguinte estrutura:</p>
      <pre className="code-block">
        <code dangerouslySetInnerHTML={{ __html: GTI_CODE.highlightJson(JSON.stringify({
          status: "success",
          message: "Sua mensagem foi enviada com sucesso!",
          data: { "...": "payload específico do endpoint" }
        }, null, 2)) }} />
      </pre>
      <p className="muted" style={{ fontSize: 14 }}>
        O campo <code className="inline-code">status</code> é sempre <code className="inline-code">"success"</code> ou <code className="inline-code">"error"</code>.
        Em caso de erro, <code className="inline-code">data</code> é omitido e <code className="inline-code">message</code> traz a descrição do problema.
      </p>

      <h2 className="section-h">Regras de mensagem</h2>
      <div className="callout warn">
        <Icon name="alert" size={16} />
        <div>
          A mensagem deve ter <strong>até 160 caracteres</strong> e <strong>não pode conter</strong> emojis,
          acentos ou outros caracteres especiais. Caracteres fora do padrão GSM-7 podem causar falha no envio.
        </div>
      </div>
    </>
  );
}

function AuthPage() {
  const sample = {
    method: "GET",
    url: API_DATA.baseUrl + "/balance",
    body: null,
  };
  return (
    <>
      <div className="crumbs"><span>Começando</span><span className="sep">/</span><span>Autenticação</span></div>
      <h1 className="page-title">Autenticação</h1>
      <p className="page-lede">
        A API GTI SMS usa autenticação do tipo <strong>Bearer</strong>. O token é informado na página{" "}
        <a href={API_DATA.developersUrl} target="_blank" rel="noopener">{API_DATA.developersUrl.replace(/^https?:\/\//, "")}</a>.
      </p>

      <h2 className="section-h">Headers obrigatórios</h2>
      <p>Inclua estes headers em <strong>todas</strong> as chamadas:</p>
      <pre className="code-block">
<code><span className="tok-prop">Authorization</span>: <span className="tok-kw">Bearer</span> <span className="tok-str">SEU_TOKEN</span>
<span className="tok-prop">Content-Type</span>: <span className="tok-str">application/json</span>
<span className="tok-prop">Accept</span>: <span className="tok-str">application/json</span></code>
      </pre>

      <div className="callout warn">
        <Icon name="alert" size={16} />
        <div>
          Nunca exponha seu token no front-end. Faça as chamadas a partir do seu backend.
          Em caso de vazamento, gere um novo token no painel.
        </div>
      </div>

      <h2 className="section-h">Como obter o token</h2>
      <ol style={{ color: "var(--fg)", lineHeight: 1.8 }}>
        <li>Acesse <a href={API_DATA.developersUrl} target="_blank" rel="noopener">{API_DATA.developersUrl.replace(/^https?:\/\//, "")}</a> com sua conta GTI SMS.</li>
        <li>Gere ou copie o token de acesso disponível na página.</li>
        <li>Use o token no header <code className="inline-code">Authorization</code> no formato <code className="inline-code">Bearer SEU_TOKEN</code>.</li>
      </ol>

      <h2 className="section-h">Testando seu token</h2>
      <p>O endpoint mais simples para validar a autenticação é <code className="inline-code">GET /balance</code>:</p>
      <div style={{ marginTop: 16 }}>
        <CodePanel
          sample={sample}
          response={{ status: 200, body: { status: "success", message: null, data: { remaining_balance: "100", expired_on: "26/01/3025, 17:09" } } }}
          lang="curl"
          onLangChange={() => {}}
          onTryIt={() => window.GTI_NAV?.("balance")}
        />
      </div>
    </>
  );
}

function ErrorsPage() {
  return (
    <>
      <div className="crumbs"><span>Começando</span><span className="sep">/</span><span>Erros e respostas</span></div>
      <h1 className="page-title">Erros e respostas</h1>
      <p className="page-lede">
        Toda chamada à API retorna um JSON com o campo <code className="inline-code">status</code> indicando
        <strong> success</strong> ou <strong>error</strong>. Em caso de erro, o campo <code className="inline-code">message</code> traz a descrição detalhada do problema.
      </p>

      <h2 className="section-h">Resposta de sucesso</h2>
      <pre className="code-block">
        <code dangerouslySetInnerHTML={{ __html: GTI_CODE.highlightJson(JSON.stringify({
          status: "success",
          message: "Sua mensagem foi enviada com sucesso!",
          data: { "...": "payload do endpoint" }
        }, null, 2)) }} />
      </pre>

      <h2 className="section-h">Resposta de erro</h2>
      <pre className="code-block">
        <code dangerouslySetInnerHTML={{ __html: GTI_CODE.highlightJson(JSON.stringify({
          status: "error",
          message: "Mensagem de erro detalhada"
        }, null, 2)) }} />
      </pre>

      <h2 className="section-h">Valores de <code className="inline-code">data.status</code> nas mensagens</h2>
      <p className="muted" style={{ fontSize: 14, marginBottom: 12 }}>
        Estados possíveis para uma mensagem SMS retornados nos endpoints de envio e consulta de status:
      </p>
      <div style={{ border: "1px solid var(--border)", borderRadius: 8, overflow: "hidden" }}>
        {API_DATA.smsStatuses.map((st, idx) => (
          <div key={st.value} style={{
            display: "grid",
            gridTemplateColumns: "160px 1fr",
            gap: 16,
            padding: "12px 16px",
            borderBottom: idx < API_DATA.smsStatuses.length - 1 ? "1px solid var(--border)" : "none",
            background: idx % 2 === 0 ? "transparent" : "var(--bg-elev-1)",
            alignItems: "center",
          }}>
            <span className={"status-pill " + (
              st.tone === "success" ? "s2xx" : st.tone === "danger" ? "s5xx" : "s4xx"
            )} style={{ width: "fit-content" }}>{st.value}</span>
            <span style={{ color: "var(--fg-muted)", fontSize: 13.5 }}>{st.desc}</span>
          </div>
        ))}
      </div>

      <h2 className="section-h">Causas comuns de erro</h2>
      <ul style={{ color: "var(--fg)", lineHeight: 1.8 }}>
        <li><strong>Token inválido ou ausente:</strong> verifique o header <code className="inline-code">Authorization: Bearer SEU_TOKEN</code>.</li>
        <li><strong>Sem créditos:</strong> consulte o saldo em <code className="inline-code">GET /balance</code>.</li>
        <li><strong>Número inválido:</strong> o destinatário deve estar no formato internacional, sem espaços ou símbolos. Ex.: <code className="inline-code">5511988887777</code>.</li>
        <li><strong>Mensagem com caracteres inválidos:</strong> emojis, acentos e caracteres especiais não são aceitos.</li>
        <li><strong>Mensagem muito longa:</strong> o limite é de 160 caracteres.</li>
      </ul>
    </>
  );
}

function RateLimitsPage() {
  return (
    <>
      <div className="crumbs"><span>Começando</span><span className="sep">/</span><span>Rate limits</span></div>
      <h1 className="page-title">Rate limits</h1>
      <p className="page-lede">
        Cada conta tem um limite de requisições por segundo. Excedê-lo retorna <code className="inline-code">429 RATE_LIMITED</code>
        com header <code className="inline-code">Retry-After</code> indicando quantos segundos aguardar.
      </p>

      <h2 className="section-h">Limites por plano</h2>
      <div style={{ border: "1px solid var(--border)", borderRadius: 8, overflow: "hidden" }}>
        {[
          { plan: "Starter",  rps: "20 req/s",  burst: "40 req em 2s" },
          { plan: "Business", rps: "100 req/s", burst: "200 req em 2s" },
          { plan: "Scale",    rps: "500 req/s", burst: "1.000 req em 2s" },
          { plan: "Enterprise", rps: "Custom",  burst: "Sob acordo" },
        ].map((row, i) => (
          <div key={row.plan} style={{
            display: "grid",
            gridTemplateColumns: "1fr 1fr 1fr",
            gap: 16,
            padding: "12px 16px",
            borderBottom: i < 3 ? "1px solid var(--border)" : "none",
            background: i % 2 === 0 ? "transparent" : "var(--bg-elev-1)",
            fontSize: 13.5,
          }}>
            <strong>{row.plan}</strong>
            <span style={{ fontFamily: "var(--font-mono)", color: "var(--fg-muted)" }}>{row.rps}</span>
            <span style={{ fontFamily: "var(--font-mono)", color: "var(--fg-muted)" }}>{row.burst}</span>
          </div>
        ))}
      </div>

      <h2 className="section-h">Headers de resposta</h2>
      <p>Toda resposta inclui:</p>
      <ul style={{ color: "var(--fg-muted)", lineHeight: 1.8 }}>
        <li><code className="inline-code">X-RateLimit-Limit</code> — limite total por segundo</li>
        <li><code className="inline-code">X-RateLimit-Remaining</code> — quantas requisições restam na janela</li>
        <li><code className="inline-code">X-RateLimit-Reset</code> — timestamp UTC do reset da janela</li>
      </ul>

      <div className="callout success">
        <Icon name="bolt" size={16} />
        <div>
          <strong>Dica:</strong> implemente <em>exponential backoff</em> ao receber 429. Os SDKs oficiais já fazem isso automaticamente.
        </div>
      </div>
    </>
  );
}

/* ============================================
   Main App
   ============================================ */
function App() {
  // Read initial id from URL hash, default to overview
  const [currentId, setCurrentId] = useState(() => {
    const h = (location.hash || "").replace(/^#/, "");
    return h || "overview";
  });
  const [lang, setLang] = useState(() => localStorage.getItem("gti-lang") || "curl");
  const [theme, setTheme] = useState(() => {
    const saved = localStorage.getItem("gti-theme");
    if (saved === "dark" || saved === "light") return saved;
    // Default to user's OS preference
    return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  });
  const [searchOpen, setSearchOpen] = useState(false);
  const [tryItOpen, setTryItOpen] = useState(false);
  const [toast, setToast] = useState(null);
  const toastTimer = useRef(null);

  useEffect(() => {
    localStorage.setItem("gti-lang", lang);
  }, [lang]);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
    localStorage.setItem("gti-theme", theme);
  }, [theme]);

  const toggleTheme = useCallback(() => {
    setTheme(t => t === "dark" ? "light" : "dark");
  }, []);

  // expose helpers
  useEffect(() => {
    window.GTI_NAV = (id) => navigate(id);
    window.GTI_TOAST = (msg) => {
      setToast(msg);
      clearTimeout(toastTimer.current);
      toastTimer.current = setTimeout(() => setToast(null), 1600);
    };
  });

  const navigate = useCallback((id) => {
    setCurrentId(id);
    setTryItOpen(false);
    history.replaceState(null, "", "#" + id);
    // scroll content to top
    document.querySelector(".main")?.scrollTo?.({ top: 0 });
    window.scrollTo({ top: 0, behavior: "instant" });
  }, []);

  // Cmd+K
  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setSearchOpen(true);
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  // Resolve current item
  const currentItem = useMemo(() => {
    for (const g of API_DATA.groups) {
      for (const it of g.items) {
        if (it.id === currentId) return it;
      }
    }
    return null;
  }, [currentId]);

  const endpoint = currentItem?.kind === "endpoint" ? API_DATA.endpoints[currentId] : null;

  return (
    <div className="app">
      <TopBar onOpenSearch={() => setSearchOpen(true)} theme={theme} onToggleTheme={toggleTheme} />
      <Sidebar current={currentId} onNavigate={navigate} />
      <main className="main">
        {currentId === "overview"    && <OverviewPage onNavigate={navigate} />}
        {currentId === "auth"        && <AuthPage />}
        {currentId === "errors"      && <ErrorsPage />}
        {endpoint && (
          <EndpointView
            key={currentId}
            endpoint={endpoint}
            lang={lang}
            onLangChange={setLang}
            onTryIt={() => setTryItOpen(true)}
          />
        )}
      </main>

      <SearchModal open={searchOpen} onClose={() => setSearchOpen(false)} onNavigate={navigate} />
      {tryItOpen && endpoint && (
        <TryItDrawer endpoint={endpoint} onClose={() => setTryItOpen(false)} />
      )}
      {toast && <div className="toast">{toast}</div>}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
