<?php
$games = is_array($games ?? null) ? $games : [];
$defaultGameCode = (string)($default_game_code ?? 'PUBG');
$isPublicMode = !empty($is_public_mode);
if ($defaultGameCode === '') {
    $defaultGameCode = 'PUBG';
}
?>

<style>
  .connect-doc-card {
    margin-bottom: 18px;
    border-radius: 12px;
  }
  .connect-doc-card .card-header h4 {
    margin: 0;
    font-weight: 700;
  }
  .connect-doc-muted {
    color: #667085;
  }
  .connect-doc-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
  }
  .connect-doc-code {
    position: relative;
  }
  .connect-doc-code pre {
    margin: 0;
    white-space: pre;
    word-break: normal;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    border-radius: 10px;
    background: #0f172a;
    color: #e2e8f0;
    padding: 14px;
    min-height: 118px;
  }
  .connect-doc-copy {
    position: absolute;
    top: 10px;
    right: 10px;
    border: 0;
    border-radius: 8px;
    background: rgba(255,255,255,.12);
    color: #fff;
    padding: 6px 10px;
    font-size: 12px;
  }
  .connect-doc-inline {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
  }
  .connect-doc-inline code {
    flex: 1 1 420px;
    word-break: break-all;
  }
  .connect-doc-inline-copy {
    border: 0;
    border-radius: 8px;
    background: #2563eb;
    color: #fff;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
  }
  .connect-doc-inline-copy:hover,
  .connect-doc-inline-copy:focus {
    opacity: .92;
  }
  .connect-doc-table th {
    width: 190px;
    white-space: nowrap;
  }
  .connect-doc-table td {
    word-break: break-word;
  }
  .connect-doc-list,
  .connect-doc-number {
    margin: 0;
    padding-left: 18px;
  }
  .connect-doc-list li,
  .connect-doc-number li {
    margin-bottom: 7px;
  }
  .connect-doc-tag {
    display: inline-block;
    margin-right: 8px;
    margin-bottom: 8px;
    padding: 4px 10px;
    border-radius: 999px;
    background: #eef4ff;
    color: #2856a6;
    font-size: 12px;
    font-weight: 600;
  }
  .connect-doc-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 10px 14px;
    border-radius: 10px;
    background: #2563eb;
    color: #fff;
    text-decoration: none;
    font-weight: 600;
  }
  .connect-doc-action:hover,
  .connect-doc-action:focus {
    color: #fff;
    text-decoration: none;
    opacity: .92;
  }
  .connect-doc-url-card .connect-doc-inline code {
    font-size: 14px;
  }

  @media (max-width: 991px) {
    .connect-doc-grid {
      grid-template-columns: 1fr;
    }
  }

  @media (max-width: 767px) {
    .connect-doc-card {
      margin-bottom: 14px;
    }
    .connect-doc-card .card-header h4 {
      font-size: 16px;
      line-height: 1.35;
    }
    .connect-doc-card .card-body {
      padding: 12px;
    }
    .connect-doc-grid {
      gap: 10px;
    }
    .connect-doc-inline {
      flex-direction: column;
      align-items: stretch;
    }
    .connect-doc-inline code {
      flex: 1 1 auto;
      width: 100%;
    }
    .connect-doc-inline-copy,
    .connect-doc-action,
    .connect-doc-copy {
      width: 100%;
    }
    .connect-doc-copy {
      position: static;
      margin-bottom: 8px;
    }
    .connect-doc-code {
      padding-top: 0;
    }
    .connect-doc-code pre {
      min-height: auto;
      max-height: 320px;
      padding: 12px;
      font-size: 12px;
      line-height: 1.55;
    }
    .connect-doc-table,
    .connect-doc-table tbody,
    .connect-doc-table tr,
    .connect-doc-table th,
    .connect-doc-table td {
      display: block;
      width: 100%;
    }
    .connect-doc-table thead {
      display: none;
    }
    .connect-doc-table tr {
      margin-bottom: 12px;
      border: 1px solid #e7edf5;
      border-radius: 12px;
      overflow: hidden;
      background: #fff;
    }
    .connect-doc-table th {
      white-space: normal;
      padding: 10px 12px;
      border-bottom: 1px solid #e7edf5;
      background: #f8fbff;
    }
    .connect-doc-table td {
      padding: 10px 12px;
      border-top: 0;
    }
    .form-group {
      max-width: 100% !important;
    }
  }
