<template>
  <transition name="personal-page-fade">
    <div
      class="personal-page-overlay"
      v-if="visible"
      @mousedown.self="personalization.handleOverlayPressStart($event)"
      @mouseup.self="personalization.handleOverlayPressEnd"
      @mouseleave.self="personalization.handleOverlayPressCancel"
      @touchstart.self.prevent="personalization.handleOverlayPressStart($event)"
      @touchend.self.prevent="personalization.handleOverlayPressEnd"
      @touchcancel.self="personalization.handleOverlayPressCancel"
    >
      <div class="personal-page-card" data-tutorial="personal-card">
        <div class="personal-page-header">
          <div>
            <h2>个人空间</h2>
            <p>配置 AI 智能体的个性化偏好</p>
          </div>
          <div class="personal-page-actions">
            <button type="button" class="personal-page-logout" @click="personalization.logout()">退出登录</button>
            <button type="button" class="personal-page-close" data-tutorial="personal-close" @click="personalization.closeDrawer()">返回工作区</button>
          </div>
        </div>
        <div class="personalization-body" v-if="!loading">
          <form class="personal-form" @submit.prevent="personalization.save()">
            <div class="personalization-layout">
              <nav class="personal-page-tabs" aria-label="个人空间分组切换">
                <button
                  v-for="tab in personalTabs"
                  :key="tab.id"
                  type="button"
                  class="personal-tab-button"
                  :data-tutorial="`personal-tab-${tab.id}`"
                  :class="{ active: activeTab === tab.id }"
                  :aria-pressed="activeTab === tab.id"
                  @click.prevent="setActiveTab(tab.id)"
                >
                  <span>{{ tab.label }}</span>
                  <small v-if="tab.description" class="personal-tab-desc">{{ tab.description }}</small>
                </button>
              </nav>
              <div class="personalization-content-shell" data-tutorial="personal-content-shell">
                <div
                  class="personalization-content"
                  @touchstart.passive="handleSwipeStart"
                  @touchend.passive="handleSwipeEnd"
                >
                  <transition name="personal-page-vertical" mode="out-in">
                    <section v-if="activeTab === 'preferences'" key="preferences" class="personal-page personal-page-pref" data-tutorial="personal-page-preferences">
                    <div class="personal-toggle-row">
                      <label class="personal-toggle">
                        <span class="toggle-text">
                          <span class="toggle-title">启用个性化提示</span>
                          <span class="toggle-desc">开启后才会注入您的偏好</span>
                        </span>
                        <span class="toggle-switch">
                          <input
                            type="checkbox"
                            :checked="form.enabled"
                            :disabled="toggleUpdating"
                            @change="personalization.toggleEnabled()"
                          />
                          <span class="switch-slider"></span>
                        </span>
                      </label>
                    </div>
                    <p class="section-note">仅作用于当前工作区，可随时在左下角开关。</p>
                    <div class="personalization-sections">
                      <div class="personal-left-column">
                        <div class="personal-section personal-info">
                          <label class="personal-field">
                            <span>您希望AI智能体怎么自称？</span>
                            <input
                              type="text"
                              placeholder="如：小秘、助理小A"
                              :value="form.self_identify"
                              maxlength="20"
                              @input="personalization.updateField({ key: 'self_identify', value: $event.target.value })"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <label class="personal-field">
                            <span>您希望AI智能体怎么称呼您？</span>
                            <input
                              type="text"
                              placeholder="如：Jojo、老师"
                              :value="form.user_name"
                              maxlength="20"
                              @input="personalization.updateField({ key: 'user_name', value: $event.target.value })"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <label class="personal-field">
                            <span>您的职业是？</span>
                            <input
                              type="text"
                              placeholder="如：产品经理、设计师"
                              :value="form.profession"
                              maxlength="20"
                              @input="personalization.updateField({ key: 'profession', value: $event.target.value })"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <div class="personal-field">
                            <label>
                              <span>您希望AI智能体用何种语气与您交流？</span>
                              <input
                                type="text"
                                placeholder="请选择或输入语气"
                                :value="form.tone"
                                maxlength="20"
                                @input="personalization.updateField({ key: 'tone', value: $event.target.value })"
                                @focus="personalization.clearFeedback()"
                              />
                            </label>
                            <div class="tone-preset-row">
                              <span>快速填入：</span>
                              <div class="tone-preset-buttons">
                                <button type="button" v-for="preset in tonePresets" :key="preset" @click.prevent="personalization.applyTonePreset(preset)">
                                  {{ preset }}
                                </button>
                              </div>
                            </div>
                          </div>
                        </div>
                      </div>
                      <div class="personal-right-column">
                        <div class="personal-section personal-considerations">
                          <div class="personal-field">
                            <span>您希望AI智能体在回答问题时必须考虑的信息是？</span>
                            <div class="consideration-input">
                              <input
                                type="text"
                                :value="newConsideration"
                                maxlength="50"
                                placeholder="输入后点击 + 号添加"
                                @input="personalization.updateNewConsideration($event.target.value)"
                                @focus="personalization.clearFeedback()"
                              />
                              <button
                                type="button"
                                class="consideration-add"
                                :disabled="!newConsideration || form.considerations.length >= maxConsiderations"
                                @click="personalization.addConsideration()"
                              >
                                +
                              </button>
                            </div>
                            <ul class="consideration-list" v-if="form.considerations.length">
                              <li
                                v-for="(item, idx) in form.considerations"
                                :key="`consideration-${idx}`"
                                class="consideration-item"
                                draggable="true"
                                @dragstart="personalization.considerationDragStart(idx, $event)"
                                @dragover.prevent="personalization.considerationDragOver(idx, $event)"
                                @drop.prevent="personalization.considerationDrop(idx, $event)"
                                @dragend="personalization.considerationDragEnd()"
                              >
                                <span class="drag-handle" aria-hidden="true">≡</span>
                                <span class="consideration-text">{{ item }}</span>
                                <button type="button" class="consideration-remove" @click="personalization.removeConsideration(idx)">
                                  −
                                </button>
                              </li>
                            </ul>
                            <p class="consideration-hint" v-else>尚未添加任何必备信息</p>
                            <p class="consideration-limit">最多 {{ maxConsiderations }} 条，可拖动排序</p>
                          </div>
                        </div>
                        <div class="personal-form-actions card-aligned">
                          <div class="personal-status-group">
                            <transition name="personal-status-fade">
                              <span class="status success" v-if="status">{{ status }}</span>
                            </transition>
                            <transition name="personal-status-fade">
                              <span class="status error" v-if="error">{{ error }}</span>
                            </transition>
                          </div>
                          <button type="submit" class="primary" :disabled="saving">
                            {{ saving ? '保存中...' : '保存设置' }}
                          </button>
                        </div>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'image'" key="image" class="personal-page behavior-page" data-tutorial="personal-page-image">
                    <div class="behavior-section">
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">图片压缩</span>
                          <p class="behavior-desc">发送图片或调用 view_image 时自动等比缩放，防止大图占用过多 tokens。</p>
                        </div>
                        <div class="run-mode-options">
                          <button
                            v-for="option in imageCompressionOptions"
                            :key="option.id"
                            type="button"
                            class="run-mode-card"
                            :class="{ active: form.image_compression === option.id }"
                            :aria-pressed="form.image_compression === option.id"
                            @click.prevent="personalization.setImageCompression(option.id)"
                          >
                            <div class="run-mode-card-header">
                              <span class="run-mode-title">{{ option.label }}</span>
                            </div>
                            <p class="run-mode-desc">{{ option.desc }}</p>
                          </button>
                        </div>
                        <p class="behavior-hint">缩放保持原始比例；若原图已低于目标分辨率，将直接使用原图。</p>
                      </div>
                    </div>
                    <div class="personal-actions-row">
                      <div class="personal-form-actions card-aligned">
                        <div class="personal-status-group">
                          <transition name="personal-status-fade">
                            <span class="status success" v-if="status">{{ status }}</span>
                          </transition>
                          <transition name="personal-status-fade">
                            <span class="status error" v-if="error">{{ error }}</span>
                          </transition>
                        </div>
                        <button type="submit" class="primary" :disabled="saving">
                          {{ saving ? '保存中...' : '保存设置' }}
                        </button>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'model'" key="model" class="personal-page behavior-page" data-tutorial="personal-page-model">
                    <div class="behavior-section">
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">默认模型</span>
                          <p class="field-desc">为新对话/登录后首次请求选择首选模型，会与默认思考模式一起生效。</p>
                        </div>
                        <div class="run-mode-options model-options">
                          <button
                            v-for="option in filteredModelOptions"
                            :key="option.id"
                            type="button"
                            class="run-mode-card"
                            :class="[{ active: form.default_model === option.value }, { disabled: option.disabled }]"
                            :aria-pressed="form.default_model === option.value"
                            :disabled="option.disabled"
                            @click.prevent="!option.disabled && setDefaultModel(option.value)"
                          >
                            <div class="run-mode-card-header">
                              <span class="run-mode-title">{{ option.label }}</span>
                              <span v-if="option.badge" class="run-mode-badge">{{ option.badge }}</span>
                              <span v-if="option.disabled" class="run-mode-badge danger">已禁用</span>
                            </div>
                            <p class="run-mode-desc">{{ option.desc }}</p>
                          </button>
                        </div>
                        <p class="behavior-hint">
                          MiniMax-M2.5 仅支持深度思考模式，选择时会给出提示。
                        </p>
                      </div>
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">默认思考模型</span>
                          <p class="field-desc">设定登录或新建任务时的初始运行模式，仍可通过主界面随时切换。</p>
                        </div>
                        <div class="run-mode-options">
                          <button
                            v-for="option in runModeOptions"
                            :key="option.id"
                            type="button"
                            class="run-mode-card"
                            :class="{ active: isRunModeActive(option.value) }"
                            :aria-pressed="isRunModeActive(option.value)"
                            @click.prevent="setDefaultRunMode(option.value)"
                          >
                            <div class="run-mode-card-header">
                              <span class="run-mode-title">{{ option.label }}</span>
                              <span v-if="option.badge" class="run-mode-badge">{{ option.badge }}</span>
                            </div>
                            <p class="run-mode-desc">{{ option.desc }}</p>
                          </button>
                        </div>
                      </div>
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">思考频率</span>
                          <p class="field-desc">控制连续快速模式运行多少轮后，系统会强制切换到思考模型。</p>
                        </div>
                        <div class="thinking-presets">
                          <button
                            v-for="preset in thinkingPresets"
                            :key="preset.id"
                            type="button"
                            :class="{ active: isPresetActive(preset.value) }"
                            @click.prevent="applyThinkingPreset(preset.value)"
                          >
                            {{ preset.label }}
                            <small>{{ preset.value }} 轮</small>
                          </button>
                        </div>
                        <div class="thinking-input-row">
                          <label>
                            <span>自定义轮数</span>
                            <input
                              type="number"
                              :min="thinkingIntervalRange.min"
                              :max="thinkingIntervalRange.max"
                              :placeholder="`默认 ${thinkingIntervalDefault} 轮`"
                              :value="form.thinking_interval ?? ''"
                              @input="handleThinkingInput"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <span class="thinking-hint">范围 {{ thinkingIntervalRange.min }}~{{ thinkingIntervalRange.max }} 轮。</span>
                          <button type="button" class="link-button" @click.prevent="restoreThinkingInterval">
                            恢复默认
                          </button>
                        </div>
                      </div>
                    </div>
                    <div class="personal-actions-row">
                      <div class="personal-form-actions card-aligned">
                        <div class="personal-status-group">
                          <transition name="personal-status-fade">
                            <span class="status success" v-if="status">{{ status }}</span>
                          </transition>
                          <transition name="personal-status-fade">
                            <span class="status error" v-if="error">{{ error }}</span>
                          </transition>
                        </div>
                        <button type="submit" class="primary" :disabled="saving">
                          {{ saving ? '保存中...' : '保存设置' }}
                        </button>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'usage'" key="usage" class="personal-page usage-summary-page" data-tutorial="personal-page-usage">
                    <div class="usage-summary-card">
                      <div class="usage-summary-header">
                        <div>
                          <p class="usage-summary-eyebrow">对话用量</p>
                          <h3>用量统计</h3>
                          <p class="usage-summary-desc">累计统计所有对话的输入/输出 Token、对话数量、用户消息与工具调用。</p>
                          <p class="usage-summary-note">宿主机模式同样统计 data/conversations 内的记录。</p>
                        </div>
                      </div>
                      <div class="usage-summary-grid usage-summary-grid--tokens">
                        <div class="usage-summary-item">
                          <div class="label">累计输入</div>
                          <div class="value value--success">{{ formatTokenCount(usageSummary.total_input_tokens) }}</div>
                        </div>
                        <div class="usage-summary-item">
                          <div class="label">累计输出</div>
                          <div class="value value--warning">{{ formatTokenCount(usageSummary.total_output_tokens) }}</div>
                        </div>
                      </div>
                      <div class="usage-summary-grid usage-summary-grid--counts">
                        <div class="usage-summary-item">
                          <div class="label">总对话数</div>
                          <div class="value">{{ formatTokenCount(usageSummary.total_conversations) }}</div>
                        </div>
                        <div class="usage-summary-item">
                          <div class="label">用户消息数</div>
                          <div class="value">{{ formatTokenCount(usageSummary.total_user_messages) }}</div>
                        </div>
                        <div class="usage-summary-item">
                          <div class="label">工具调用次数</div>
                          <div class="value">{{ formatTokenCount(usageSummary.total_tools) }}</div>
                        </div>
                      </div>
                      <div class="usage-summary-meta">
                        <span v-if="usageError" class="usage-summary-error">{{ usageError }}</span>
                        <span v-else-if="usageLoading">正在同步最新统计...</span>
                        <span v-else>最近更新：{{ usageUpdatedText }}</span>
                        <button
                          type="button"
                          class="usage-summary-refresh"
                          @click="fetchUsageSummary"
                          :disabled="usageLoading"
                        >
                          {{ usageLoading ? '刷新中...' : '刷新数据' }}
                        </button>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'app-update'" key="app-update" class="personal-page app-update-page" data-tutorial="personal-page-app-update">
                    <div class="usage-summary-card">
                      <div class="usage-summary-header">
                        <div>
                          <p class="usage-summary-eyebrow">App 更新</p>
                          <h3>软件更新</h3>
                          <p class="usage-summary-desc">仅移动 App 可见。自动检查新版本，也可手动检查。</p>
                          <p class="usage-summary-note">
                            当前版本：{{ appCurrentVersionText }}
                          </p>
                        </div>
                      </div>

                      <div class="usage-summary-grid usage-summary-grid--counts">
                        <div class="usage-summary-item">
                          <div class="label">最新版本</div>
                          <div class="value">{{ appLatestVersionText }}</div>
                        </div>
                        <div class="usage-summary-item">
                          <div class="label">安装包大小</div>
                          <div class="value">{{ appLatestFileSizeText }}</div>
                        </div>
                        <div class="usage-summary-item">
                          <div class="label">更新状态</div>
                          <div class="value" :class="{ 'value--warning': appHasUpdate }">
                            {{ appUpdateStateText }}
                          </div>
                        </div>
                      </div>

                      <div class="app-update-changelog" v-if="appUpdateChangelogText">
                        <div class="app-update-changelog-title">更新说明</div>
                        <pre class="app-update-changelog-content">{{ appUpdateChangelogText }}</pre>
                      </div>

                      <div class="usage-summary-meta">
                        <span v-if="appUpdateError" class="usage-summary-error">{{ appUpdateError }}</span>
                        <span v-else-if="appUpdateChecking">正在检查版本...</span>
                        <span v-else>{{ appUpdateCheckedText }}</span>
                        <div class="app-update-actions">
                          <button type="button" class="usage-summary-refresh" @click="checkAppUpdate" :disabled="appUpdateChecking">
                            {{ appUpdateChecking ? '检查中...' : '手动检查' }}
                          </button>
                          <button
                            type="button"
                            class="usage-summary-refresh"
                            :disabled="!appHasUpdate || !appDownloadUrl"
                            @click="downloadLatestApp"
                          >
                            下载更新
                          </button>
                        </div>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'behavior'" key="behavior" class="personal-page behavior-page" data-tutorial="personal-page-behavior">
                    <div class="behavior-section">
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">使用自定义称呼</span>
                          <p class="field-desc">开启后，对话区域将使用您在"个性化设置"中配置的自称和称呼。关闭则显示默认的"AI Assistant"和"用户"。</p>
                        </div>
                        <label class="toggle-row">
                          <input
                            type="checkbox"
                            :checked="form.use_custom_names"
                            @change="personalization.updateField({ key: 'use_custom_names', value: $event.target.checked })"
                          />
                          <span class="fancy-check" aria-hidden="true">
                            <svg viewBox="0 0 64 64">
                              <path
                                d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                                pathLength="575.0541381835938"
                                class="fancy-path"
                              ></path>
                            </svg>
                          </span>
                          <span>在对话中显示自定义称呼</span>
                        </label>
                      </div>
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">增强工具显示</span>
                          <p class="field-desc">开启后工具块将显示格式化的内容，关闭则显示原始 JSON 数据。默认开启。</p>
                        </div>
                        <label class="toggle-row">
                          <input
                            type="checkbox"
                            :checked="form.enhanced_tool_display"
                            @change="personalization.updateField({ key: 'enhanced_tool_display', value: $event.target.checked })"
                          />
                          <span class="fancy-check" aria-hidden="true">
                            <svg viewBox="0 0 64 64">
                              <path
                                d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                                pathLength="575.0541381835938"
                                class="fancy-path"
                              ></path>
                            </svg>
                          </span>
                          <span>显示格式化的工具结果（更清晰易读）</span>
                        </label>
                      </div>
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">上下文压缩策略</span>
                          <p class="field-desc">可分别控制自动浅层压缩与自动深层压缩。</p>
                        </div>
                        <label class="toggle-row">
                          <input
                            type="checkbox"
                            :checked="form.auto_shallow_compress_enabled"
                            @change="personalization.updateField({ key: 'auto_shallow_compress_enabled', value: $event.target.checked })"
                          />
                          <span class="fancy-check" aria-hidden="true">
                            <svg viewBox="0 0 64 64">
                              <path
                                d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                                pathLength="575.0541381835938"
                                class="fancy-path"
                              ></path>
                            </svg>
                          </span>
                          <span>自动浅层压缩</span>
                        </label>
                        <label class="toggle-row">
                          <input
                            type="checkbox"
                            :checked="form.auto_deep_compress_enabled"
                            @change="personalization.updateField({ key: 'auto_deep_compress_enabled', value: $event.target.checked })"
                          />
                          <span class="fancy-check" aria-hidden="true">
                            <svg viewBox="0 0 64 64">
                              <path
                                d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                                pathLength="575.0541381835938"
                                class="fancy-path"
                              ></path>
                            </svg>
                          </span>
                          <span>自动深层压缩</span>
                        </label>
                        <div class="compression-custom-grid">
                          <label class="compression-input-row">
                            <span>浅压缩触发上下文</span>
                            <input
                              type="number"
                              min="1000"
                              step="1"
                              placeholder="默认 80000"
                              :value="form.shallow_compress_trigger_tokens ?? ''"
                              @input="handleCompressionNumberInput('shallow_compress_trigger_tokens', $event)"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <label class="compression-input-row">
                            <span>浅压缩保留最近 Tool 条数</span>
                            <input
                              type="number"
                              min="0"
                              step="1"
                              placeholder="默认 15"
                              :value="form.shallow_compress_keep_recent_tools ?? ''"
                              @input="handleCompressionNumberInput('shallow_compress_keep_recent_tools', $event)"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <label class="compression-input-row">
                            <span>浅压缩每轮最多替换条数</span>
                            <input
                              type="number"
                              min="1"
                              step="1"
                              placeholder="默认 10"
                              :value="form.shallow_compress_max_replace_per_round ?? ''"
                              @input="handleCompressionNumberInput('shallow_compress_max_replace_per_round', $event)"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <label class="compression-input-row">
                            <span>浅压缩触发间隔（Tool 调用次数）</span>
                            <input
                              type="number"
                              min="1"
                              step="1"
                              placeholder="默认 10"
                              :value="form.shallow_compress_trigger_tool_calls_interval ?? ''"
                              @input="handleCompressionNumberInput('shallow_compress_trigger_tool_calls_interval', $event)"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                          <label class="compression-input-row">
                            <span>深压缩触发上下文</span>
                            <input
                              type="number"
                              min="1000"
                              step="1"
                              placeholder="默认 150000"
                              :value="form.deep_compress_trigger_tokens ?? ''"
                              @input="handleCompressionNumberInput('deep_compress_trigger_tokens', $event)"
                              @focus="personalization.clearFeedback()"
                            />
                          </label>
                        </div>
                        <div class="compression-actions-row">
                          <button type="button" class="compression-reset-btn" @click.prevent="restoreCompressionDefaults">
                            恢复默认
                          </button>
                        </div>
                        <p class="field-desc compression-custom-hint">
                          自定义项留空则使用默认值；深压缩触发上下文必须大于浅压缩触发上下文。
                        </p>
                      </div>
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">堆叠块显示模式</span>
                          <p class="field-desc">选择思考/工具块的显示方式。默认为堆叠动画。</p>
                        </div>
                        <div class="run-mode-options">
                          <button
                            v-for="option in blockDisplayOptions"
                            :key="option.id"
                            type="button"
                            class="run-mode-card"
                            :class="{ active: experiments.blockDisplayMode === option.value }"
                            :aria-pressed="experiments.blockDisplayMode === option.value"
                            @click.prevent="handleBlockDisplayModeChange(option.value)"
                          >
                            <div class="run-mode-card-header">
                              <span class="run-mode-title">{{ option.label }}</span>
                              <span v-if="option.badge" class="run-mode-badge">{{ option.badge }}</span>
                            </div>
                            <p class="run-mode-desc">{{ option.desc }}</p>
                          </button>
                        </div>
                      </div>
                  <div class="behavior-field">
                    <div class="behavior-field-header">
                      <span class="field-title">静默禁用</span>
                      <p class="field-desc">禁用工具时不再注入提示消息，模型不会感知被禁用项。</p>
                    </div>
                    <label class="toggle-row">
                      <input
                        type="checkbox"
                        :checked="form.silent_tool_disable"
                        @change="personalization.updateField({ key: 'silent_tool_disable', value: $event.target.checked })"
                      />
                      <span class="fancy-check" aria-hidden="true">
                        <svg viewBox="0 0 64 64">
                          <path
                            d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                            pathLength="575.0541381835938"
                            class="fancy-path"
                          ></path>
                        </svg>
                      </span>
                      <span>静默禁用工具（不向模型提示）</span>
                    </label>
                  </div>
                  <div class="behavior-field">
                    <div class="behavior-field-header">
                      <span class="field-title">自动生成对话标题</span>
                      <p class="field-desc">默认开启；关闭后标题将沿用首条消息。</p>
                    </div>
                        <label class="toggle-row">
                          <input
                            type="checkbox"
                            :checked="form.auto_generate_title"
                            @change="personalization.updateField({ key: 'auto_generate_title', value: $event.target.checked })"
                          />
                          <span class="fancy-check" aria-hidden="true">
                            <svg viewBox="0 0 64 64">
                              <path
                                d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                                pathLength="575.0541381835938"
                                class="fancy-path"
                              ></path>
                            </svg>
                          </span>
                          <span>使用快速模型为新对话生成含 emoji 的简短标题</span>
                        </label>
                      </div>
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">工具意图提示</span>
                          <p class="field-desc">开启后，调用工具时会先用约15字告诉你要做什么，替代“正在/完成”文案。</p>
                        </div>
                        <label class="toggle-row">
                          <input
                            type="checkbox"
                            :checked="form.tool_intent_enabled"
                            @change="personalization.updateField({ key: 'tool_intent_enabled', value: $event.target.checked })"
                          />
                          <span class="fancy-check" aria-hidden="true">
                            <svg viewBox="0 0 64 64">
                              <path
                                d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                                pathLength="575.0541381835938"
                                class="fancy-path"
                          ></path>
                        </svg>
                      </span>
                      <span>在工具块显示"我要做什么"的简短提示</span>
                    </label>
                  </div>
                  <div class="behavior-field">
                    <div class="behavior-field-header">
                      <span class="field-title">Skill 提示系统</span>
                      <p class="field-desc">开启后，检测到特定关键词时会自动提示模型阅读相关 skill（如 terminal-guide、sub-agent-guide 等）。</p>
                    </div>
                    <label class="toggle-row">
                      <input
                        type="checkbox"
                        :checked="form.skill_hints_enabled"
                        @change="personalization.updateField({ key: 'skill_hints_enabled', value: $event.target.checked })"
                      />
                      <span class="fancy-check" aria-hidden="true">
                        <svg viewBox="0 0 64 64">
                          <path
                            d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                            pathLength="575.0541381835938"
                            class="fancy-path"
                          ></path>
                        </svg>
                      </span>
                      <span>根据关键词自动提示阅读相关 skill</span>
                    </label>
                  </div>
                  <div class="behavior-field">
                    <div class="behavior-field-header">
                      <span class="field-title">强约束系统</span>
                      <p class="field-desc">开启后，若未在当前对话先阅读对应 SKILL.md，直接调用工具会返回“必须先阅读”。仅对个人空间中已启用的 skill 生效。</p>
                    </div>
                    <div class="strict-skill-grid">
                      <label class="toggle-row">
                        <input
                          type="checkbox"
                          :checked="form.skill_strict_terminal_enabled"
                          @change="personalization.updateField({ key: 'skill_strict_terminal_enabled', value: $event.target.checked })"
                        />
                        <span class="fancy-check" aria-hidden="true">
                          <svg viewBox="0 0 64 64">
                            <path
                              d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                              pathLength="575.0541381835938"
                              class="fancy-path"
                            ></path>
                          </svg>
                        </span>
                        <span>Terminal 系列工具</span>
                      </label>
                      <label class="toggle-row">
                        <input
                          type="checkbox"
                          :checked="form.skill_strict_sub_agent_enabled"
                          @change="personalization.updateField({ key: 'skill_strict_sub_agent_enabled', value: $event.target.checked })"
                        />
                        <span class="fancy-check" aria-hidden="true">
                          <svg viewBox="0 0 64 64">
                            <path
                              d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
                              pathLength="575.0541381835938"
                              class="fancy-path"
                            ></path>
                          </svg>
                        </span>
                        <span>子智能体系列工具</span>
                      </label>
                    </div>
                  </div>
                  <div class="behavior-field">
                    <div class="behavior-field-header">
                      <span class="field-title">默认禁用工具类别</span>
                      <p class="field-desc">选择后，这些类别在新任务中会保持关闭，也可随时通过快捷菜单临时开启。</p>
                    </div>
                        <div class="tool-category-grid" v-if="toolCategories.length">
                          <label
                            v-for="category in toolCategories"
                            :key="category.id"
                            class="tool-category-chip"
                          >
                            <input
                              type="checkbox"
                              :checked="form.disabled_tool_categories.includes(category.id)"
                              @change="toggleCategory(category.id)"
                            />
                            <span>{{ category.label }}</span>
                          </label>
                        </div>
                        <p class="behavior-hint" v-else>暂无可配置的工具类别。</p>
                      </div>
                    </div>
                    <div class="personal-actions-row">
                      <div class="personal-form-actions card-aligned">
                        <div class="personal-status-group">
                          <transition name="personal-status-fade">
                            <span class="status success" v-if="status">{{ status }}</span>
                          </transition>
                          <transition name="personal-status-fade">
                            <span class="status error" v-if="error">{{ error }}</span>
                          </transition>
                        </div>
                        <button type="submit" class="primary" :disabled="saving">
                          {{ saving ? '保存中...' : '保存设置' }}
                        </button>
                      </div>
                    </div>
                    </section>
                  <section v-else-if="activeTab === 'skills'" key="skills" class="personal-page behavior-page" data-tutorial="personal-page-skills">
                    <div class="behavior-section">
                      <div class="behavior-field">
                        <div class="behavior-field-header">
                          <span class="field-title">可用 Skills</span>
                          <p class="field-desc">勾选后会注入 system prompt，并同步到工作区的 skills/ 目录。</p>
                        </div>
                        <div class="tool-category-grid" v-if="skillsCatalog.length">
                          <label
                            v-for="skill in skillsCatalog"
                            :key="skill.id"
                            class="tool-category-chip"
                          >
                            <input
                              type="checkbox"
                              :checked="form.enabled_skills.includes(skill.id)"
                              @change="personalization.toggleSkill(skill.id)"
                            />
                            <span>{{ skill.label }}</span>
                          </label>
                        </div>
                        <p class="behavior-hint" v-else>暂无可用的 skills。</p>
                      </div>
                    </div>
                    <div class="personal-actions-row">
                      <div class="personal-form-actions card-aligned">
                        <div class="personal-status-group">
                          <transition name="personal-status-fade">
                            <span class="status success" v-if="status">{{ status }}</span>
                          </transition>
                          <transition name="personal-status-fade">
                            <span class="status error" v-if="error">{{ error }}</span>
                          </transition>
                        </div>
                        <button type="submit" class="primary" :disabled="saving">
                          {{ saving ? '保存中...' : '保存设置' }}
                        </button>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'theme'" key="theme" class="personal-page theme-page" data-tutorial="personal-page-theme">
                    <div class="theme-section">
                      <div class="theme-header">
                        <div>
                          <h3>界面主题</h3>
                          <p>在浅色、深色和 Claude 经典之间一键切换。会立即应用并保存在本地。</p>
                        </div>
                        <div class="theme-badge">Beta</div>
                      </div>
                      <div class="theme-grid">
                        <button
                          v-for="option in themeOptions"
                          :key="option.id"
                          type="button"
                          class="theme-card"
                          :class="{ active: activeTheme === option.id }"
                          @click.prevent="applyThemeOption(option.id)"
                        >
                          <div class="theme-card-head">
                            <div class="theme-dot-row">
                              <span
                                v-for="(color, idx) in option.swatches"
                                :key="`${option.id}-${idx}`"
                                class="theme-dot"
                                :style="{ background: color }"
                                aria-hidden="true"
                              ></span>
                            </div>
                            <span class="theme-check" v-if="activeTheme === option.id">✓</span>
                          </div>
                          <div class="theme-card-body">
                            <h4>{{ option.label }}</h4>
                            <p>{{ option.desc }}</p>
                          </div>
                        </button>
                      </div>
                      <p class="theme-note">虚拟显示器保持原样；仅主界面、侧边栏与个人空间配色随主题改变。</p>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'tutorial'" key="tutorial" class="personal-page tutorial-page">
                    <div class="tutorial-intro-content">
                      <div class="tutorial-intro-header">
                        <p class="tutorial-intro-eyebrow">功能引导</p>
                        <h3>新手教程</h3>
                        <p class="tutorial-intro-desc">
                          通过高亮 + 悬浮说明窗，快速了解主要功能入口和常用设置。
                        </p>
                      </div>

                      <div class="tutorial-intro-features">
                        <div class="tutorial-feature-item">
                          <div>
                            <h4>主界面导览</h4>
                            <p>认识侧边栏、工作区、模型与模式选择。</p>
                          </div>
                        </div>
                        <div class="tutorial-feature-item">
                          <div>
                            <h4>快捷菜单</h4>
                            <p>学习上传文件、对话回顾、用量统计等高频功能。</p>
                          </div>
                        </div>
                        <div class="tutorial-feature-item">
                          <div>
                            <h4>个人空间</h4>
                            <p>了解模型偏好、主题、Skills、图片压缩等配置。</p>
                          </div>
                        </div>
                      </div>

                      <div class="tutorial-intro-actions">
                        <button type="button" class="tutorial-start-button" @click="startTutorial">
                          开始新手教程
                        </button>
                        <p class="tutorial-intro-hint">教程开始后会自动关闭个人空间，您可随时退出或跳过当前步骤。</p>
                      </div>
                    </div>
                  </section>
                  <section v-else-if="activeTab === 'admin-monitor'" key="admin-monitor" class="personal-page admin-monitor-page">
                    <div class="admin-monitor-panel">
                      <div class="admin-monitor-heading">
                        <p class="admin-monitor-eyebrow">系统资源</p>
                        <div class="admin-monitor-title-row">
                          <h3>管理员监控入口</h3>
                          <span class="admin-monitor-chip">自动刷新</span>
                        </div>
                        <p class="admin-monitor-desc">独立面板集中展示配额趋势、容器运行、项目存储与上传安全。</p>
                      </div>
                      <div class="admin-monitor-highlights">
                        <span class="admin-monitor-tag">用量统计</span>
                        <span class="admin-monitor-tag">容器健康</span>
                        <span class="admin-monitor-tag">上传审计</span>
                        <span class="admin-monitor-tag">邀请码管理</span>
                      </div>
                      <div class="admin-monitor-actions">
                        <button type="button" class="admin-monitor-button" @click="openAdminPanel">
                          打开监控面板
                        </button>
                        <button type="button" class="admin-monitor-button ghost" @click="openApiAdmin">
                          API 管理
                        </button>
                        <p class="admin-monitor-hint">新窗口开启，不打断当前对话与配置。</p>
                      </div>
                    </div>
                    <div class="admin-monitor-panel secondary">
                      <div class="admin-monitor-heading">
                        <p class="admin-monitor-eyebrow">自定义工具</p>
                        <div class="admin-monitor-title-row">
                          <h3>自定义工具管理</h3>
                          <span class="admin-monitor-chip alt">低代码 · Python</span>
                        </div>
                        <p class="admin-monitor-desc">在线创建/编辑 definition.json、execution.py、return.json、meta.json，保存后自动生效。</p>
                      </div>
                      <div class="admin-monitor-highlights">
                        <span class="admin-monitor-tag">仅管理员可见</span>
                        <span class="admin-monitor-tag">容器内执行</span>
                        <span class="admin-monitor-tag">无需重启</span>
                        <span class="admin-monitor-tag">三层拆分</span>
                      </div>
                      <div class="admin-monitor-actions">
                        <button type="button" class="admin-monitor-button" @click="openCustomTools">
                          打开自定义工具
                        </button>
                        <p class="admin-monitor-hint">新窗口打开 /admin/custom-tools 页面。</p>
                      </div>
                    </div>
                  </section>
                  </transition>
                </div>
              </div>
            </div>
          </form>
        </div>
        <div class="personalization-loading" v-else>正在加载个性化配置...</div>
      </div>
    </div>
  </transition>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import { usePersonalizationStore, type BlockDisplayMode } from '@/stores/personalization';
