<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>设置 — Telegram 下载器</title>
  <style>
    *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
    :root {
      --bg:       #0d1117;
      --surface:  #161b22;
      --surface2: #1c2128;
      --border:   #30363d;
      --accent:   #58a6ff;
      --green:    #3fb950;
      --orange:   #d29922;
      --red:      #f85149;
      --text:     #e6edf3;
      --muted:    #8b949e;
      --hdr-h:    52px;
    }
    html, body { height: 100%; }
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      background: var(--bg); color: var(--text); font-size: 14px; line-height: 1.5; }

    /* ── Header ── */
    .hdr {
      position: fixed; top: 0; left: 0; right: 0; height: var(--hdr-h);
      background: var(--surface); border-bottom: 1px solid var(--border);
      display: flex; align-items: center; padding: 0 20px; gap: 12px; z-index: 200;
    }
    .hdr-back {
      display: flex; align-items: center; gap: 5px; color: var(--muted);
      text-decoration: none; font-size: 13px; padding: 4px 10px;
      border: 1px solid var(--border); border-radius: 6px; transition: all .15s;
    }
    .hdr-back:hover { color: var(--accent); border-color: var(--accent); }
    .hdr-title { font-size: 15px; font-weight: 700; color: var(--accent); }

    /* ── Main Layout ── */
    .main { margin-top: var(--hdr-h); display: flex; height: calc(100vh - var(--hdr-h)); }

    /* ── Sidebar Tabs ── */
    .sidebar {
      width: 180px; flex-shrink: 0;
      background: var(--surface); border-right: 1px solid var(--border);
      padding: 16px 8px; display: flex; flex-direction: column; gap: 4px;
    }
    .stab {
      display: flex; align-items: center; gap: 8px;
      padding: 9px 12px; border-radius: 7px; cursor: pointer;
      font-size: 13px; color: var(--muted); border: none; background: none;
      text-align: left; transition: all .12s; width: 100%;
    }
    .stab:hover { background: rgba(88,166,255,.07); color: var(--text); }
    .stab.active { background: rgba(88,166,255,.12); color: var(--accent); font-weight: 600; }
    .stab-icon { font-size: 15px; flex-shrink: 0; }

    /* ── Content ── */
    .content { flex: 1; overflow-y: auto; padding: 24px; }
    .tab-panel { display: none; max-width: 800px; }
    .tab-panel.active { display: block; }

    /* ── Card ── */
    .card {
      background: var(--surface); border: 1px solid var(--border);
      border-radius: 8px; margin-bottom: 16px;
    }
    .card-hd {
      padding: 12px 16px; border-bottom: 1px solid var(--border);
      font-size: 13px; font-weight: 600; display: flex; align-items: center;
      justify-content: space-between;
    }
    .card-bd { padding: 16px; }

    /* ── Form Controls ── */
    .field { margin-bottom: 14px; }
    .field:last-child { margin-bottom: 0; }
    .field-label { display: block; font-size: 11px; color: var(--muted);
      margin-bottom: 5px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px; }
    .field-hint { font-size: 11px; color: var(--muted); margin-top: 4px; }
    .field-input {
      width: 100%; padding: 7px 10px; background: var(--bg);
      border: 1px solid var(--border); border-radius: 6px;
      color: var(--text); font-size: 13px; transition: border-color .15s;
    }
    .field-input:focus { outline: none; border-color: var(--accent); }
    .field-input-sm { width: 120px; }
    select.field-input { cursor: pointer; }

    /* ── Buttons ── */
    .btn {
      padding: 7px 16px; border-radius: 6px; font-size: 13px; font-weight: 500;
      cursor: pointer; border: none; display: inline-flex; align-items: center;
      gap: 5px; transition: opacity .15s; white-space: nowrap;
    }
    .btn:disabled { opacity: .4; cursor: not-allowed; }
    .btn-primary { background: var(--accent); color: #0d1117; }
    .btn-primary:hover:not(:disabled) { opacity: .85; }
    .btn-outline { background: transparent; border: 1px solid var(--border); color: var(--muted); }
    .btn-outline:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
    .btn-danger { background: transparent; border: 1px solid rgba(248,81,73,.4); color: var(--red); }
    .btn-danger:hover:not(:disabled) { background: rgba(248,81,73,.1); }
    .btn-sm { padding: 4px 10px; font-size: 12px; }

    /* ── Badges ── */
    .badge {
      display: inline-flex; align-items: center; padding: 2px 7px;
      border-radius: 4px; font-size: 11px; font-weight: 600;
    }
    .badge-green  { background: rgba(63,185,80,.15);  color: var(--green); }
    .badge-orange { background: rgba(210,153,34,.15); color: var(--orange); }
    .badge-red    { background: rgba(248,81,73,.15);  color: var(--red); }
    .badge-blue   { background: rgba(88,166,255,.15); color: var(--accent); }
    .badge-muted  { background: rgba(139,148,158,.12); color: var(--muted); }

    /* ── Log List ── */
    .log-toolbar { display: flex; gap: 8px; margin-bottom: 12px; align-items: center; flex-wrap: wrap; }
    .log-list {
      font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px;
      line-height: 1.6; overflow-x: auto;
    }
    .log-line { padding: 2px 0; border-bottom: 1px solid rgba(48,54,61,.5); white-space: pre-wrap; word-break: break-all; }
    .log-line:last-child { border-bottom: none; }
    .log-err  { color: var(--red); }
    .log-warn { color: var(--orange); }
    .log-info { color: var(--text); }
    .log-debug { color: var(--muted); }
    .log-empty { text-align: center; padding: 24px; color: var(--muted); font-size: 13px; }

    /* ── Table ── */
    .tbl-wrap { overflow-x: auto; }
    table { width: 100%; border-collapse: collapse; font-size: 12px; }
    th { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border);
      color: var(--muted); font-weight: 600; font-size: 11px; white-space: nowrap; }
    td { padding: 7px 10px; border-bottom: 1px solid rgba(48,54,61,.6); }
    tr:last-child td { border-bottom: none; }
    tr:hover td { background: rgba(88,166,255,.04); }
    .td-truncate { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    /* ── Pagination ── */
    .pager { display: flex; align-items: center; gap: 6px; margin-top: 14px;
      font-size: 12px; color: var(--muted); }
    .pager-btn {
      padding: 4px 10px; border-radius: 5px; background: transparent;
      border: 1px solid var(--border); color: var(--muted);
      cursor: pointer; font-size: 12px; transition: all .12s;
    }
    .pager-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
    .pager-btn:disabled { opacity: .4; cursor: default; }
    .pager-info { flex: 1; text-align: center; }
    .pager-jump { display: flex; align-items: center; gap: 5px; }
    .pager-jump input { width: 54px; padding: 3px 7px; background: var(--bg);
      border: 1px solid var(--border); border-radius: 5px; color: var(--text);
      font-size: 12px; text-align: center; }
    .pager-jump input:focus { outline: none; border-color: var(--accent); }

    /* ── DB Search Bar ── */
    .search-bar { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
    .search-bar .field-input { width: auto; flex: 1; min-width: 120px; }
    .search-bar select.field-input { width: auto; }

    /* ── Status/Session ── */
    .info-row { display: flex; justify-content: space-between; align-items: center;
      padding: 10px 0; border-bottom: 1px solid var(--border); }
    .info-row:last-child { border-bottom: none; }
    .info-k { font-size: 12px; color: var(--muted); }
    .info-v { font-size: 12px; }

    /* ── Proxy Fields ── */
    .proxy-grid { display: grid; grid-template-columns: 1fr 1fr 100px; gap: 10px; }

    /* ── Toast ── */
    .toasts { position: fixed; top: 60px; right: 14px; display: flex;
      flex-direction: column; gap: 7px; z-index: 999; pointer-events: none; }
    .toast { padding: 9px 16px; border-radius: 7px; font-size: 13px; animation: tin .2s ease; }
    .toast-ok  { background: rgba(63,185,80,.92); color: #0d1117; }
    .toast-err { background: rgba(248,81,73,.92); color: #fff; }
    @keyframes tin { from { opacity:0; transform:translateX(16px); } to { opacity:1; transform:none; } }

    /* ── Spinner ── */
    .spin { display: inline-block; width: 11px; height: 11px;
      border: 2px solid rgba(255,255,255,.3); border-radius: 50%;
      border-top-color: currentColor; animation: sp 1s linear infinite; }
    @keyframes sp { to { transform: rotate(360deg); } }

    /* ── Confirm Modal ── */
    .modal-mask { display: none; position: fixed; inset: 0;
      background: rgba(0,0,0,.7); z-index: 500;
      align-items: center; justify-content: center; }
    .modal-mask.on { display: flex; }
    .modal-box { background: var(--surface); border: 1px solid var(--border);
      border-radius: 10px; padding: 24px; max-width: 380px; width: 90%; }
    .modal-title { font-size: 15px; font-weight: 700; margin-bottom: 8px; }
    .modal-body { font-size: 13px; color: var(--muted); margin-bottom: 20px; line-height: 1.6; }
    .modal-foot { display: flex; gap: 8px; justify-content: flex-end; }
  </style>
</head>
<body>

<!-- Header -->
<header class="hdr">
  <a href="/" class="hdr-back">← 返回主页</a>
  <span style="color:var(--border);">|</span>
  <div class="hdr-title">⚙ 设置</div>
</header>

<div class="toasts" id="toasts"></div>

<!-- 确认弹窗 -->
<div class="modal-mask" id="confirm-modal">
  <div class="modal-box">
    <div class="modal-title" id="modal-title">确认操作</div>
    <div class="modal-body" id="modal-body"></div>
    <div class="modal-foot">
      <button class="btn btn-outline btn-sm" onclick="closeConfirm()">取消</button>
      <button class="btn btn-danger btn-sm" id="modal-ok-btn" onclick="doConfirm()">确认</button>
    </div>
  </div>
</div>

<div class="main">

  <!-- Sidebar -->
  <nav class="sidebar">
    <button class="stab active" onclick="switchTab('general')"><span class="stab-icon">⚙</span>常规设置</button>
    <button class="stab" onclick="switchTab('logs')"><span class="stab-icon">📋</span>运行日志</button>
    <button class="stab" onclick="switchTab('db')"><span class="stab-icon">🗄</span>下载记录</button>
    <button class="stab" onclick="switchTab('account')"><span class="stab-icon">👤</span>账户管理</button>
  </nav>

  <!-- Content -->
  <div class="content">

    <!-- Tab: 常规设置 -->
    <div class="tab-panel active" id="tab-general">
      <div class="card">
        <div class="card-hd">下载设置</div>
        <div class="card-bd">
          <div class="field">
            <label class="field-label">并发下载数量</label>
            <input class="field-input field-input-sm" type="number" id="g-max-task" min="1" max="20" value="5">
            <div class="field-hint">同时下载的文件数，范围 1–20，修改后自动重启生效</div>
          </div>
          <div class="field">
            <label class="field-label">日志级别</label>
            <select class="field-input field-input-sm" id="g-log-level">
              <option value="INFO">INFO（推荐）</option>
              <option value="DEBUG">DEBUG（详细）</option>
              <option value="WARNING">WARNING（仅警告）</option>
            </select>
            <div class="field-hint">修改后重启生效</div>
          </div>
          <div class="field">
            <label class="field-label">文件保存路径</label>
            <input class="field-input" type="text" id="g-save-path" placeholder="/path/to/downloads">
          </div>
        </div>
      </div>
      <div style="display:flex;gap:8px;">
        <button class="btn btn-primary" id="g-save-btn" onclick="saveGeneral()">💾 保存并重启</button>
      </div>
    </div>

    <!-- Tab: 运行日志 -->
    <div class="tab-panel" id="tab-logs">
      <div class="card">
        <div class="card-hd">
          <span>运行日志</span>
          <span id="log-total-badge" style="font-size:11px;color:var(--muted);"></span>
        </div>
        <div class="card-bd">
          <div class="log-toolbar">
            <select class="field-input" style="width:130px;" id="log-level-filter">
              <option value="">全部级别</option>
              <option value="INFO">INFO</option>
              <option value="WARNING">WARNING</option>
              <option value="ERROR">ERROR</option>
              <option value="DEBUG">DEBUG</option>
            </select>
            <input class="field-input" style="flex:1;min-width:140px;" type="text"
              id="log-keyword" placeholder="关键词搜索…" onkeydown="if(event.key==='Enter')loadLogs(1)">
            <button class="btn btn-outline btn-sm" onclick="loadLogs(1)">🔍 搜索</button>
            <button class="btn btn-outline btn-sm" onclick="loadLogs(logPage)">↺ 刷新</button>
          </div>
          <div id="log-list" class="log-list"><div class="log-empty">加载中…</div></div>
          <div class="pager" id="log-pager" style="display:none;">
            <button class="pager-btn" id="log-prev" onclick="loadLogs(logPage-1)">‹ 上一页</button>
            <div class="pager-info" id="log-pager-info"></div>
            <div class="pager-jump">
              跳转 <input type="number" id="log-jump-input" min="1" onkeydown="if(event.key==='Enter')loadLogs(+this.value)"> 页
            </div>
            <button class="pager-btn" id="log-next" onclick="loadLogs(logPage+1)">下一页 ›</button>
          </div>
        </div>
      </div>
    </div>

    <!-- Tab: 下载记录 -->
    <div class="tab-panel" id="tab-db">
      <div class="card">
        <div class="card-hd">
          <span>下载记录</span>
          <span id="db-total-badge" style="font-size:11px;color:var(--muted);"></span>
        </div>
        <div class="card-bd">
          <div class="search-bar">
            <input class="field-input" type="text" id="db-chat" placeholder="频道ID/名称">
            <input class="field-input" type="text" id="db-filename" placeholder="文件名">
            <select class="field-input" id="db-status">
              <option value="">全部状态</option>
              <option value="success">success</option>
              <option value="skip">skip</option>
            </select>
            <select class="field-input" id="db-mediatype">
              <option value="">全部类型</option>
              <option value="audio">audio</option>
              <option value="video">video</option>
              <option value="photo">photo</option>
              <option value="document">document</option>
            </select>
            <input class="field-input" type="date" id="db-date-from" title="开始日期">
            <input class="field-input" type="date" id="db-date-to" title="结束日期">
            <button class="btn btn-primary btn-sm" onclick="loadDb(1)">搜索</button>
            <button class="btn btn-outline btn-sm" onclick="clearDbSearch()">重置</button>
          </div>
          <div class="tbl-wrap">
            <table>
              <thead>
                <tr>
                  <th>ID</th><th>频道</th><th>消息ID</th><th>文件名</th>
                  <th>大小</th><th>类型</th><th>时间</th><th>状态</th><th>操作</th>
                </tr>
              </thead>
              <tbody id="db-tbody"><tr><td colspan="9" style="text-align:center;padding:20px;color:var(--muted);">加载中…</td></tr></tbody>
            </table>
          </div>
          <div class="pager" id="db-pager" style="display:none;">
            <button class="pager-btn" id="db-prev" onclick="loadDb(dbPage-1)">‹ 上一页</button>
            <div class="pager-info" id="db-pager-info"></div>
            <div class="pager-jump">
              跳转 <input type="number" id="db-jump-input" min="1" onkeydown="if(event.key==='Enter')loadDb(+this.value)"> 页
            </div>
            <button class="pager-btn" id="db-next" onclick="loadDb(dbPage+1)">下一页 ›</button>
          </div>
        </div>
      </div>
    </div>

    <!-- Tab: 账户管理 -->
    <div class="tab-panel" id="tab-account">
      <div class="card">
        <div class="card-hd">Session 状态</div>
        <div class="card-bd" id="session-info">
          <div style="color:var(--muted);font-size:13px;">检测中…</div>
        </div>
      </div>

      <div class="card">
        <div class="card-hd">代理设置</div>
        <div class="card-bd">
          <div class="field">
            <label class="field-label">代理类型</label>
            <select class="field-input field-input-sm" id="p-scheme">
              <option value="socks5">SOCKS5</option>
              <option value="http">HTTP</option>
            </select>
          </div>
          <div class="proxy-grid">
            <div class="field">
              <label class="field-label">地址</label>
              <input class="field-input" type="text" id="p-host" placeholder="192.168.1.1">
            </div>
            <div class="field">
              <label class="field-label">端口</label>
              <input class="field-input" type="number" id="p-port" placeholder="7890">
            </div>
            <div class="field">
              <label class="field-label">　</label>
              <button class="btn btn-outline btn-sm" onclick="testProxy()" id="p-test-btn">🔌 测试</button>
              <span id="p-test-result" style="font-size:11px;display:block;margin-top:4px;"></span>
            </div>
          </div>
          <div class="field-hint" style="margin-bottom:12px;">留空地址则不使用代理。修改后自动重启。</div>
          <button class="btn btn-primary btn-sm" id="p-save-btn" onclick="saveProxy()">💾 保存代理并重启</button>
        </div>
      </div>

      <div class="card">
        <div class="card-hd">重新配置账户</div>
        <div class="card-bd">
          <p style="font-size:13px;color:var(--muted);margin-bottom:14px;line-height:1.7;">
            点击下方按钮将删除当前登录 session，服务重启后需在终端重新运行登录命令完成 Telegram 账号验证。<br>
            <span style="color:var(--orange);">⚠ 操作不可撤销，当前下载任务将被中断。</span>
          </p>
          <button class="btn btn-danger" onclick="confirmClearSession()">🔑 清除 Session 并重新登录</button>
        </div>
      </div>
    </div>

  </div><!-- /content -->
</div><!-- /main -->

<script>
  // ── Toast ──
  function toast(msg, type = 'ok') {
    const el = document.createElement('div');
    el.className = 'toast toast-' + type;
    el.textContent = msg;
    document.getElementById('toasts').appendChild(el);
    setTimeout(() => el.remove(), 3500);
  }

  function fmtBytes(n) {
    if (!n) return '—';
    n = +n;
    if (n < 1024) return n + ' B';
    if (n < 1024**2) return (n/1024).toFixed(1) + ' KB';
    if (n < 1024**3) return (n/1024**2).toFixed(1) + ' MB';
    return (n/1024**3).toFixed(2) + ' GB';
  }

  // ── Tab 切换 ──
  const TAB_INIT = { logs: false, db: false, account: false };
  function switchTab(name) {
    document.querySelectorAll('.stab').forEach(b => b.classList.remove('active'));
    document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
    document.querySelector(`.stab[onclick*="${name}"]`).classList.add('active');
    document.getElementById('tab-' + name).classList.add('active');
    if (!TAB_INIT[name]) {
      TAB_INIT[name] = true;
      if (name === 'logs') loadLogs(1);
      if (name === 'db') loadDb(1);
      if (name === 'account') loadAccountInfo();
    }
  }

  // ════ 常规设置 ════
  function loadGeneral() {
    fetch('/api/settings/general').then(r => r.json()).then(d => {
      document.getElementById('g-max-task').value = d.max_download_task || 5;
      document.getElementById('g-log-level').value = d.log_level || 'INFO';
      document.getElementById('g-save-path').value = d.save_path || '';
    }).catch(() => {});
  }

  function saveGeneral() {
    const btn = document.getElementById('g-save-btn');
    btn.disabled = true; btn.innerHTML = '<span class="spin"></span> 保存中…';
    const body = {
      max_download_task: +document.getElementById('g-max-task').value,
      log_level: document.getElementById('g-log-level').value,
      save_path: document.getElementById('g-save-path').value.trim(),
    };
    fetch('/api/settings/general', {
      method: 'POST', headers: {'Content-Type':'application/json'},
      body: JSON.stringify(body)
    }).then(r => r.json()).then(d => {
      if (d.success) { toast('已保存，5秒后重启…'); setTimeout(() => location.href = '/', 5000); }
      else { toast(d.error || '保存失败', 'err'); btn.disabled = false; btn.textContent = '💾 保存并重启'; }
    }).catch(() => { toast('请求失败', 'err'); btn.disabled = false; btn.textContent = '💾 保存并重启'; });
  }

  // ════ 运行日志 ════
  let logPage = 1, logPages = 1;
  function loadLogs(page) {
    page = Math.max(1, Math.min(page, logPages));
    logPage = page;
    const level = document.getElementById('log-level-filter').value;
    const kw = document.getElementById('log-keyword').value.trim();
    const url = `/api/settings/logs?page=${page}&page_size=100&level=${encodeURIComponent(level)}&keyword=${encodeURIComponent(kw)}`;
    document.getElementById('log-list').innerHTML = '<div class="log-empty">加载中…</div>';
    fetch(url).then(r => r.json()).then(d => {
      logPages = d.pages || 1;
      document.getElementById('log-total-badge').textContent = `共 ${d.total} 行`;
      if (!d.lines || !d.lines.length) {
        document.getElementById('log-list').innerHTML = '<div class="log-empty">暂无日志</div>';
        document.getElementById('log-pager').style.display = 'none';
        return;
      }
      document.getElementById('log-list').innerHTML = d.lines.map(line => {
        let cls = 'log-info';
        if (line.includes('| ERROR') || line.includes('|ERROR')) cls = 'log-err';
        else if (line.includes('| WARNING') || line.includes('|WARNING')) cls = 'log-warn';
        else if (line.includes('| DEBUG') || line.includes('|DEBUG')) cls = 'log-debug';
        const escaped = line.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
        return `<div class="log-line ${cls}">${escaped}</div>`;
      }).join('');
      const pager = document.getElementById('log-pager');
      pager.style.display = 'flex';
      document.getElementById('log-pager-info').textContent = `第 ${logPage} / ${logPages} 页`;
      document.getElementById('log-prev').disabled = logPage <= 1;
      document.getElementById('log-next').disabled = logPage >= logPages;
      document.getElementById('log-jump-input').value = logPage;
    }).catch(() => { document.getElementById('log-list').innerHTML = '<div class="log-empty">加载失败</div>'; });
  }

  // ════ 下载记录 ════
  let dbPage = 1, dbPages = 1;
  function loadDb(page) {
    page = Math.max(1, Math.min(page, dbPages));
    dbPage = page;
    const params = new URLSearchParams({
      page, page_size: 50,
      chat_id: document.getElementById('db-chat').value.trim(),
      file_name: document.getElementById('db-filename').value.trim(),
      status: document.getElementById('db-status').value,
      media_type: document.getElementById('db-mediatype').value,
      date_from: document.getElementById('db-date-from').value,
      date_to: document.getElementById('db-date-to').value,
    });
    document.getElementById('db-tbody').innerHTML = '<tr><td colspan="9" style="text-align:center;padding:16px;color:var(--muted);">加载中…</td></tr>';
    fetch('/api/settings/db_records?' + params).then(r => r.json()).then(d => {
      dbPages = d.pages || 1;
      document.getElementById('db-total-badge').textContent = `共 ${d.total} 条`;
      if (!d.records || !d.records.length) {
        document.getElementById('db-tbody').innerHTML = '<tr><td colspan="9" style="text-align:center;padding:20px;color:var(--muted);">暂无记录</td></tr>';
        document.getElementById('db-pager').style.display = 'none';
        return;
      }
      document.getElementById('db-tbody').innerHTML = d.records.map(r => {
        const statusBadge = r.status === 'success'
          ? `<span class="badge badge-green">成功</span>`
          : r.status === 'skip'
            ? `<span class="badge badge-orange">跳过</span>`
            : `<span class="badge badge-muted">${r.status||'—'}</span>`;
        const undoBtn = r.status === 'skip'
          ? `<button class="btn btn-outline btn-sm" onclick="undoSkip('${r.chat_id}',${r.message_id},this)">撤销</button>`
          : '';
        return `<tr>
          <td>${r.id}</td>
          <td class="td-truncate" title="${r.chat_title||r.chat_id}">${r.chat_title||r.chat_id||'—'}</td>
          <td>${r.message_id}</td>
          <td class="td-truncate" title="${r.file_name||''}">${r.file_name||'—'}</td>
          <td style="white-space:nowrap">${fmtBytes(r.file_size)}</td>
          <td>${r.media_type||'—'}</td>
          <td style="white-space:nowrap;font-size:11px;">${(r.download_time||'').slice(0,16)}</td>
          <td>${statusBadge}</td>
          <td>${undoBtn}</td>
        </tr>`;
      }).join('');
      const pager = document.getElementById('db-pager');
      pager.style.display = 'flex';
      document.getElementById('db-pager-info').textContent = `第 ${dbPage} / ${dbPages} 页`;
      document.getElementById('db-prev').disabled = dbPage <= 1;
      document.getElementById('db-next').disabled = dbPage >= dbPages;
      document.getElementById('db-jump-input').value = dbPage;
    }).catch(() => { document.getElementById('db-tbody').innerHTML = '<tr><td colspan="9" style="text-align:center;padding:20px;color:var(--red);">加载失败</td></tr>'; });
  }

  function clearDbSearch() {
    ['db-chat','db-filename'].forEach(id => document.getElementById(id).value = '');
    ['db-status','db-mediatype'].forEach(id => document.getElementById(id).value = '');
    ['db-date-from','db-date-to'].forEach(id => document.getElementById(id).value = '');
    loadDb(1);
  }

  function undoSkip(chatId, msgId, btn) {
    btn.disabled = true;
    fetch('/api/undo_skip', {
      method: 'POST', headers: {'Content-Type':'application/json'},
      body: JSON.stringify({chat_id: chatId, message_id: +msgId})
    }).then(r => r.json()).then(d => {
      if (d.success) { toast('已撤销跳过'); loadDb(dbPage); }
      else { toast(d.error || '撤销失败', 'err'); btn.disabled = false; }
    }).catch(() => { toast('请求失败', 'err'); btn.disabled = false; });
  }

  // ════ 账户管理 ════
  function loadAccountInfo() {
    fetch('/api/settings/general').then(r => r.json()).then(d => {
      const p = d.proxy || {};
      document.getElementById('p-scheme').value = p.scheme || 'socks5';
      document.getElementById('p-host').value = p.hostname || '';
      document.getElementById('p-port').value = p.port || '';
    }).catch(() => {});

    fetch('/api/setup_status').then(r => r.json()).then(s => {
      const el = document.getElementById('session-info');
      el.innerHTML = `
        <div class="info-row">
          <span class="info-k">Session 文件</span>
          <span class="info-v">${s.has_session
            ? '<span class="badge badge-green">✓ 已登录</span>'
            : '<span class="badge badge-red">✗ 未登录</span>'}</span>
        </div>
        <div class="info-row">
          <span class="info-k">API 凭证</span>
          <span class="info-v">${s.has_api_credentials
            ? '<span class="badge badge-green">✓ 已配置</span>'
            : '<span class="badge badge-red">✗ 未配置</span>'}</span>
        </div>`;
    }).catch(() => {});
  }

  function testProxy() {
    const btn = document.getElementById('p-test-btn');
    const res = document.getElementById('p-test-result');
    btn.disabled = true; btn.innerHTML = '<span class="spin"></span>';
    res.textContent = '';
    fetch('/api/test_proxy', {
      method: 'POST', headers: {'Content-Type':'application/json'},
      body: JSON.stringify({
        scheme: document.getElementById('p-scheme').value,
        hostname: document.getElementById('p-host').value.trim(),
        port: +document.getElementById('p-port').value || 0,
      })
    }).then(r => r.json()).then(d => {
      res.style.color = d.success ? 'var(--green)' : 'var(--red)';
      res.textContent = d.success ? ('✓ ' + d.message) : ('✗ ' + d.error);
    }).catch(e => { res.style.color = 'var(--red)'; res.textContent = '✗ ' + e.message; })
      .finally(() => { btn.disabled = false; btn.textContent = '🔌 测试'; });
  }

  function saveProxy() {
    const btn = document.getElementById('p-save-btn');
    btn.disabled = true; btn.innerHTML = '<span class="spin"></span> 保存中…';
    fetch('/api/settings/general', {
      method: 'POST', headers: {'Content-Type':'application/json'},
      body: JSON.stringify({
        proxy: {
          scheme: document.getElementById('p-scheme').value,
          hostname: document.getElementById('p-host').value.trim(),
          port: +document.getElementById('p-port').value || 7890,
        }
      })
    }).then(r => r.json()).then(d => {
      if (d.success) { toast('代理已保存，5秒后重启…'); setTimeout(() => location.href = '/', 5000); }
      else { toast(d.error || '保存失败', 'err'); btn.disabled = false; btn.textContent = '💾 保存代理并重启'; }
    }).catch(() => { toast('请求失败', 'err'); btn.disabled = false; btn.textContent = '💾 保存代理并重启'; });
  }

  // ── 确认弹窗 ──
  let _confirmCallback = null;
  function showConfirm(title, body, cb) {
    document.getElementById('modal-title').textContent = title;
    document.getElementById('modal-body').textContent = body;
    _confirmCallback = cb;
    document.getElementById('confirm-modal').classList.add('on');
  }
  function closeConfirm() {
    document.getElementById('confirm-modal').classList.remove('on');
    _confirmCallback = null;
  }
  function doConfirm() {
    closeConfirm();
    if (_confirmCallback) _confirmCallback();
  }

  function confirmClearSession() {
    showConfirm(
      '确认清除 Session？',
      '此操作将删除当前登录凭证并重启服务。重启后需在终端运行登录命令重新完成 Telegram 账号验证。',
      clearSession
    );
  }

  function clearSession() {
    fetch('/api/settings/clear_session', { method: 'POST' })
      .then(r => r.json()).then(d => {
        if (d.success) { toast('Session 已清除，服务即将重启…'); setTimeout(() => location.href = '/', 5000); }
        else toast(d.error || '操作失败', 'err');
      }).catch(() => toast('请求失败', 'err'));
  }

  // ── 初始化 ──
  loadGeneral();
</script>
</body>
</html>