</style>

<div class="row">
  <div class="col-md-12">
    <div class="card connect-doc-card">
      <div class="card-header">
        <h4><?= e(app_zh('对接示例与接入指南')) ?></h4>
      </div>
      <div class="card-body">
        <p class="connect-doc-muted">
          <?= e(app_zh('本页现在以 C++ 对接为主，优先给你能直接拿去改的 libcurl 与 WinHTTP 示例。查卡、解绑、自助查卡页面也都放在这里，方便你统一联调。')) ?>
        </p>
        <div class="alert alert-info" style="margin-bottom:16px;">
          <?php if ($isPublicMode): ?>
            <?= e(app_zh('当前站点已指向 public，下面展示的是可以直接调用的标准地址。老式面板、旧启动器和现有 C++ 客户端只需要替换域名即可无缝衔接。')) ?>
          <?php else: ?>
            <?= e(app_zh('当前站点未指向 public，下面只展示 index.php?r=... 这一套兼容地址。老式面板、旧启动器和现有 C++ 客户端可以直接沿用这套地址，无需额外改路由。')) ?>
          <?php endif; ?>
        </div>

        <div class="form-group" style="max-width:360px;">
          <label><?= e(app_zh('选择示例游戏代码')) ?></label>
          <select class="form-control" id="connect-game-select">
            <?php foreach ($games as $code => $game): ?>
              <option value="<?= e((string)$code) ?>" <?= (string)$code === $defaultGameCode ? 'selected' : '' ?>>
                <?= e((string)($game['name'] ?? $code)) ?> (<?= e((string)$code) ?>)
              </option>
            <?php endforeach; ?>
          </select>
        </div>

        <div>
          <span class="connect-doc-tag">C++</span>
          <span class="connect-doc-tag">libcurl</span>
          <span class="connect-doc-tag">WinHTTP</span>
          <span class="connect-doc-tag">conncet</span>
          <span class="connect-doc-tag">API v1</span>
          <span class="connect-doc-tag"><?= e(app_zh('查卡 / 解绑')) ?></span>
          <span class="connect-doc-tag"><?= e(app_zh('自助查卡页')) ?></span>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="card connect-doc-card connect-doc-url-card">
      <div class="card-header">
        <h4><?= e(app_zh('当前 conncet 登录地址')) ?></h4>
      </div>
      <div class="card-body">
        <div class="connect-doc-inline">
          <code id="connect-login-url-preview"><?= e((string)($connect_post_url ?? '')) ?></code>
          <button class="connect-doc-inline-copy" type="button" data-copy-text-target="connect-login-url-preview"><?= e(app_zh('复制地址')) ?></button>
        </div>
        <p class="connect-doc-muted" style="margin:10px 0 0;">
          <?= e(app_zh('这个地址会根据当前站点是否指向 public 自动切换。老式面板、旧启动器和现有 C++ 客户端都可以直接复制使用，不需要改接口参数。')) ?>
        </p>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="card connect-doc-card">
      <div class="card-header">
        <h4><?= e(app_zh('地址一览')) ?></h4>
      </div>
      <div class="card-body table-responsive">
        <table class="table table-bordered table-hover connect-doc-table">
          <tbody>
            <tr>
              <th><?= e(app_zh('兼容接口登录')) ?></th>
              <td>
                <div class="connect-doc-inline">
                  <code id="connect-post-url-text"><?= e((string)($connect_post_url ?? '')) ?></code>
                  <button class="connect-doc-inline-copy" type="button" data-copy-text-target="connect-post-url-text"><?= e(app_zh('复制地址')) ?></button>
                </div>
              </td>
            </tr>
            <tr>
              <th><?= e(app_zh('标准 API 心跳')) ?></th>
              <td>
                <div class="connect-doc-inline">
                  <code id="api-ping-url-text"><?= e((string)($api_ping_url ?? '')) ?></code>
                  <button class="connect-doc-inline-copy" type="button" data-copy-text-target="api-ping-url-text"><?= e(app_zh('复制地址')) ?></button>
                </div>
              </td>
            </tr>
            <tr>
              <th><?= e(app_zh('标准 API 登录')) ?></th>
              <td>
                <div class="connect-doc-inline">
                  <code id="api-login-url-text"><?= e((string)($api_login_url ?? '')) ?></code>
                  <button class="connect-doc-inline-copy" type="button" data-copy-text-target="api-login-url-text"><?= e(app_zh('复制地址')) ?></button>
                </div>
              </td>
            </tr>
            <tr>
              <th><?= e(app_zh('卡密查询 API')) ?></th>
              <td>
                <div class="connect-doc-inline">
                  <code id="api-query-url-text"><?= e((string)($api_query_url ?? '')) ?></code>
                  <button class="connect-doc-inline-copy" type="button" data-copy-text-target="api-query-url-text"><?= e(app_zh('复制地址')) ?></button>
                </div>
              </td>
            </tr>
            <tr>
              <th><?= e(app_zh('解绑设备 API')) ?></th>
              <td>
                <div class="connect-doc-inline">
                  <code id="api-unbind-url-text"><?= e((string)($api_unbind_url ?? '')) ?></code>
                  <button class="connect-doc-inline-copy" type="button" data-copy-text-target="api-unbind-url-text"><?= e(app_zh('复制地址')) ?></button>
                </div>
              </td>
            </tr>
            <tr>
              <th><?= e(app_zh('用户自助查卡页')) ?></th>
              <td>
                <div class="connect-doc-inline">
                  <code id="query-page-url-text"><?= e((string)($query_page_url ?? '')) ?></code>
                  <button class="connect-doc-inline-copy" type="button" data-copy-text-target="query-page-url-text"><?= e(app_zh('复制地址')) ?></button>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('接口参数')) ?></h4>
        </div>
        <div class="card-body table-responsive">
          <table class="table table-bordered table-hover connect-doc-table">
            <tbody>
              <tr>
                <th>game</th>
                <td><?= e(app_zh('游戏代码，例如 PUBG。登录接口必传，必须和后台卡密对应。')) ?></td>
              </tr>
              <tr>
                <th>user_key / key</th>
                <td><?= e(app_zh('卡密本身。兼容接口和标准 API 都支持。')) ?></td>
              </tr>
              <tr>
                <th>serial</th>
                <td><?= e(app_zh('设备码，必传。后端会按设备码记录绑定设备，并严格校验设备数量上限。')) ?></td>
              </tr>
              <tr>
                <th>X-API-TOKEN</th>
                <td><?= e(app_zh('推荐写法。查卡与解绑接口使用这个请求头。')) ?></td>
              </tr>
              <tr>
                <th>X-API-KEY</th>
                <td><?= e(app_zh('兼容写法。现在也会被识别，方便老工具直接沿用。')) ?></td>
              </tr>
              <tr>
                <th>Authorization</th>
                <td><?= e(app_zh('也支持 Bearer TOKEN。适合你统一 SDK 鉴权头。')) ?></td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('查卡与售后建议')) ?></h4>
        </div>
        <div class="card-body table-responsive">
          <table class="table table-bordered table-hover connect-doc-table">
            <tbody>
              <tr>
                <th><?= e(app_zh('玩家端登录')) ?></th>
                <td><?= e(app_zh('优先用 conncet 或 API v1/login，拿 token、到期时间和公告内容。')) ?></td>
              </tr>
              <tr>
                <th><?= e(app_zh('用户查卡')) ?></th>
                <td><?= e(app_zh('优先给用户用自助查卡页面，不建议把 API Token 直接塞进客户端。')) ?></td>
              </tr>
              <tr>
                <th><?= e(app_zh('售后查卡')) ?></th>
                <td><?= e(app_zh('服务端中转调用 /api/v1/key/query，返回卡密状态、设备数、设备列表。')) ?></td>
              </tr>
              <tr>
                <th><?= e(app_zh('设备解绑')) ?></th>
                <td><?= e(app_zh('如果站点开启了自助解绑，可调用 /api/v1/key/unbind；否则请走后台操作。')) ?></td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('推荐联调顺序')) ?></h4>
        </div>
        <div class="card-body">
          <ol class="connect-doc-number">
            <li><?= e(app_zh('先请求心跳接口，确认域名、HTTPS 和服务器返回正常。')) ?></li>
            <li><?= e(app_zh('再用一条真实卡密测试 conncet 或 API v1/login，先跑通验证主链路。')) ?></li>
            <li><?= e(app_zh('确认客户端能收到 token、serial_used、BHATIA_EXP、公告字段。')) ?></li>
            <li><?= e(app_zh('最后再接查卡和解绑接口，这样排错最清楚。')) ?></li>
          </ol>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('上线前自查')) ?></h4>
        </div>
        <div class="card-body">
          <ul class="connect-doc-list">
            <li><?= e(app_zh('确认当前站点已通过云端授权，否则登录接口会返回站点未授权。')) ?></li>
            <li><?= e(app_zh('确认 game 代码和后台创建卡密时的游戏代码一致。')) ?></li>
            <li><?= e(app_zh('查卡与解绑接口统一使用 POST，不要直接拿浏览器 GET 去测。')) ?></li>
            <li><?= e(app_zh('查卡接口如果要外放，请优先走你自己的服务端中转。')) ?></li>
          </ul>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('C++ 对接 conncet（libcurl）')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="connect-cpp-curl-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="connect-cpp-curl-demo"><code></code></pre>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('C++ 对接 conncet（WinHTTP）')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="connect-cpp-winhttp-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="connect-cpp-winhttp-demo"><code></code></pre>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('C++ 标准 API 登录（JSON）')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="api-login-cpp-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="api-login-cpp-demo"><code></code></pre>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('C++ 查卡 / 解绑（libcurl）')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="api-query-cpp-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="api-query-cpp-demo"><code></code></pre>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('快速测试 conncet（curl）')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="connect-curl-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="connect-curl-demo"><code></code></pre>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('服务端中转查卡（PHP）')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="proxy-query-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="proxy-query-demo"><code></code></pre>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('用户自助查卡页面')) ?></h4>
        </div>
        <div class="card-body">
          <p class="connect-doc-muted">
            <?= e(app_zh('登录页里的查卡入口已经拿掉了。如果你要给用户一个现成的查卡界面，直接把下面这个页面地址放到菜单、帮助中心或公告页即可。')) ?>
          </p>
          <p><code id="query-page-url-preview"><?= e((string)($query_page_url ?? '')) ?></code></p>
          <p style="margin-bottom:14px;">
            <a class="connect-doc-action" id="query-page-link" href="<?= e((string)($query_page_url ?? '')) ?>" target="_blank" rel="noopener noreferrer"><?= e(app_zh('打开查卡页面')) ?></a>
          </p>
          <div class="connect-doc-code">
            <button class="connect-doc-copy" data-copy-target="query-page-demo"><?= e(app_zh('复制')) ?></button>
            <pre id="query-page-demo"><code></code></pre>
          </div>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('查卡成功返回示例')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="query-success-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="query-success-demo"><code></code></pre>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="connect-doc-grid">
      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('登录成功返回示例')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="success-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="success-demo"><code></code></pre>
        </div>
      </div>

      <div class="card connect-doc-card">
        <div class="card-header">
          <h4><?= e(app_zh('常见失败返回示例')) ?></h4>
        </div>
        <div class="card-body connect-doc-code">
          <button class="connect-doc-copy" data-copy-target="fail-demo"><?= e(app_zh('复制')) ?></button>
          <pre id="fail-demo"><code></code></pre>
        </div>
      </div>
    </div>
  </div>

  <div class="col-md-12">
    <div class="card connect-doc-card">
      <div class="card-header">
        <h4><?= e(app_zh('排错提示')) ?></h4>
      </div>
      <div class="card-body">
        <ul class="connect-doc-list">
          <li><?= e(app_zh('提示卡密不存在：先确认 game 代码、user_key 和后台卡密归属是否一致。')) ?></li>
          <li><?= e(app_zh('提示设备数量已达上限：说明卡密绑定设备已满，可在后台或自助查卡页处理。')) ?></li>
          <li><?= e(app_zh('查卡接口返回未授权访问：优先检查 X-API-TOKEN / X-API-KEY / Bearer 头是否正确。')) ?></li>
          <li><?= e(app_zh('查卡接口如果直连客户端不稳定，建议改成服务端中转，由你自己的服务端再去调平台 API。')) ?></li>
          <li><?= e(app_zh('serial 现在必须传真实设备码，否则登录会被直接拦截。建议先在客户端稳定生成设备码，再对接登录流程。')) ?></li>
        </ul>
      </div>
    </div>
  </div>