import { useResourceStore } from '@/stores/resource';
import { useUiStore } from '@/stores/ui';
import { usePolicyStore } from '@/stores/policy';
import { useTutorialStore } from '@/stores/tutorial';
import { formatTokenCount } from '@/utils/formatters';
import { useTheme } from '@/utils/theme';
import type { ThemeKey } from '@/utils/theme';

defineOptions({ name: 'PersonalizationDrawer' });

const personalization = usePersonalizationStore();
const resourceStore = useResourceStore();
const uiStore = useUiStore();
const tutorialStore = useTutorialStore();
const {
  visible,
  loading,
  form,
  tonePresets,
  newConsideration,
  maxConsiderations,
  status,
  error,
  saving,
  toggleUpdating,
  toolCategories,
  skillsCatalog,
  thinkingIntervalDefault,
  thinkingIntervalRange,
  experiments
} = storeToRefs(personalization);

const baseTabs = [
  { id: 'preferences', label: '个性化设置', description: '称呼、语气与注意事项' },
  { id: 'model', label: '模型偏好', description: '默认模型选择' },
  { id: 'usage', label: '用量统计', description: '对话累计数据' },
  { id: 'app-update', label: '软件更新', description: '检查并下载新版 APK' },
  { id: 'behavior', label: '模型行为', description: '工具提示与界面表现' },
  { id: 'skills', label: 'Skills', description: '可用技能开关' },
  { id: 'image', label: '图片压缩', description: '发送图片的尺寸策略' },
  { id: 'theme', label: '主题切换', description: '浅色 / 深色 / Claude' },
  { id: 'tutorial', label: '新手教程', description: '功能引导与使用说明' }
] as const;

type PersonalTab =
  | 'preferences'
  | 'model'
  | 'usage'
  | 'app-update'
  | 'behavior'
  | 'skills'
  | 'image'
  | 'theme'
  | 'tutorial'
  | 'admin-monitor';

const isAdmin = computed(() => (resourceStore.usageQuota.role || '').toLowerCase() === 'admin');
const isAppShell = computed(() => {
  if (typeof window === 'undefined') return false;
  const params = new URLSearchParams(window.location.search);
  if (params.has('app_shell')) return true;
  return Boolean((window as any)?.AndroidThemeBridge);
});

const personalTabs = computed(() => {
  const tabs = baseTabs.filter((tab) => (tab.id === 'app-update' ? isAppShell.value : true));
  if (isAdmin.value) {
    tabs.push({ id: 'admin-monitor' as const, label: '管理员监控', description: '系统总览' });
  }
  return tabs;
});

const activeTab = ref<PersonalTab>('preferences');
const swipeState = ref<{ startY: number; active: boolean }>({ startY: 0, active: false });

type RunModeValue = 'fast' | 'thinking' | 'deep' | null;
type CompressionField =
  | 'shallow_compress_trigger_tokens'
  | 'shallow_compress_keep_recent_tools'
  | 'shallow_compress_max_replace_per_round'
  | 'shallow_compress_trigger_tool_calls_interval'
  | 'deep_compress_trigger_tokens';