</div>

<script>
(function () {
  var connectUrl = <?= app_json_for_html((string)($connect_post_url ?? '')) ?>;
  var apiPingUrl = <?= app_json_for_html((string)($api_ping_url ?? '')) ?>;
  var apiLoginUrl = <?= app_json_for_html((string)($api_login_url ?? '')) ?>;
  var apiQueryUrl = <?= app_json_for_html((string)($api_query_url ?? '')) ?>;
  var apiUnbindUrl = <?= app_json_for_html((string)($api_unbind_url ?? '')) ?>;
  var queryPageUrl = <?= app_json_for_html((string)($query_page_url ?? '')) ?>;
  var defaultGameCode = <?= app_json_for_html($defaultGameCode) ?>;
  var copiedText = <?= app_json_for_html(app_zh('已复制')) ?>;
  var select = document.getElementById('connect-game-select');

  function sameOriginUrl(url) {
    if (!url) {
      return url;
    }
    try {
      var parsed = new URL(url, window.location.href);
      return window.location.origin + parsed.pathname + parsed.search + parsed.hash;
    } catch (error) {
      return url;
    }
  }

  connectUrl = sameOriginUrl(connectUrl);
  apiPingUrl = sameOriginUrl(apiPingUrl);
  apiLoginUrl = sameOriginUrl(apiLoginUrl);
  apiQueryUrl = sameOriginUrl(apiQueryUrl);
  apiUnbindUrl = sameOriginUrl(apiUnbindUrl);
  queryPageUrl = sameOriginUrl(queryPageUrl);

  function setText(id, text) {
    var el = document.getElementById(id);
    if (el) {
      el.textContent = text;
    }
  }

  function setCode(id, text) {
    var el = document.querySelector('#' + id + ' code');
    if (el) {
      el.textContent = text;
    }
  }

  function gameCode() {
    return select ? (select.value || defaultGameCode) : defaultGameCode;
  }

  function fallbackCopy(text) {
    var textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.setAttribute('readonly', 'readonly');
    textarea.style.position = 'fixed';
    textarea.style.opacity = '0';
    document.body.appendChild(textarea);
    textarea.select();
    try {
      document.execCommand('copy');
    } catch (error) {
      document.body.removeChild(textarea);
      return false;
    }
    document.body.removeChild(textarea);
    return true;
  }

  function copyText(text, onSuccess) {
    if (!text) {
      return;
    }
    if (navigator.clipboard && window.isSecureContext) {
      navigator.clipboard.writeText(text).then(onSuccess).catch(function () {
        if (fallbackCopy(text)) {
          onSuccess();
        }
      });
      return;
    }
    if (fallbackCopy(text)) {
      onSuccess();
    }
  }

  function render() {
    var code = gameCode();

    setText('connect-post-url-text', connectUrl);
    setText('connect-login-url-preview', connectUrl);
    setText('api-ping-url-text', apiPingUrl);
    setText('api-login-url-text', apiLoginUrl);
    setText('api-query-url-text', apiQueryUrl);
    setText('api-unbind-url-text', apiUnbindUrl);
    setText('query-page-url-text', queryPageUrl);
    setText('query-page-url-preview', queryPageUrl);
    var queryPageLink = document.getElementById('query-page-link');
    if (queryPageLink) {
      queryPageLink.href = queryPageUrl;
    }

    setCode('connect-cpp-curl-demo', [
      '#include <curl/curl.h>',
      '#include <iostream>',
      '#include <string>',
      '',
      'static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {',
      '    ((std::string*)userp)->append((char*)contents, size * nmemb);',
      '    return size * nmemb;',
      '}',
      '',
      'int main() {',
      '    CURL* curl = curl_easy_init();',
      '    if (!curl) return 1;',
      '',
      '    std::string response;',
      '    std::string postFields = "game=' + code + '&user_key=YOUR_KEY&serial=REAL_MACHINE_CODE";',
      '',
      '    curl_easy_setopt(curl, CURLOPT_URL, "' + connectUrl + '");',
      '    curl_easy_setopt(curl, CURLOPT_POST, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());',
      '    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3L);',
      '    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);',
      '    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);',
      '    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);',
      '    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L);',
      '',
      '    CURLcode res = curl_easy_perform(curl);',
      '    long httpCode = 0;',
      '    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);',
      '    curl_easy_cleanup(curl);',
      '',
      '    if (res != CURLE_OK) {',
      '        std::cerr << "request failed: " << curl_easy_strerror(res) << std::endl;',
      '        return 1;',
      '    }',
      '    if (httpCode != 200) {',
      '        std::cerr << "http status: " << httpCode << "\\n" << response << std::endl;',
      '        return 1;',
      '    }',
      '    if (response.empty() || response[0] != \'{\') {',
      '        std::cerr << "non-json response:\\n" << response << std::endl;',
      '        return 1;',
      '    }',
      '',
      '    std::cout << response << std::endl;',
      '    return 0;',
      '}'
    ].join('\n'));

    setCode('connect-cpp-winhttp-demo', [
      '#include <windows.h>',
      '#include <winhttp.h>',
      '#include <iostream>',
      '#pragma comment(lib, "winhttp.lib")',
      '',
      'int main() {',
      '    URL_COMPONENTS parts = {0};',
      '    wchar_t host[256] = {0};',
      '    wchar_t path[1024] = {0};',
      '    std::wstring url = L"' + connectUrl.replace(/\\/g, '\\\\') + '";',
      '    std::string body = "game=' + code + '&user_key=YOUR_KEY&serial=REAL_MACHINE_CODE";',
      '',
      '    parts.dwStructSize = sizeof(parts);',
      '    parts.lpszHostName = host;',
      '    parts.dwHostNameLength = 255;',
      '    parts.lpszUrlPath = path;',
      '    parts.dwUrlPathLength = 1023;',
      '    WinHttpCrackUrl(url.c_str(), 0, 0, &parts);',
      '',
      '    HINTERNET hSession = WinHttpOpen(L"LightYear/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0);',
      '    HINTERNET hConnect = WinHttpConnect(hSession, host, parts.nPort, 0);',
      '    HINTERNET hRequest = WinHttpOpenRequest(',
      '        hConnect,',
      '        L"POST",',
      '        path,',
      '        NULL,',
      '        WINHTTP_NO_REFERER,',
      '        WINHTTP_DEFAULT_ACCEPT_TYPES,',
      '        parts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0',
      '    );',
      '',
      '    DWORD redirectPolicy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;',
      '    WinHttpSetOption(hRequest, WINHTTP_OPTION_REDIRECT_POLICY, &redirectPolicy, sizeof(redirectPolicy));',
      '',
      '    WinHttpSendRequest(hRequest, L"Content-Type: application/x-www-form-urlencoded\\r\\n", 0,',
      '        (LPVOID)body.c_str(), (DWORD)body.size(), (DWORD)body.size(), 0);',
      '    WinHttpReceiveResponse(hRequest, NULL);',
      '',
      '    DWORD statusCode = 0;',
      '    DWORD statusSize = sizeof(statusCode);',
      '    WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusSize, WINHTTP_NO_HEADER_INDEX);',
      '    if (statusCode != 200) {',
      '        std::wcerr << L"http status: " << statusCode << std::endl;',
      '    }',
      '',
      '    DWORD size = 0;',
      '    do {',
      '        WinHttpQueryDataAvailable(hRequest, &size);',
      '        if (!size) break;',
      '        std::string buffer(size, 0);',
      '        DWORD downloaded = 0;',
      '        WinHttpReadData(hRequest, &buffer[0], size, &downloaded);',
      '        std::cout.write(buffer.c_str(), downloaded);',
      '    } while (size > 0);',
      '',
      '    WinHttpCloseHandle(hRequest);',
      '    WinHttpCloseHandle(hConnect);',
      '    WinHttpCloseHandle(hSession);',
      '    return 0;',
      '}'
    ].join('\n'));

    setCode('api-login-cpp-demo', [
      '#include <curl/curl.h>',
      '#include <iostream>',
      '#include <string>',
      '',
      'static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {',
      '    ((std::string*)userp)->append((char*)contents, size * nmemb);',
      '    return size * nmemb;',
      '}',
      '',
      'int main() {',
      '    CURL* curl = curl_easy_init();',
      '    if (!curl) return 1;',
      '',
      '    std::string response;',
      '    std::string json = "{\\"game\\":\\"' + code + '\\",\\"user_key\\":\\"YOUR_KEY\\",\\"serial\\":\\"REAL_MACHINE_CODE\\"}";',
      '    struct curl_slist* headers = NULL;',
      '    headers = curl_slist_append(headers, "Content-Type: application/json");',
      '',
      '    curl_easy_setopt(curl, CURLOPT_URL, "' + apiLoginUrl + '");',
      '    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3L);',
      '    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);',
      '    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);',
      '    curl_easy_setopt(curl, CURLOPT_POST, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());',
      '    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);',
      '    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);',
      '    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L);',
      '',
      '    CURLcode res = curl_easy_perform(curl);',
      '    long httpCode = 0;',
      '    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);',
      '    curl_slist_free_all(headers);',
      '    curl_easy_cleanup(curl);',
      '',
      '    if (res != CURLE_OK) {',
      '        std::cerr << "request failed: " << curl_easy_strerror(res) << std::endl;',
      '        return 1;',
      '    }',
      '    if (httpCode != 200) {',
      '        std::cerr << "http status: " << httpCode << "\\n" << response << std::endl;',
      '        return 1;',
      '    }',
      '    if (response.empty() || response[0] != \'{\') {',
      '        std::cerr << "non-json response:\\n" << response << std::endl;',
      '        return 1;',
      '    }',
      '',
      '    std::cout << response << std::endl;',
      '    return 0;',
      '}'
    ].join('\n'));

    setCode('api-query-cpp-demo', [
      '#include <curl/curl.h>',
      '#include <iostream>',
      '#include <string>',
      '',
      'static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {',
      '    ((std::string*)userp)->append((char*)contents, size * nmemb);',
      '    return size * nmemb;',
      '}',
      '',
      'int main() {',
      '    CURL* curl = curl_easy_init();',
      '    if (!curl) return 1;',
      '',
      '    std::string response;',
      '    std::string postFields = "user_key=YOUR_KEY";',
      '    struct curl_slist* headers = NULL;',
      '    headers = curl_slist_append(headers, "X-API-TOKEN: YOUR_API_TOKEN");',
      '    headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");',
      '',
      '    curl_easy_setopt(curl, CURLOPT_URL, "' + apiQueryUrl + '");',
      '    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3L);',
      '    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);',
      '    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);',
      '    curl_easy_setopt(curl, CURLOPT_POST, 1L);',
      '    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());',
      '    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);',
      '    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);',
      '    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L);',
      '',
      '    CURLcode res = curl_easy_perform(curl);',
      '    if (res != CURLE_OK) {',
      '        std::cerr << "query failed: " << curl_easy_strerror(res) << std::endl;',
      '    } else {',
      '        std::cout << "[query]\\n" << response << std::endl;',
      '    }',
      '',
      '    response.clear();',
      '    curl_easy_setopt(curl, CURLOPT_URL, "' + apiUnbindUrl + '");',
      '    res = curl_easy_perform(curl);',
      '    if (res != CURLE_OK) {',
      '        std::cerr << "unbind failed: " << curl_easy_strerror(res) << std::endl;',
      '    } else {',
      '        std::cout << "[unbind]\\n" << response << std::endl;',
      '    }',
      '',
      '    curl_slist_free_all(headers);',
      '    curl_easy_cleanup(curl);',
      '    return 0;',
      '}'
    ].join('\n'));

    setCode('connect-curl-demo', [
      'curl -X POST "' + connectUrl + '" \\',
      '  -d "game=' + code + '" \\',
      '  -d "user_key=YOUR_KEY" \\',
      '  -d "serial=REAL_MACHINE_CODE"'
    ].join('\n'));

    setCode('proxy-query-demo', [
      '<' + '?php',
      '$remote = "' + apiQueryUrl + '";',
      '$userKey = $_POST["user_key"] ?? "";',
      '',
      '$headers = [',
      '    "X-API-TOKEN: YOUR_API_TOKEN",',
      '    "Content-Type: application/x-www-form-urlencoded",',
      '];',
      '',
      '$ch = curl_init();',
      'curl_setopt_array($ch, [',
      '    CURLOPT_URL => $remote,',
      '    CURLOPT_POST => true,',
      '    CURLOPT_POSTFIELDS => http_build_query(["user_key" => $userKey]),',
      '    CURLOPT_HTTPHEADER => $headers,',
      '    CURLOPT_RETURNTRANSFER => true,',
      '    CURLOPT_TIMEOUT => 15,',
      ']);',
      '',
      '$resp = curl_exec($ch);',
      'curl_close($ch);',
      'header("Content-Type: application/json; charset=utf-8");',
      'echo $resp;'
    ].join('\n'));

    setCode('query-page-demo', [
      '查卡页面地址：',
      queryPageUrl,
      '',
      '建议做法：',
      '1. 把这个地址放到用户中心、官网帮助页或启动器菜单里。',
      '2. 不再从登录页直接挂查卡入口，避免页面太杂。',
      '3. 查卡与解绑优先让用户走这个页面，不要把 API Token 暴露给客户端。'
    ].join('\n'));

    setCode('query-success-demo', [
      '{',
      '  "status": true,',
      '  "code": "OK",',
      '  "message": "ok",',
      '  "reason": "ok",',
      '  "data": {',
      '    "game": "' + code + '",',
      '    "user_key": "YOUR_KEY",',
      '    "status": "active",',
      '    "activated": true,',
      '    "expired_at": "2026-12-31 23:59:59",',
      '    "devices_count": 1,',
      '    "devices": ["REAL_MACHINE_CODE"],',
      '    "device_list": "REAL_MACHINE_CODE",',
      '    "max_devices": 1,',
      '    "allow_self_unbind": true',
      '  }',
      '}'
    ].join('\n'));

    setCode('success-demo', [
      '{',
      '  "status": true,',
      '  "code": "OK",',
      '  "message": "登录成功",',
      '  "reason": "登录成功",',
      '  "data": {',
      '    "game": "' + code + '",',
      '    "user_key": "YOUR_KEY",',
      '    "serial_used": "REAL_MACHINE_CODE",',
      '    "token": "hmac_sha256_result",',
      '    "expired_at": "2026-12-31 23:59:59",',
      '    "max_devices": 1,',
      '    "devices_count": 1,',
      '    "server_time": 1777777777,',
      '    "compat": {',
      '      "MOD_NAME": "Light Year",',
      '      "MOD_STATUS": "normal",',
      '      "FLOTING_TEST": "欢迎使用",',
      '      "BHATIA_EXP": "2026-12-31 23:59:59",',
      '      "BHATIA_SLOT": 1,',
      '      "rng": 1777777777',
      '    }',
      '  }',
      '}'
    ].join('\n'));

    setCode('fail-demo', [
      '{',
      '  "status": false,',
      '  "code": "UNAUTHORIZED",',
      '  "message": "未授权访问",',
      '  "reason": "未授权访问"',
      '}',
      '',
      '{',
      '  "status": false,',
      '  "code": "KEY_NOT_FOUND",',
      '  "message": "卡密不存在",',
      '  "reason": "卡密不存在"',
      '}',
      '',
      '{',
      '  "status": false,',
      '  "code": "DEVICE_LIMIT",',
      '  "message": "设备数量已达上限",',
      '  "reason": "设备数量已达上限"',
      '}'
    ].join('\n'));
  }

  if (select) {
    select.addEventListener('change', render);
  }

  document.querySelectorAll('.connect-doc-copy').forEach(function (button) {
    button.addEventListener('click', function () {
      var targetId = button.getAttribute('data-copy-target');
      var target = document.querySelector('#' + targetId + ' code');
      if (!target) {
        return;
      }
      var text = target.textContent || '';
      if (!text) {
        return;
      }
      copyText(text, function () {
        var oldText = button.textContent;
        button.textContent = copiedText;
        setTimeout(function () {
          button.textContent = oldText;
        }, 1200);
      });
    });
  });

  document.querySelectorAll('[data-copy-text-target]').forEach(function (button) {
    button.addEventListener('click', function () {
      var targetId = button.getAttribute('data-copy-text-target');
      var target = document.getElementById(targetId);
      if (!target) {
        return;
      }
      var text = target.textContent || '';
      if (!text) {
        return;
      }
      copyText(text, function () {
        var oldText = button.textContent;
        button.textContent = copiedText;
        setTimeout(function () {
          button.textContent = oldText;
        }, 1200);
      });
    });
  });

  render();
})();
</script>