const runModeOptions: Array<{ id: string; label: string; desc: string; value: RunModeValue; badge?: string }> = [
  { id: 'fast', label: '快速模式', desc: '追求响应速度，跳过思考模型', value: 'fast' },
  { id: 'thinking', label: '思考模式', desc: '首轮回复会先输出思考过程', value: 'thinking', badge: '推荐' },
  { id: 'deep', label: '深度思考', desc: '整轮对话都使用思考模型', value: 'deep' }
];

const policyStore = usePolicyStore();

const modelOptions = [
  { id: 'deepseek', label: 'DeepSeek', desc: '通用 + 思考强化', value: 'deepseek' },
  { id: 'kimi-k2.5', label: 'Kimi-k2.5', desc: '新版 Kimi，思考开关 + 图文多模态', value: 'kimi-k2.5', badge: '图文' },
  { id: 'kimi', label: 'Kimi-k2', desc: '旧版 Kimi-k2，兼顾通用对话', value: 'kimi' },
  { id: 'qwen3-vl-plus', label: 'Qwen3.5', desc: '图文多模态 + 深度思考', value: 'qwen3-vl-plus', badge: '图文' },
  { id: 'minimax-m2.5', label: 'MiniMax-M2.5', desc: '仅深度思考，超长上下文', value: 'minimax-m2.5', badge: '深度思考' }
] as const;

const filteredModelOptions = computed(() =>
  modelOptions.map((opt) => ({
    ...opt,
    disabled: policyStore.disabledModelSet.has(opt.value)
  }))
);

const thinkingPresets = [
  { id: 'low', label: '低', value: 10 },
  { id: 'medium', label: '中', value: 5 },
  { id: 'high', label: '高', value: 3 }
];

const imageCompressionOptions = [
  { id: 'original', label: '原图', desc: '不压缩' },
  { id: '1080p', label: '1080p', desc: '最长边不超过 1080p 等比缩放' },
  { id: '720p', label: '720p', desc: '最长边不超过 720p 等比缩放' },
  { id: '540p', label: '540p', desc: '最长边不超过 540p 等比缩放' }
] as const;

const usageSummary = ref({
  total_input_tokens: 0,
  total_output_tokens: 0,
  total_conversations: 0,
  total_user_messages: 0,
  total_tools: 0
});
const usageLoading = ref(false);
const usageError = ref('');
const usageUpdatedAt = ref<string | null>(null);

const usageUpdatedText = computed(() => {
  if (!usageUpdatedAt.value) {
    return '尚未刷新';
  }
  const date = new Date(usageUpdatedAt.value);
  if (Number.isNaN(date.getTime())) {
    return '时间未知';
  }
  return date.toLocaleString('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit'
  });
});

const appCurrentVersionCode = ref<number | null>(null);
const appCurrentVersionName = ref<string>('');
const appUpdateChecking = ref(false);
const appUpdateError = ref('');
const appUpdateCheckedAt = ref<string | null>(null);
const appUpdateInfo = ref<{
  latestVersionCode: number;
  latestVersionName: string;
  apkUrl: string;
  fileSizeBytes: number;
  changelog?: string;
  publishedAt?: string | null;
  hasUpdate?: boolean | null;
} | null>(null);

if (typeof window !== 'undefined') {
  const params = new URLSearchParams(window.location.search);
  const vcRaw = params.get('app_vc') || '';
  const vnRaw = params.get('app_vn') || '';
  const bridge = (window as any)?.AndroidThemeBridge;
  const bridgeVcRaw = bridge && typeof bridge.getAppVersionCode === 'function' ? String(bridge.getAppVersionCode() || '') : '';
  const bridgeVnRaw = bridge && typeof bridge.getAppVersionName === 'function' ? String(bridge.getAppVersionName() || '') : '';
  // App 端优先使用 Bridge 实时版本，避免 WebView 恢复旧 URL 参数导致显示过期版本号
  const finalVcRaw = bridgeVcRaw || vcRaw;
  const finalVnRaw = bridgeVnRaw || vnRaw;
  appCurrentVersionCode.value = /^\d+$/.test(finalVcRaw) ? Number(finalVcRaw) : null;
  appCurrentVersionName.value = finalVnRaw || '';
}

const hydrateAppVersionFromBridge = () => {
  if (typeof window === 'undefined') return;
  const bridge = (window as any)?.AndroidThemeBridge;
  if (!bridge) return;
  try {
    const vcRaw = typeof bridge.getAppVersionCode === 'function' ? String(bridge.getAppVersionCode() || '') : '';
    const vnRaw = typeof bridge.getAppVersionName === 'function' ? String(bridge.getAppVersionName() || '') : '';
    if (vcRaw && /^\d+$/.test(vcRaw)) {
      appCurrentVersionCode.value = Number(vcRaw);
    }
    if (vnRaw) {
      appCurrentVersionName.value = vnRaw;
    }
  } catch {
    // ignore bridge read failures
  }
};

const appCurrentVersionText = computed(() => {
  const vn = appCurrentVersionName.value || '未知';
  const vc = appCurrentVersionCode.value ?? '?';
  return `${vn} (${vc})`;
});

const appLatestVersionText = computed(() => {
  if (!appUpdateInfo.value) return '--';
  return `${appUpdateInfo.value.latestVersionName || '未知'} (${appUpdateInfo.value.latestVersionCode ?? '?'})`;
});

const appLatestFileSizeText = computed(() => {
  const bytes = Number(appUpdateInfo.value?.fileSizeBytes || 0);
  if (!bytes) return '--';
  const mb = bytes / 1024 / 1024;
  return `${mb.toFixed(mb >= 100 ? 0 : 1)} MB`;
});

const appUpdateChangelogText = computed(() => {
  const text = (appUpdateInfo.value?.changelog || '').trim();
  return text || '';
});

const appHasUpdate = computed(() => {
  if (!appUpdateInfo.value) return false;
  if (typeof appUpdateInfo.value.hasUpdate === 'boolean') return appUpdateInfo.value.hasUpdate;
  if (appCurrentVersionCode.value == null) return false;
  return Number(appUpdateInfo.value.latestVersionCode || 0) > appCurrentVersionCode.value;
});

const appDownloadUrl = computed(() => appUpdateInfo.value?.apkUrl || '');

const appUpdateStateText = computed(() => {
  if (!appUpdateInfo.value) return '未检查';
  return appHasUpdate.value ? '发现新版本' : '已是最新';
});

const appUpdateCheckedText = computed(() => {
  if (!appUpdateCheckedAt.value) return '尚未检查更新';
  const d = new Date(appUpdateCheckedAt.value);
  if (Number.isNaN(d.getTime())) return '刚刚检查过';
  return `最近检查：${d.toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}`;
});

const fetchUsageSummary = async () => {
  if (usageLoading.value) {
    return;
  }
  usageLoading.value = true;
  usageError.value = '';
  try {
    const response = await fetch('/api/conversations/statistics');
    const payload = await response.json();
    if (!response.ok || !payload.success) {
      throw new Error(payload.error || payload.message || '获取用量统计失败');
    }
    const data = payload.data || {};
    const tokenStats = data.token_statistics || {};
    usageSummary.value = {
      total_input_tokens: Number(tokenStats.total_input_tokens || 0),
      total_output_tokens: Number(tokenStats.total_output_tokens || 0),
      total_conversations: Number(data.total_conversations || 0),
      total_user_messages: Number(data.total_user_messages || 0),
      total_tools: Number(data.total_tools || 0)
    };
    usageUpdatedAt.value = new Date().toISOString();
  } catch (error: any) {
    usageError.value = error?.message || '获取用量统计失败';
  } finally {
    usageLoading.value = false;
  }
};

const checkAppUpdate = async () => {
  if (appUpdateChecking.value) return;
  hydrateAppVersionFromBridge();
  appUpdateChecking.value = true;
  appUpdateError.value = '';
  try {
    const params = new URLSearchParams();
    if (appCurrentVersionCode.value != null) {
      params.set('currentVersionCode', String(appCurrentVersionCode.value));
    }
    const suffix = params.toString() ? `?${params.toString()}` : '';
    const resp = await fetch(`/api/app/version${suffix}`);
    const payload = await resp.json();
    if (!resp.ok || !payload?.success) {
      throw new Error(payload?.error || '检查更新失败');
    }
    const data = payload?.data || {};
    appUpdateInfo.value = {
      latestVersionCode: Number(data.latestVersionCode || 0),
      latestVersionName: String(data.latestVersionName || ''),
      apkUrl: String(data.apkUrl || ''),
      fileSizeBytes: Number(data.fileSizeBytes || 0),
      changelog: String(data.changelog || ''),
      publishedAt: data.publishedAt || null,
      hasUpdate: typeof data.hasUpdate === 'boolean' ? data.hasUpdate : null
    };
    appUpdateCheckedAt.value = new Date().toISOString();
  } catch (error: any) {
    appUpdateError.value = error?.message || '检查更新失败';
  } finally {
    appUpdateChecking.value = false;
  }
};

const downloadLatestApp = () => {
  const url = appDownloadUrl.value;
  if (!url) {
    appUpdateError.value = '未拿到下载地址';
    return;
  }
  window.location.href = url;
};

onMounted(() => {
  hydrateAppVersionFromBridge();
});

watch(
  () => [activeTab.value, visible.value],
  ([tab, isVisible]) => {
    if (isVisible && tab === 'usage') {
      fetchUsageSummary();
    }
    if (isVisible && tab === 'app-update' && isAppShell.value && !appUpdateInfo.value && !appUpdateChecking.value) {
      checkAppUpdate();
    }
  }
);

const setActiveTab = (tab: PersonalTab) => {
  activeTab.value = tab;
};

const startTutorial = () => {
  personalization.closeDrawer();
  window.setTimeout(() => {
    tutorialStore.startTutorial();
  }, 320);
};

const shiftTab = (direction: 1 | -1) => {
  const tabs = personalTabs.value;
  const currentIndex = tabs.findIndex((tab) => tab.id === activeTab.value);
  if (currentIndex === -1) {
    return;
  }
  const nextIndex = currentIndex + direction;
  if (nextIndex < 0 || nextIndex >= tabs.length) {
    return;
  }
  activeTab.value = tabs[nextIndex].id as PersonalTab;
};

const handleSwipeStart = (event: TouchEvent) => {
  // 手机端禁用滑动切换标签页
  if (window.innerWidth <= 768) {
    return;
  }
  if (!event.touches.length) {
    return;
  }
  swipeState.value = { startY: event.touches[0].clientY, active: true };
};

const handleSwipeEnd = (event: TouchEvent) => {
  // 手机端禁用滑动切换标签页
  if (window.innerWidth <= 768) {
    return;
  }
  if (!swipeState.value.active || !event.changedTouches.length) {
    return;
  }
  const deltaY = event.changedTouches[0].clientY - swipeState.value.startY;
  swipeState.value.active = false;
  if (Math.abs(deltaY) < 60) {
    return;
  }
  shiftTab(deltaY < 0 ? 1 : -1);
};

const applyThinkingPreset = (value: number) => {
  personalization.setThinkingInterval(value);
};

const isRunModeActive = (value: RunModeValue) => {
  if (value === null) {
    return !form.value.default_run_mode;
  }
  return form.value.default_run_mode === value;
};

const setDefaultRunMode = (value: RunModeValue) => {
  if (checkModeModelConflict(value, form.value.default_model)) {
    return;
  }
  personalization.setDefaultRunMode(value);
};

const setDefaultModel = (value: string) => {
  if (policyStore.disabledModelSet.has(value)) {
    uiStore.pushToast({
      title: '模型被禁用',
      message: '已被管理员禁用，无法选择',
      type: 'warning'
    });
    return;
  }
  if (checkModeModelConflict(form.value.default_run_mode, value)) {
    return;
  }
  personalization.setDefaultModel(value);
};

const checkModeModelConflict = (mode: RunModeValue, model: string | null): boolean => {
  const warnings: string[] = [];
  if (model === 'minimax-m2.5' && mode && mode !== 'deep') {
    warnings.push('MiniMax-M2.5 仅支持深度思考模式，已保持原设置。');
  }
  if (warnings.length) {
    uiStore.pushToast({
      title: '模型/思考模式不兼容',
      message: warnings.join(' '),
      type: 'warning',
      duration: 6000
    });
    return true;
  }
  return false;
};

const handleThinkingInput = (event: Event) => {
  const target = event.target as HTMLInputElement;
  if (!target.value) {
    personalization.setThinkingInterval(null);
    return;
  }
  const parsed = Number(target.value);
  personalization.setThinkingInterval(Number.isNaN(parsed) ? null : parsed);
};

const restoreThinkingInterval = () => {
  personalization.setThinkingInterval(null);
};

const handleCompressionNumberInput = (key: CompressionField, event: Event) => {
  const target = event.target as HTMLInputElement | null;
  if (!target || !target.value) {
    personalization.updateField({ key, value: null });
    return;
  }
  const parsed = Number(target.value);
  if (!Number.isFinite(parsed)) {
    personalization.updateField({ key, value: null });
    return;
  }
  personalization.updateField({ key, value: Math.round(parsed) });
};

const restoreCompressionDefaults = () => {
  personalization.updateField({ key: 'shallow_compress_trigger_tokens', value: null });
  personalization.updateField({ key: 'shallow_compress_keep_recent_tools', value: null });
  personalization.updateField({ key: 'shallow_compress_max_replace_per_round', value: null });
  personalization.updateField({ key: 'shallow_compress_trigger_tool_calls_interval', value: null });
  personalization.updateField({ key: 'deep_compress_trigger_tokens', value: null });
};

const isPresetActive = (value: number) => {
  if (form.value.thinking_interval === null || typeof form.value.thinking_interval === 'undefined') {
    return value === thinkingIntervalDefault.value;
  }
  return form.value.thinking_interval === value;
};

const toggleCategory = (categoryId: string) => {
  personalization.toggleDefaultToolCategory(categoryId);
};

const blockDisplayOptions = [
  { id: 'traditional', label: '传统列表', desc: '按时间顺序垂直排列，经典样式', value: 'traditional' as const },
  { id: 'stacked', label: '堆叠动画', desc: '超过 6 条自动收纳为"更多"，动态展示', value: 'stacked' as const, badge: '推荐' },
  { id: 'minimal', label: '极简模式', desc: '摘要行 + 无缝展开，流式输出效果', value: 'minimal' as const, badge: '新' }
];

const handleBlockDisplayModeChange = (mode: 'traditional' | 'stacked' | 'minimal') => {
  personalization.setBlockDisplayMode(mode);
};

const openAdminPanel = () => {
  window.open('/admin/monitor', '_blank', 'noopener');
  personalization.closeDrawer();
};

const openCustomTools = () => {
  window.open('/admin/custom-tools', '_blank', 'noopener');
  personalization.closeDrawer();
};

const openApiAdmin = () => {
  window.open('/admin/api', '_blank', 'noopener');
  personalization.closeDrawer();
};

// ===== 主题切换 =====
const { setTheme, loadTheme } = useTheme();
const themeOptions: Array<{ id: ThemeKey; label: string; desc: string; swatches: string[] }> = [
  {
    id: 'claude',
    label: 'Claude 经典',
    desc: '仿 Claude 的米色质感，柔和高对比',
    swatches: ['#eeece2', '#f7f3ea', '#da7756']
  },
  {
    id: 'light',
    label: '明亮',
    desc: '纯白底色 + 优雅灰，类似 ChatGPT 风格',
    swatches: ['#ffffff', '#f7f7f8', '#6b7280']
  },
  {
    id: 'dark',
    label: '夜间',
    desc: '深灰 + 黑，低亮度并保持彩色点缀',
    swatches: ['#1a1a1a', '#2a2a2a', '#3a3a3a']
  }
];

const activeTheme = ref<ThemeKey>(loadTheme());

const applyThemeOption = (theme: ThemeKey) => {
  activeTheme.value = theme;
  setTheme(theme);
};
</script>

<style scoped>
.compression-custom-grid {
  margin-top: 10px;
  display: grid;
  gap: 10px;
}

.compression-input-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  color: var(--claude-text-secondary);
  font-size: 12px;
}

.compression-input-row input {
  border: 1px solid var(--claude-border);
  border-radius: 10px;
  background: var(--claude-panel);
  color: var(--claude-text);
  padding: 8px 10px;
  font-size: 13px;
}

.compression-custom-hint {
  margin-top: 8px;
}

.compression-actions-row {
  margin-top: 4px;
  display: flex;
  justify-content: flex-end;
}

.compression-reset-btn {
  border: 1px solid var(--claude-border);
  border-radius: 10px;
  padding: 6px 12px;
  background: var(--claude-panel);
  color: var(--claude-text);
  font-size: 12px;
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.compression-reset-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 18px rgba(61, 57, 41, 0.14);
}

.usage-summary-page {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 12px 0 24px;
  height: 100%;
}

.usage-summary-card {
  width: 100%;
  max-width: 720px;
  padding: 0;
  min-height: 320px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  flex: 1 1 auto;
  min-height: 0;
}

.usage-summary-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.usage-summary-header h3 {
  margin: 4px 0 6px;
  font-size: 24px;
}

.usage-summary-eyebrow {
  margin: 0;
  font-size: 12px;
  color: var(--claude-accent-strong);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.usage-summary-desc {
  margin: 0;
  color: var(--claude-text-secondary);
}

.usage-summary-note {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--claude-text-tertiary);
}

.usage-summary-refresh {
  border: 1px solid var(--claude-border);
  border-radius: 12px;
  padding: 6px 14px;
  background: var(--claude-panel);
  color: var(--claude-text);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  box-shadow: 0 6px 14px rgba(61, 57, 41, 0.12);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.usage-summary-refresh:disabled {
  opacity: 0.7;
  cursor: not-allowed;
  box-shadow: none;
}

.usage-summary-refresh:not(:disabled):hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 28px rgba(61, 57, 41, 0.22);
}

.app-update-page .app-update-actions {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.app-update-changelog {
  border: 1px solid var(--claude-border);
  border-radius: 14px;
  padding: 12px;
  background: var(--claude-panel);
  max-height: 300px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.app-update-changelog-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--claude-text);
  margin-bottom: 8px;
}

.app-update-changelog-content {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 12px;
  line-height: 1.55;
  color: var(--claude-text-secondary);
  flex: 1 1 auto;
  min-height: 0;
  max-height: 240px;
  overflow: auto;
}

.usage-summary-grid {
  display: grid;
  gap: 14px;
}

.usage-summary-grid--tokens {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.usage-summary-grid--counts {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.usage-summary-item {
  padding: 14px 16px;
  border-radius: 16px;
  border: 1px solid var(--claude-border);
  background: transparent;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.usage-summary-item .label {
  font-size: 12px;
  color: var(--claude-text-secondary);
}

.usage-summary-item .value {
  font-size: 22px;
  font-weight: 600;
  color: var(--claude-text);
}

.usage-summary-item .value--success {
  color: var(--claude-success);
}

.usage-summary-item .value--warning {
  color: var(--claude-warning);
}

.usage-summary-item .value--accent {
  color: var(--claude-text);
}

.usage-summary-meta {
  font-size: 12px;
  color: var(--claude-text-secondary);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: auto;
}

.usage-summary-error {
  color: var(--claude-warning);
}

.admin-monitor-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: center;
  min-height: 320px;
  padding: 12px 0 24px;
}

.admin-monitor-panel {
  width: 100%;
  max-width: 640px;
  padding: 28px 32px;
  border-radius: 26px;
  border: 1px solid var(--theme-control-border, var(--claude-border));
  background: linear-gradient(145deg, var(--theme-surface-soft), var(--theme-surface-muted));
  box-shadow: var(--theme-shadow-soft, var(--claude-shadow));
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.admin-monitor-panel.secondary {
  background: linear-gradient(145deg, var(--theme-surface-muted), var(--theme-surface-soft));
}

.admin-monitor-heading {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.admin-monitor-title-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.admin-monitor-title-row h3 {
  margin: 0;
  font-size: 24px;
}

.admin-monitor-desc {
  margin: 0;
  color: var(--claude-text-secondary);
  max-width: 460px;
}

.admin-monitor-chip {
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--theme-chip-border, var(--claude-border));
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--claude-text-secondary);
  background: var(--theme-chip-bg, var(--claude-panel));
}

.admin-monitor-eyebrow {
  font-size: 12px;
  color: var(--claude-accent-strong);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.admin-monitor-highlights {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.admin-monitor-tag {
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px dashed var(--theme-chip-border, var(--claude-border));
  background: var(--theme-chip-bg, var(--claude-panel));
  font-size: 13px;
  color: var(--claude-text-secondary);
}

.section-note {
  margin: 6px 0 14px;
  font-size: 12px;
  color: var(--claude-text-secondary);
}

.admin-monitor-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.admin-monitor-button {
  border: none;
  border-radius: 16px;
  padding: 11px 28px;
  background: linear-gradient(135deg, var(--claude-accent), var(--claude-accent-strong));
  color: #fff;
  font-weight: 600;
  letter-spacing: 0.04em;
  box-shadow: var(--theme-shadow-soft, var(--claude-shadow));
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.admin-monitor-button.ghost {
  background: transparent;
  color: var(--claude-text);
  border: 1px dashed var(--theme-chip-border, var(--claude-border));
  box-shadow: none;
}

.admin-monitor-button:hover {
  transform: translateY(-1px);
  box-shadow: var(--theme-shadow-mid, var(--claude-shadow));
}

.admin-monitor-button:active {
  transform: translateY(0);
  box-shadow: var(--theme-shadow-soft, var(--claude-shadow));
}

.admin-monitor-hint {
  margin: 0;
  font-size: 13px;
  color: var(--claude-text-secondary);
}

@media (max-width: 640px) {
  .usage-summary-refresh {
    width: 100%;
    justify-content: center;
  }

  .usage-summary-grid--tokens,
  .usage-summary-grid--counts {
    grid-template-columns: 1fr;
  }

  .admin-monitor-panel {
    padding: 24px;
  }

  .admin-monitor-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .admin-monitor-button {
    width: 100%;
    justify-content: center;
  }

  .admin-monitor-hint {
    text-align: center;
  }
}
</style>
