<template>
  <div class="shell-page shell-page-fluid page-section websites-page">
    <div class="panel">
      <div class="panel-head">
        <div class="panel-title">检测与变更控制台</div>
        <div class="panel-actions">
          <el-button size="small" text @click="loadAll">刷新</el-button>
          <el-button size="small" type="primary" @click="openWebsiteCreate">新增网站</el-button>
        </div>
      </div>
      <el-table :data="websites" v-loading="websiteLoading" row-key="id" style="width:100%">
        <el-table-column label="名称" min-width="180">
          <template #default="{ row }">
            <div class="cell-name">{{ row.name }}</div>
            <div class="cell-url">{{ row.base_url }}</div>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="110">
          <template #default="{ row }">
            <span :class="['status-badge', row.last_status]"><span class="dot" />{{ statusLabel(row.last_status) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="自动同步" width="100">
          <template #default="{ row }">
            <el-switch v-model="row.auto_sync_enabled" @change="toggleWebsiteSync(row)" />
          </template>
        </el-table-column>
        <el-table-column label="超时" width="80">
          <template #default="{ row }">{{ row.timeout_seconds }}s</template>
        </el-table-column>
        <el-table-column label="最近错误" min-width="180">
          <template #default="{ row }">
            <el-tooltip v-if="row.last_error" :content="row.last_error" placement="top" :show-after="300">
              <span class="error-text">{{ row.last_error.substring(0, 42) }}…</span>
            </el-tooltip>
            <span v-else class="muted">—</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="340">
          <template #default="{ row }">
            <div class="action-row">
              <el-button size="small" text @click="openWebsiteEdit(row)" title="编辑网站配置（API凭证、参数等）">编辑</el-button>
              <el-button size="small" text @click="selectWebsite(row)" title="查看当前网站的分组和绑定配置">查看</el-button>
              <el-button size="small" text @click="testWebsite(row)" :loading="row._testing" title="仅验证连通性，测试API是否正常响应">测试连接</el-button>
              <el-button size="small" text @click="openBindingCreate(row)" title="为此网站创建一个新的上游倍率绑定规则">新增绑定</el-button>
              <el-button size="small" text @click="openImportGroups(row)" title="一键从上游导入可用分组到此网站">导入分组</el-button>
              <el-button size="small" text @click="openImportAccounts(row)" title="将此网站下的所有账户批量导入账号管理">导入账号</el-button>
              <el-button size="small" text type="danger" @click="deleteWebsite(row)" title="删除此网站及其所有的绑定配置">删除</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <div class="content-grid">
      <div class="panel">
        <div class="panel-head">
          <div>
            <div class="panel-title">我的网站分组</div>
            <div class="panel-sub">{{ selectedWebsite?.name || '请选择网站' }}</div>
          </div>
          <el-select
            :model-value="selectedWebsite?.id"
            size="small"
            filterable
            class="site-switcher"
            placeholder="切换网站"
            @change="onSelectedWebsiteChange"
          >
            <el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
          </el-select>
          <el-button size="small" :disabled="!selectedWebsite" :loading="groupsLoading" @click="loadWebsiteGroups">拉取分组</el-button>
          <el-button size="small" type="primary" :disabled="!selectedWebsite" @click="openGroupCreate">新增分组</el-button>
        </div>
        <el-table :data="sortedWebsiteGroups" v-loading="groupsLoading" row-key="id" size="small" style="width:100%">
          <el-table-column prop="name" label="分组" min-width="150" />
          <el-table-column prop="id" label="ID" min-width="130" />
          <el-table-column prop="description" label="描述" min-width="150" />
          <el-table-column label="倍率" width="100">
            <template #default="{ row }"><span class="rate-value">{{ row.rate_multiplier ?? '—' }}</span></template>
          </el-table-column>
          <el-table-column label="操作" width="140">
            <template #default="{ row }">
              <el-button size="small" text :disabled="!selectedWebsite" @click="openBindingCreate(selectedWebsite, row)">绑定</el-button>
              <el-button size="small" text :disabled="!selectedWebsite" @click="openGroupEdit(row)">编辑</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <div class="panel">
        <div class="panel-head">
          <div>
            <div class="panel-title">分组绑定</div>
            <div class="panel-sub">{{ selectedWebsite?.name || '请选择网站' }}</div>
          </div>
          <el-select
            :model-value="selectedWebsite?.id"
            size="small"
            filterable
            class="site-switcher"
            placeholder="切换网站"
            @change="onSelectedWebsiteChange"
          >
            <el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
          </el-select>
          <el-button
            size="small"
            text
            :loading="batchSyncLoading"
            :disabled="!selectedWebsite || selectedWebsiteBindings.length === 0"
            @click="syncAllWebsiteBindings"
            title="同步当前网站的所有分组绑定"
          >
            一键同步
          </el-button>
          <el-button
            size="small"
            text
            :loading="organizeLoading"
            :disabled="!selectedWebsite || selectedWebsiteBindings.length === 0"
            @click="organizeWebsiteGroups"
            title="按当前网站的现有绑定关系一键整理分组并导入账号"
          >
            一键整理分组
          </el-button>
          <el-button
            size="small"
            text
            :disabled="!selectedWebsite"
            @click="openCleanupDialog"
            title="清理当前网站已导入但失效/孤立的账号"
          >
            清理失效账号
          </el-button>
          <el-button
            size="small"
            text
            :disabled="!selectedWebsite"
            @click="openConcurrencyDialog"
            title="一键设置当前网站已导入账号的并发数"
          >
            设置账号并发
          </el-button>
          <el-button
            size="small"
            text
            :disabled="!selectedWebsite"
            @click="triggerSyncUpstreamModels"
            title="一键同步当前网站已导入账号的上游支持模型"
          >
            同步上游模型
          </el-button>
          <el-button size="small" text :disabled="websites.length === 0" @click="openBindingCreate(selectedWebsite || websites[0])">新增绑定</el-button>
        </div>
        <div class="binding-list" v-loading="bindingLoading">
          <div v-for="binding in selectedWebsiteBindings" :key="binding.id" class="binding-item">
            <div class="binding-main">
              <div class="binding-title">{{ binding.website_name }} / {{ binding.target_group_name || binding.target_group_id }}</div>
              <div class="binding-meta">
                {{ algorithmLabel(binding.algorithm) }} + {{ binding.percent }}% ·
                {{ binding.source_groups.length }} 个上游分组
              </div>
            </div>
            <div class="binding-actions">
              <el-switch v-model="binding.enabled" @change="toggleBinding(binding)" />
              <el-button size="small" text :loading="binding._syncing" @click="syncBinding(binding)">同步</el-button>
              <el-button size="small" text @click="openBindingEdit(binding)"><el-icon><Edit /></el-icon></el-button>
              <el-button size="small" text type="danger" @click="deleteBinding(binding)"><el-icon><Delete /></el-icon></el-button>
            </div>
          </div>
          <div v-if="!bindingLoading && selectedWebsiteBindings.length === 0" class="empty-hint">暂无绑定</div>
        </div>
      </div>
    </div>

    <div class="panel">
      <div class="panel-head">
        <div class="panel-title">最近同步结果</div>
        <el-button size="small" text @click="loadLogs">刷新</el-button>
      </div>
      <el-table :data="logs" v-loading="logLoading" row-key="id" size="small" style="width:100%">
        <el-table-column label="时间" width="150">
          <template #default="{ row }">{{ fmtTime(row.created_at) }}</template>
        </el-table-column>
        <el-table-column label="目标分组" min-width="160">
          <template #default="{ row }">{{ row.target_group_name || row.target_group_id }}</template>
        </el-table-column>
        <el-table-column label="倍率" width="130">
          <template #default="{ row }">
            <span class="rate-value">{{ row.old_rate ?? '—' }} → {{ row.new_rate ?? '—' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="90">
          <template #default="{ row }">
            <el-tag size="small" :type="row.status === 'success' ? 'success' : 'danger'">{{ row.status === 'success' ? '成功' : '失败' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="message" label="结果" min-width="220" />
      </el-table>
    </div>

    <el-drawer v-model="websiteDrawer" :title="editingWebsiteId ? '编辑网站' : '新增网站'" size="460px" destroy-on-close>
      <el-form ref="websiteFormRef" :model="websiteForm" :rules="websiteRules" label-position="top">
        <el-form-item label="名称" prop="name"><el-input v-model="websiteForm.name" placeholder="我的 sub2api" /></el-form-item>
        <el-form-item label="Base URL" prop="base_url"><el-input v-model="websiteForm.base_url" placeholder="https://sub2api.example.com" /></el-form-item>
        <el-form-item label="API Prefix"><el-input v-model="websiteForm.api_prefix" placeholder="/api/v1/admin" /></el-form-item>
        <el-form-item label="认证方式">
          <el-select v-model="websiteForm.auth_type" style="width:100%">
            <el-option label="x-api-key" value="api_key" />
            <el-option label="Bearer JWT" value="bearer" />
          </el-select>
        </el-form-item>
        <template v-if="websiteForm.auth_type === 'api_key'">
          <el-form-item label="Admin API Key"><el-input v-model="websiteForm.auth_config.key" type="password" show-password placeholder="admin-..." /></el-form-item>
          <el-form-item label="Header"><el-input v-model="websiteForm.auth_config.header" placeholder="x-api-key" /></el-form-item>
        </template>
        <template v-else>
          <el-form-item label="JWT"><el-input v-model="websiteForm.auth_config.token" type="password" show-password placeholder="***" /></el-form-item>
        </template>
        <el-row :gutter="12">
          <el-col :span="12"><el-form-item label="分组接口"><el-input v-model="websiteForm.groups_endpoint" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="更新接口"><el-input v-model="websiteForm.group_update_endpoint" /></el-form-item></el-col>
        </el-row>
        <el-form-item label="超时（秒）"><el-input-number v-model="websiteForm.timeout_seconds" :min="5" :max="120" style="width:100%" /></el-form-item>
        <div class="switch-line">
          <span>启用网站</span><el-switch v-model="websiteForm.enabled" />
        </div>
        <div class="switch-line">
          <span>启用自动同步</span><el-switch v-model="websiteForm.auto_sync_enabled" />
        </div>
      </el-form>
      <template #footer>
        <el-button @click="websiteDrawer = false">取消</el-button>
        <el-button type="primary" :loading="savingWebsite" @click="saveWebsite">保存</el-button>
      </template>
    </el-drawer>

    <el-drawer v-model="bindingDrawer" :title="editingBindingId ? '编辑绑定' : '新增绑定'" size="560px" destroy-on-close class="custom-binding-drawer">
      <el-form ref="bindingFormRef" :model="bindingForm" :rules="bindingRules" label-position="top">
        <el-form-item label="目标网站">
          <div class="custom-select-wrapper">
            <el-select v-model="bindingForm.website_id" style="width:100%" @change="onBindingWebsiteChange" class="custom-theme-select">
              <el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
            </el-select>
          </div>
        </el-form-item>
        <el-form-item label="目标分组" prop="target_group_id">
          <div class="custom-select-wrapper">
            <el-select v-model="bindingForm.target_group_id" filterable style="width:100%" @change="onTargetGroupChange" class="custom-theme-select">
              <el-option v-for="group in bindingWebsiteGroups" :key="group.id" :label="`${group.name} (${group.rate_multiplier ?? '—'})`" :value="group.id" />
            </el-select>
          </div>
        </el-form-item>

        <el-form-item label="监听上游分组" prop="source_group_keys">
          <!-- 整合选择联动的主容器 -->
          <div class="custom-selector-container">
            <div class="selector-info-area">
              <div class="selected-count-line">
                已选 <span class="accent-bold-text">{{ sourceGroupKeys.length }}</span> 个上游分组
              </div>
              <!-- 空白占位描述 -->
              <p class="empty-placeholder-text" v-if="sourceGroupKeys.length === 0">暂无选择，请点击按钮进行选择</p>
              <!-- 已选 Tag 轻量级展示列表 -->
              <div class="tags-container-inline" v-else>
                <el-tag
                  v-for="key in sourceGroupKeys"
                  :key="key"
                  closable
                  class="custom-inline-tag"
                  @close="removeSelectedKey(key)"
                >
                  {{ getGroupLabel(key) }}
                </el-tag>
              </div>
            </div>
            <button type="button" @click="openGroupSelectModal" class="btn-select-trigger">
              选择分组
            </button>
          </div>
        </el-form-item>

        <!-- 算法与百分比 -->
        <el-row :gutter="12">
          <el-col :span="12">
            <el-form-item label="算法">
              <div class="custom-select-wrapper">
                <el-select v-model="bindingForm.algorithm" style="width:100%" class="custom-theme-select">
                  <el-option label="优先级期望成本 + 百分比" value="priority_weighted_plus_percent" />
                  <el-option label="最高倍率 + 百分比" value="max_plus_percent" />
                  <el-option label="平均倍率 + 百分比" value="average_plus_percent" />
                  <el-option label="最低倍率 + 百分比" value="min_plus_percent" />
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="百分比">
              <div class="custom-percent-stepper">
                <button type="button" @click="adjustPercent(-5)" class="stepper-btn">
                  <el-icon><Minus /></el-icon>
                </button>
                <input
                  type="number"
                  step="0.01"
                  min="0"
                  max="100"
                  v-model.number="bindingForm.percent"
                  class="stepper-input"
                />
                <button type="button" @click="adjustPercent(5)" class="stepper-btn">
                  <el-icon><Plus /></el-icon>
                </button>
              </div>
            </el-form-item>
          </el-col>
        </el-row>

        <el-form-item label="启用">
          <div class="switch-toggle-line">
            <button
              type="button"
              class="custom-switch-toggle"
              :class="{ active: bindingForm.enabled }"
              @click="bindingForm.enabled = !bindingForm.enabled"
            >
              <span class="toggle-circle" />
            </button>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="drawer-footer-actions">
          <el-button @click="bindingDrawer = false" class="btn-cancel">取消</el-button>
          <el-button type="primary" :loading="savingBinding" @click="saveBinding" class="btn-save">保存</el-button>
        </div>
      </template>
    </el-drawer>

    <!-- 新增/编辑分组弹窗 -->
    <el-dialog
      v-model="groupFormVisible"
      :title="groupFormTitle"
      width="450px"
      destroy-on-close
      class="custom-theme-dialog"
    >
      <el-form :model="groupForm" :rules="groupFormRules" ref="groupFormRef" label-width="80px">
        <el-form-item label="名称" prop="name">
          <el-input v-model="groupForm.name" placeholder="请输入分组名称" />
        </el-form-item>
        <el-form-item label="描述" prop="description">
          <el-input v-model="groupForm.description" type="textarea" :rows="3" placeholder="请输入描述/备注（可选）" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="groupFormVisible = false" class="btn-cancel">取消</el-button>
          <el-button type="primary" :loading="groupFormSaving" @click="saveWebsiteGroup" class="btn-save">保存</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 选择上游分组弹窗 -->
    <el-dialog v-model="groupSelectVisible" title="选择上游分组" width="min(85vw, 1200px)" destroy-on-close class="group-select-dialog custom-theme-dialog">
      <!-- 搜索和倍率筛选条 -->
      <div class="dialog-filter-bar" style="margin-bottom: 16px;">
        <el-input v-model="groupSearchQuery" placeholder="输入分组名称、分组 ID..." clearable class="custom-theme-search keyword-search-input">
          <template #prefix>
            <el-icon><Search /></el-icon>
          </template>
        </el-input>
        <div class="rate-range-inputs">
          <div class="rate-input-box">
            <span class="rate-input-label">倍率 &gt;=</span>
            <input type="number" step="0.01" v-model.number="groupRateMin" placeholder="不限" class="rate-number-input" />
          </div>
          <div class="rate-input-box">
            <span class="rate-input-label">倍率 &lt;=</span>
            <input type="number" step="0.01" v-model.number="groupRateMax" placeholder="不限" class="rate-number-input" />
          </div>
        </div>
      </div>

      <div class="group-selector-layout">
        <!-- 左栏：按上游站点分类 -->
        <div class="left-panel">
          <div class="panel-header">上游站点</div>
          <div class="list-container">
            <button
              type="button"
              class="site-filter-btn"
              :class="{ active: selectedUpstreamId === '' }"
              @click="selectedUpstreamId = ''"
            >
              <span>全部上游</span>
              <span class="site-count-badge" :class="{ 'badge-active': selectedUpstreamId === '' }">{{ upstreamGroupOptions.length }}</span>
            </button>
            <button
              type="button"
              v-for="upstream in upstreams"
              :key="upstream.id"
              class="site-filter-btn"
              :class="{ active: selectedUpstreamId === upstream.id }"
              @click="selectedUpstreamId = upstream.id"
            >
              <span class="site-name-text" :title="upstream.name">{{ upstream.name }}</span>
              <span class="site-count-badge" :class="{ 'badge-active': selectedUpstreamId === upstream.id }">{{ upstreamCounts[upstream.id] || 0 }}</span>
            </button>
          </div>
        </div>

        <!-- 中栏：展示该上游下的分组，带 Checkbox -->
        <div class="middle-panel">
          <div class="panel-header flex-header">
            <el-checkbox
              :model-value="isAllFilteredSelected"
              :indeterminate="isSomeFilteredSelected"
              @change="toggleSelectAllFiltered"
              class="custom-theme-checkbox"
            >
              <span class="checkbox-text-label">可选分组列表 (已选 <span class="accent-text-bold">{{ tempSelectedKeys.filter(k => filteredGroupsForModal.some(g => g.key === k)).length }}</span>/{{ filteredGroupsForModal.length }})</span>
            </el-checkbox>
          </div>

          <div class="list-container group-list-scroll">
            <div v-if="upstreamGroupOptions.length === 0" class="empty-hint-dialog">
              暂无分组快照，请先同步上游
            </div>
            <div v-else-if="filteredGroupsForModal.length === 0" class="empty-hint-dialog">
              没有匹配的分组快照
            </div>
            <div
              v-else
              v-for="item in filteredGroupsForModal"
              :key="item.key"
              class="group-card-item"
              :class="{ selected: tempSelectedKeys.includes(item.key) }"
              @click="toggleGroupKey(item.key)"
            >
              <div class="card-left-part">
                <el-checkbox
                  :model-value="tempSelectedKeys.includes(item.key)"
                  @click.stop
                  @change="toggleGroupKey(item.key)"
                  class="custom-theme-checkbox"
                />
                <div class="card-details-info">
                  <div class="card-meta-line">
                    <span class="card-upstream-badge">{{ item.source.upstream_name }}</span>
                    <span class="card-id-text">ID: {{ item.source.group_id }}</span>
                  </div>
                  <h4 class="card-name-title">{{ item.source.group_name }}</h4>
                </div>
              </div>
              <div class="card-right-part">
                <span class="card-rate-label">倍率:</span>
                <span class="card-rate-value">{{ formatRate(item.rate) }}</span>
              </div>
            </div>
          </div>
        </div>

        <!-- 右栏：已选分组列表 -->
        <div class="right-panel">
          <div class="panel-header flex-header">
            <span>已选分组 ({{ tempSelectedKeys.length }})</span>
            <button type="button" v-if="tempSelectedKeys.length > 0" class="btn-clear-link" @click="clearAllTempKeys">清空</button>
          </div>

          <div class="list-container selected-list-scroll">
            <div v-if="tempSelectedKeys.length === 0" class="empty-hint-dialog small">
              <el-icon class="empty-layers-icon"><Grid /></el-icon>
              <p>暂无选定分组</p>
            </div>
            <div
              v-else
              v-for="key in tempSelectedKeys"
              :key="key"
              class="selected-card-item"
            >
              <div class="selected-card-info-box" v-if="getGroupDetails(key)">
                <p class="selected-card-meta-line">
                  {{ getGroupDetails(key)?.source.upstream_name }} · ID {{ getGroupDetails(key)?.source.group_id }}
                </p>
                <h5 class="selected-card-title-text">{{ getGroupDetails(key)?.source.group_name }}</h5>
              </div>
              <div class="selected-card-info-box" v-else>
                <h5 class="selected-card-title-text">{{ key }}</h5>
              </div>
              <button type="button" class="btn-trash-item" @click="removeTempKey(key)">
                <el-icon><Delete /></el-icon>
              </button>
            </div>
          </div>
        </div>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="groupSelectVisible = false">取消</el-button>
          <el-button type="primary" @click="confirmGroupSelection">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <el-dialog v-model="importGroupsDialog" title="导入上游分组" width="680px" destroy-on-close>
      <el-form label-position="top">
        <el-form-item label="目标网站">
          <el-select v-model="importGroupsForm.website_id" style="width:100%">
            <el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="来源上游">
          <el-select v-model="importGroupsForm.upstream_id" filterable style="width:100%" @change="importGroupsForm.group_ids = []">
            <el-option v-for="upstream in upstreams" :key="upstream.id" :label="upstream.name" :value="upstream.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="上游分组">
          <el-select v-model="importGroupsForm.group_ids" multiple filterable style="width:100%" placeholder="不选则导入全部分组">
            <el-option
              v-for="group in importSourceGroups"
              :key="sourceGroupId(group)"
              :label="`${sourceGroupName(group)} (${group.rate || group.rate_multiplier || '—'})`"
              :value="sourceGroupId(group)"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="分组名前缀">
          <el-input v-model="importGroupsForm.name_prefix" placeholder="可留空，参数和倍率保持上游一致" />
        </el-form-item>
      </el-form>
      <div v-if="importGroupResults.length" class="result-panel">
        <div class="result-title">导入结果</div>
        <el-table :data="importGroupResults" size="small">
          <el-table-column prop="source_group_name" label="上游分组" min-width="140" />
          <el-table-column prop="target_group_name" label="我的分组" min-width="160" />
          <el-table-column prop="target_group_id" label="目标 ID" width="100" />
          <el-table-column label="状态" width="90">
            <template #default="{ row }">
              <el-tag v-if="row.status === 'created'" size="small" type="success">已创建</el-tag>
              <el-tag v-else-if="row.status === 'exists'" size="small" type="info">已存在</el-tag>
              <el-tag v-else size="small" type="danger">失败</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="message" label="结果" min-width="160" />
        </el-table>
      </div>
      <template #footer>
        <el-button @click="importGroupsDialog = false">关闭</el-button>
        <el-button type="primary" :loading="importingGroups" @click="submitImportGroups">导入分组</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="importAccountsDialog" title="导入为账号管理账号" width="760px" destroy-on-close>
      <el-form label-position="top">
        <el-alert
          class="dialog-note"
          type="info"
          show-icon
          :closable="false"
          title="这里会把已生成的上游 Key 创建成 Sub2API 账号管理里的 apikey 账号，不会创建系统登录用户。"
        />
        <el-row :gutter="12">
          <el-col :span="12">
            <el-form-item label="目标网站">
              <el-select v-model="importAccountsForm.website_id" style="width:100%" @change="onImportAccountWebsiteChange">
                <el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="账号平台">
              <el-select v-model="importAccountsForm.platform_mode" style="width:100%" @change="onPlatformModeChange">
                <el-option label="自动识别（按 Key/分组名判断）" value="auto" />
                <el-option label="手动选择" value="manual" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="固定平台（手动模式）">
              <el-select v-model="importAccountsForm.default_platform" style="width:100%" :disabled="importAccountsForm.platform_mode === 'auto'">
                <el-option label="OpenAI 兼容" value="openai" />
                <el-option label="Anthropic" value="anthropic" />
                <el-option label="Gemini" value="gemini" />
                <el-option label="Antigravity" value="antigravity" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="24" style="margin-bottom:6px">
            <el-button size="small" text :loading="syncingImportStatus" @click="syncImportStatus">
              <el-icon><Refresh /></el-icon>刷新导入状态
            </el-button>
            <el-button
              size="small"
              text
              type="primary"
              :loading="reorderingPriorities"
              :disabled="!importAccountsForm.website_id || !importAccountsForm.upstream_id"
              @click="reorderImportPriorities"
            >
              <el-icon><Sort /></el-icon>重排优先级
            </el-button>
            <span v-if="importSyncStatus" style="font-size:12px;color:var(--text-muted);margin-left:8px">
              已校验已导入标记 {{ importSyncStatus.total }} 个，清除 {{ importSyncStatus.cleared }} 个失效标记
            </span>
          </el-col>
        </el-row>
        <el-row :gutter="12">
          <el-col :span="12">
            <el-form-item label="来源上游">
              <el-select v-model="importAccountsForm.upstream_id" filterable style="width:100%" @change="onImportAccountUpstreamChange">
                <el-option v-for="upstream in upstreams" :key="upstream.id" :label="upstream.name" :value="upstream.id" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="账号名前缀">
              <el-input v-model="importAccountsForm.account_name_prefix" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="12">
          <el-col :span="12">
            <el-form-item label="并发/容量">
              <el-input-number v-model="importAccountsForm.concurrency" :min="1" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="优先级">
              <template #label>
                <span>优先级</span>
                <el-tooltip content="按倍率自动分配优先级：倍率最低的上游分组优先级最高（priority=1），后续按 10 递增：11、21..." placement="top" :show-after="300">
                  <el-icon style="margin-left:4px;vertical-align:middle;color:var(--text-muted)"><WarningFilled /></el-icon>
                </el-tooltip>
              </template>
              <div style="display:flex;align-items:center;gap:8px">
                <el-switch
                  v-model="importAccountsForm.auto_priority_by_rate"
                  active-text="按倍率自动分配"
                  inactive-text="手动设置"
                />
                <el-input-number
                  v-if="!importAccountsForm.auto_priority_by_rate"
                  v-model="importAccountsForm.priority"
                  :min="0"
                  style="width:160px"
                />
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="已生成的上游 Key">
          <div style="display:flex;gap:8px;margin-bottom:6px">
            <el-button size="small" text @click="selectAllImportableKeys">全选可导入 Key</el-button>
            <el-button size="small" text @click="clearImportAccountSelection">清空</el-button>
          </div>
          <div v-if="importGeneratedKeys.length" class="import-stats">
            总计 {{ importGeneratedKeys.length }} 个，现可导入 {{ importableGeneratedKeys.length }} 个，已导入 {{ importedGeneratedKeyCount }} 个，无明文 {{ missingPlaintextKeyCount }} 个
          </div>
          <el-select
            v-model="importAccountsForm.upstream_key_ids"
            multiple
            filterable
            style="width:100%"
            placeholder="选择要导入为账号管理账号的 Key"
            :loading="generatedKeyLoading"
            @change="autoFillAccountTargetGroups()"
          >
            <el-option
              v-for="item in importableGeneratedKeys"
              :key="item.id!"
              :label="`${item.group_name || item.group_id} / ${detectPlatform(item)} / ${item.key_name} / ${item.masked_key}`"
              :value="item.id!"
            />
          </el-select>
        </el-form-item>
        <div v-if="selectedAccountGroups.length" class="mapping-panel">
          <div class="result-title">目标分组映射</div>
          <div v-for="group in selectedAccountGroups" :key="group.group_id" class="mapping-row">
            <span class="mapping-label">{{ group.group_name || group.group_id }}</span>
            <el-select v-model="importAccountsForm.target_group_map[group.group_id]" clearable filterable placeholder="可不选" style="width:280px">
              <el-option v-for="target in importTargetGroups" :key="target.id" :label="`${target.name} (${target.rate_multiplier ?? '—'})`" :value="target.id" />
            </el-select>
          </div>
        </div>
      </el-form>
      <div v-if="importAccountResults.length" class="result-panel">
        <div class="result-title">创建结果</div>
        <el-table :data="importAccountResults" size="small">
          <el-table-column prop="source_group_name" label="来源分组" min-width="130" />
          <el-table-column prop="account_name" label="账号管理账号" min-width="180" />
          <el-table-column label="识别平台" width="120">
            <template #default="{ row }">
              <span>{{ platformLabel(row.platform) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="请求地址" min-width="180">
            <template #default="{ row }">
              <span class="mono" style="font-size:12px">{{ row.upstream_base_url || '—' }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="account_id" label="账号 ID" width="110" />
          <el-table-column label="状态" width="90">
            <template #default="{ row }">
              <el-tag v-if="row.status === 'created'" size="small" type="success">成功</el-tag>
              <el-tag v-else-if="row.status === 'exists'" size="small" type="info">已存在</el-tag>
              <el-tag v-else size="small" type="danger">失败</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="message" label="结果" min-width="160" />
        </el-table>
      </div>
      <template #footer>
        <el-button @click="importAccountsDialog = false">关闭</el-button>
        <el-button type="primary" :loading="importingAccounts" :disabled="importingAccounts" @click="submitImportAccounts">创建账号管理账号</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="organizeDialog" title="一键整理分组结果" width="850px" destroy-on-close>
      <div v-if="organizeMessage" style="margin-bottom:12px; font-weight:bold; color:var(--el-color-primary)">
        {{ organizeMessage }}
      </div>
      <el-table :data="organizeResults" size="small" border style="width:100%">
        <el-table-column label="目标分组" min-width="150">
          <template #default="{ row }">
            <div>{{ row.target_group_name }}</div>
            <div style="font-size:11px;color:var(--text-muted)">ID: {{ row.target_group_id }}</div>
          </template>
        </el-table-column>
        <el-table-column label="来源上游/分组" min-width="165">
          <template #default="{ row }">
            <div>{{ row.upstream_name }}</div>
            <div style="font-size:11px;color:var(--text-muted)">{{ row.source_group_name }} (ID: {{ row.source_group_id }})</div>
          </template>
        </el-table-column>
        <el-table-column label="上游 Key" min-width="140">
          <template #default="{ row }">
            <span v-if="row.key_name">{{ row.key_name }}</span>
            <span v-else class="muted">—</span>
          </template>
        </el-table-column>
        <el-table-column label="目标账号" min-width="150">
          <template #default="{ row }">
            <div v-if="row.account_id">
              <div>{{ row.account_name }}</div>
              <div style="font-size:11px;color:var(--text-muted)">ID: {{ row.account_id }}</div>
            </div>
            <span v-else class="muted">—</span>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="110">
          <template #default="{ row }">
            <el-tag v-if="row.status === 'created'" size="small" type="success">已创建</el-tag>
            <el-tag v-else-if="row.status === 'recreated'" size="small" type="warning">清理后重建</el-tag>
            <el-tag v-else-if="row.status === 'exists'" size="small" type="info">已存在</el-tag>
            <el-tag v-else-if="row.status === 'missing_key'" size="small" type="danger">缺少 Key</el-tag>
            <el-tag v-else size="small" type="danger">失败</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="message" label="说明/原因" min-width="150">
          <template #default="{ row }">
            <span :class="{ 'error-text': row.status === 'failed' }">{{ row.message }}</span>
          </template>
        </el-table-column>
      </el-table>
      <template #footer>
        <el-button @click="organizeDialog = false">关闭</el-button>
      </template>
    </el-dialog>

    <!-- 清理失效账号弹窗 -->
    <el-dialog
      v-model="cleanupDialog"
      title="清理失效账号候选预览"
      width="1000px"
      destroy-on-close
    >
      <div v-loading="cleanupLoading">
        <el-alert
          title="清理规则说明"
          type="info"
          show-icon
          :closable="false"
          style="margin-bottom: 15px;"
        >
          <div style="font-size: 13px; line-height: 1.5;">
            系统已自动分析出可能已经失效、上游孤立或属于脏数据的账号候选。<br />
            <strong>是否将删除</strong> 字段是由后端调用目标站账号测试接口的结果判定。只有测试明确失败（非正常响应）或 404 的账号，才会被允许清理。<br />
            “确认清理”时，后端会重新测试 and 验证所有账号状态，只清理最终判定为失效的项。无 SmartUp 导入备注的手工账号不会被处理。
          </div>
        </el-alert>

        <el-table :data="cleanupItems" border stripe style="width: 100%; max-height: 500px; overflow-y: auto;">
          <el-table-column prop="account_id" label="账号 ID" width="160" show-overflow-tooltip />
          <el-table-column prop="account_name" label="账号名" width="180" show-overflow-tooltip />
          <el-table-column prop="upstream_name" label="来源上游" width="110" show-overflow-tooltip>
            <template #default="{ row }">
              <el-tag v-if="row.upstream_name" size="small">{{ row.upstream_name }}</el-tag>
              <span v-else class="text-muted">-</span>
            </template>
          </el-table-column>
          <el-table-column prop="source_group_name" label="来源分组" width="120" show-overflow-tooltip>
            <template #default="{ row }">
              <el-tag v-if="row.source_group_name" type="info" size="small">{{ row.source_group_name }}</el-tag>
              <span v-else class="text-muted">-</span>
            </template>
          </el-table-column>
          <el-table-column prop="upstream_key_id" label="Key ID" width="90" align="center">
            <template #default="{ row }">
              <span v-if="row.upstream_key_id" style="font-family: monospace;">#{{ row.upstream_key_id }}</span>
              <span v-else class="text-muted">-</span>
            </template>
          </el-table-column>
          <el-table-column prop="reason" label="原因" min-width="180" show-overflow-tooltip />
          <el-table-column prop="test_status" label="测试结果" width="110" align="center">
            <template #default="{ row }">
              <el-tag v-if="row.test_status === 'test_passed'" type="success" size="small">测试通过</el-tag>
              <el-tag v-else-if="row.test_status === 'failed'" type="danger" size="small">测试失败</el-tag>
              <el-tag v-else-if="row.test_status === '404'" type="warning" size="small">404 不存在</el-tag>
              <el-tag v-else type="info" size="small">未知 / 异常</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="cleanup_allowed" label="是否将删除" width="100" align="center">
            <template #default="{ row }">
              <el-tag v-if="row.cleanup_allowed" type="danger" effect="dark" size="small">将删除</el-tag>
              <el-tag v-else type="info" size="small">跳过</el-tag>
            </template>
          </el-table-column>
          <el-table-column v-if="cleanupHasExecuted" prop="action_status" label="执行结果" width="110" align="center">
            <template #default="{ row }">
              <el-tag v-if="row.action_status === 'deleted'" type="success" effect="dark" size="small">已删除</el-tag>
              <el-tag v-else-if="row.action_status === 'already_deleted'" type="warning" effect="dark" size="small">已不存在</el-tag>
              <el-tag v-else-if="row.action_status === 'skipped'" type="info" size="small">已跳过</el-tag>
              <el-tag v-else-if="row.action_status === 'failed'" type="danger" effect="dark" size="small">删除失败</el-tag>
              <span v-else>-</span>
            </template>
          </el-table-column>
        </el-table>

        <div v-if="cleanupItems.length === 0" style="padding: 30px; text-align: center; color: var(--el-text-color-secondary);">
          没有找到可以清理的失效或孤立账号。
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cleanupDialog = false" :disabled="cleanupExecuting">
            {{ cleanupHasExecuted ? '关闭' : '取消' }}
          </el-button>
          <el-button
            v-if="!cleanupHasExecuted"
            type="danger"
            :loading="cleanupExecuting"
            :disabled="cleanupLoading || cleanupItems.filter(i => i.cleanup_allowed).length === 0"
            @click="executeCleanup"
          >
            确认清理 ({{ cleanupItems.filter(i => i.cleanup_allowed).length }} 个)
          </el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 设置账号并发数弹窗 -->
    <el-dialog
      v-model="concurrencyDialog"
      title="一键设置账号并发数"
      width="850px"
      destroy-on-close
    >
      <div v-if="!concurrencyHasExecuted">
        <el-alert
          title="功能说明"
          type="warning"
          show-icon
          :closable="false"
          style="margin-bottom: 15px;"
        >
          <div style="font-size: 13px; line-height: 1.5;">
            该操作将<strong>仅修改由 SmartUp 导入并绑定到当前网站的账号并发数</strong>，不会影响任何由目标站手工创建的其他账号。<br />
            如果目标站接口支持批量更新（bulk-update），系统将一次性批量设置；否则将自动退回至逐个请求更新模式。
          </div>
        </el-alert>

        <el-form label-width="120px" style="margin-top: 20px;">
          <el-form-item label="目标并发数">
            <el-input-number
              v-model="targetConcurrency"
              :min="1"
              :max="1000"
              :step="10"
              style="width: 200px;"
            />
            <div style="font-size: 12px; color: var(--el-text-color-secondary); margin-top: 5px;">
              请输入 1 到 1000 之间的并发值，推荐设置为 100。
            </div>
          </el-form-item>
        </el-form>
      </div>

      <div v-else>
        <div style="margin-bottom: 15px; font-weight: bold; color: var(--el-color-primary);">
          {{ concurrencyMessage }}
        </div>

        <el-table :data="concurrencyResults" border stripe size="small" style="width: 100%; max-height: 400px; overflow-y: auto;">
          <el-table-column prop="account_id" label="账号 ID" width="150" />
          <el-table-column prop="account_name" label="账号名" min-width="180" show-overflow-tooltip />
          <el-table-column prop="old_concurrency" label="当前并发" width="110" align="center">
            <template #default="{ row }">
              <span v-if="row.old_concurrency !== null">{{ row.old_concurrency }}</span>
              <span v-else class="text-muted">-</span>
            </template>
          </el-table-column>
          <el-table-column prop="target_concurrency" label="目标并发" width="110" align="center" />
          <el-table-column prop="status" label="状态" width="100" align="center">
            <template #default="{ row }">
              <el-tag v-if="row.status === 'success'" type="success" size="small">成功</el-tag>
              <el-tag v-else-if="row.status === 'skipped'" type="warning" size="small">跳过</el-tag>
              <el-tag v-else-if="row.status === 'failed'" type="danger" size="small">失败</el-tag>
              <el-tag v-else type="info" size="small">{{ row.status }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="message" label="说明/原因" min-width="150" show-overflow-tooltip />
        </el-table>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="concurrencyDialog = false" :disabled="concurrencyExecuting">
            {{ concurrencyHasExecuted ? '关闭' : '取消' }}
          </el-button>
          <el-button
            v-if="!concurrencyHasExecuted"
            type="primary"
            :loading="concurrencyExecuting"
            @click="submitSetConcurrency"
          >
            确认执行
          </el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 同步上游模型结果弹窗 -->
    <el-dialog
      v-model="syncModelsDialog"
      title="一键同步上游模型结果"
      width="850px"
      destroy-on-close
      :show-close="!syncModelsExecuting"
      :close-on-click-modal="!syncModelsExecuting"
      :close-on-press-escape="!syncModelsExecuting"
      :before-close="handleSyncModelsDialogBeforeClose"
    >
      <div>
        <div style="margin-bottom: 15px; display: flex; align-items: center; justify-content: space-between; font-size: 14px;">
          <div>
            <span style="margin-right: 15px;">已处理: <strong style="color: var(--el-color-primary);">{{ syncModelsProcessedCount }}/{{ syncModelsTotal }}</strong></span>
            <span style="margin-right: 15px;">成功: <strong style="color: var(--el-color-success);">{{ syncModelsSuccessCount }}</strong></span>
            <span style="margin-right: 15px;">失败: <strong style="color: var(--el-color-danger);">{{ syncModelsFailedCount }}</strong></span>
            <span>跳过: <strong style="color: var(--el-color-warning);">{{ syncModelsSkippedCount }}</strong></span>
          </div>
          <div v-if="syncModelsExecuting" style="color: var(--el-color-info); display: flex; align-items: center;">
            <span class="is-loading" style="margin-right: 5px; display: inline-flex;"><el-icon><Refresh /></el-icon></span>
            正在同步模型...
          </div>
        </div>

        <div v-if="syncModelsMessage" style="margin-bottom: 15px; font-weight: bold; color: var(--el-color-primary);">
          {{ syncModelsMessage }}
        </div>

        <el-table :data="syncModelsResults" border stripe size="small" style="width: 100%; max-height: 400px; overflow-y: auto;">
          <el-table-column prop="account_id" label="账号 ID" width="150" />
          <el-table-column prop="account_name" label="账号名" min-width="180" show-overflow-tooltip />
          <el-table-column prop="model_count" label="同步模型数" width="110" align="center">
            <template #default="{ row }">
              <el-tooltip
                v-if="row.models && row.models.length > 0"
                class="box-item"
                effect="dark"
                placement="top"
              >
                <template #content>
                  <div style="max-width: 300px; word-break: break-all;">
                    {{ row.models.join(', ') }}
                  </div>
                </template>
                <el-tag type="info" size="small" style="cursor: pointer;">
                  {{ row.model_count }} 个
                </el-tag>
              </el-tooltip>
              <span v-else class="text-muted">0 个</span>
            </template>
          </el-table-column>
          <el-table-column prop="status" label="状态" width="100" align="center">
            <template #default="{ row }">
              <el-tag v-if="row.status === 'success'" type="success" size="small">成功</el-tag>
              <el-tag v-else-if="row.status === 'skipped'" type="warning" size="small">跳过</el-tag>
              <el-tag v-else-if="row.status === 'failed'" type="danger" size="small">失败</el-tag>
              <el-tag v-else type="info" size="small">{{ row.status }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="message" label="说明/原因" min-width="200" show-overflow-tooltip />
        </el-table>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="syncModelsDialog = false" :disabled="syncModelsExecuting">
            关闭
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance } from 'element-plus'
import dayjs from 'dayjs'
import { ArrowDown, Delete, Edit, Plus, Minus, Grid, Connection, Link, Upload, Key, Refresh, Sort, WarningFilled, Search, Close } from '@element-plus/icons-vue'
import { useAuthStore } from '@/stores/auth'
import {
  upstreamsApi,
  websitesApi,
  type BindingSourceGroup,
  type GeneratedUpstreamKey,
  type GroupBindingData,
  type GroupBindingForm,
  type ImportAccountItem,
  type ImportGroupItem,
  type UpstreamData,
  type WebsiteData,
  type WebsiteForm,
  type WebsiteGroup,
  type WebsiteSyncLog,
  type OrganizeGroupsItem,
  type CleanupInvalidAccountsItem,
  type SetConcurrencyItem,
  type SyncUpstreamModelsItem,
} from '@/api'

const websites = ref<(WebsiteData & { _testing?: boolean })[]>([])
const upstreams = ref<UpstreamData[]>([])
const selectedWebsite = ref<WebsiteData | null>(null)
const websiteGroups = ref<WebsiteGroup[]>([])
const sortedWebsiteGroups = computed(() => {
  return [...websiteGroups.value].sort((a, b) => {
    const rateA = a.rate_multiplier !== null && a.rate_multiplier !== undefined && a.rate_multiplier !== '—'
      ? parseFloat(String(a.rate_multiplier))
      : NaN
    const rateB = b.rate_multiplier !== null && b.rate_multiplier !== undefined && b.rate_multiplier !== '—'
      ? parseFloat(String(b.rate_multiplier))
      : NaN

    const isNaN_A = isNaN(rateA)
    const isNaN_B = isNaN(rateB)

    if (isNaN_A && isNaN_B) {
      return a.name.localeCompare(b.name) || String(a.id).localeCompare(String(b.id))
    }
    if (isNaN_A) return 1
    if (isNaN_B) return -1

    if (rateA !== rateB) {
      return rateA - rateB
    }
    return a.name.localeCompare(b.name) || String(a.id).localeCompare(String(b.id))
  })
})
const bindingWebsiteGroups = ref<WebsiteGroup[]>([])
const bindings = ref<(GroupBindingData & { _syncing?: boolean })[]>([])
const logs = ref<WebsiteSyncLog[]>([])
const snapshotsByUpstream = ref<Record<number, any[]>>({})
const importTargetGroups = ref<WebsiteGroup[]>([])
const importGeneratedKeys = ref<GeneratedUpstreamKey[]>([])

const websiteLoading = ref(false)
const groupsLoading = ref(false)
const bindingLoading = ref(false)
const logLoading = ref(false)
const batchSyncLoading = ref(false)
const importingGroups = ref(false)
const importingAccounts = ref(false)
const generatedKeyLoading = ref(false)
const importSyncStatus = ref<{ total: number; cleared: number; failed: number } | null>(null)
const syncingImportStatus = ref(false)
const reorderingPriorities = ref(false)

const statusLabel = (s: string) => ({ healthy: '健康', unhealthy: '异常', unknown: '未知' }[s] || s)
const algorithmLabel = (s: string) => ({ max_plus_percent: '最高倍率', average_plus_percent: '平均倍率', min_plus_percent: '最低倍率', priority_weighted_plus_percent: '优先级期望成本' }[s] || s)
const toUTC = (t: string) => /[Z+\-]\d*$/.test(t.trim()) ? t : t + 'Z'
const fmtTime = (t: string) => dayjs(toUTC(t)).format('MM-DD HH:mm:ss')
const sourceGroupId = (group: any) => String(group?.group_id || group?.id || group?.name || '')
const sourceGroupName = (group: any) => String(group?.group_name || group?.name || sourceGroupId(group))

function defaultWebsiteForm(): WebsiteForm {
  return {
    name: '',
    site_type: 'sub2api',
    base_url: '',
    api_prefix: '/api/v1/admin',
    auth_type: 'api_key',
    auth_config: { key: '', header: 'x-api-key' },
    groups_endpoint: '/groups',
    group_update_endpoint: '/groups/{id}',
    enabled: true,
    auto_sync_enabled: true,
    timeout_seconds: 30,
  }
}

const websiteDrawer = ref(false)
const savingWebsite = ref(false)
const editingWebsiteId = ref<number | null>(null)
const websiteFormRef = ref<FormInstance>()
const websiteForm = ref<WebsiteForm>(defaultWebsiteForm())
const websiteRules = {
  name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  base_url: [{ required: true, message: '请输入 Base URL', trigger: 'blur' }],
}

function defaultBindingForm(): GroupBindingForm {
  return {
    website_id: websites.value[0]?.id ?? 0,
    target_group_id: '',
    target_group_name: '',
    source_groups: [],
    percent: 0,
    algorithm: 'priority_weighted_plus_percent',
    enabled: true,
  }
}

const bindingDrawer = ref(false)
const savingBinding = ref(false)
const editingBindingId = ref<number | null>(null)
const bindingFormRef = ref<FormInstance>()
const bindingForm = ref<GroupBindingForm>(defaultBindingForm())
const sourceGroupKeys = ref<string[]>([])
const bindingRules = {
  target_group_id: [{ required: true, message: '请选择目标分组', trigger: 'change' }],
}

const importGroupsDialog = ref(false)
const importGroupsForm = ref({
  website_id: 0,
  upstream_id: 0,
  group_ids: [] as string[],
  name_prefix: '',
})
const importGroupResults = ref<ImportGroupItem[]>([])

const groupFormVisible = ref(false)
const groupFormSaving = ref(false)
const editingGroupId = ref<string | null>(null)
const groupFormRef = ref<FormInstance>()
const groupForm = ref({
  name: '',
  description: '',
})
const groupFormRules = {
  name: [{ required: true, message: '请输入分组名称', trigger: 'blur' }],
}

const groupFormTitle = computed(() => {
  return editingGroupId.value ? '编辑分组' : '新增分组'
})

const importAccountsDialog = ref(false)
const importAccountsForm = ref({
  website_id: 0,
  upstream_id: 0,
  upstream_key_ids: [] as number[],
  target_group_map: {} as Record<string, string>,
  account_name_prefix: 'SmartUp',
  default_platform: 'openai',
  platform_mode: 'auto',
  concurrency: 100,
  priority: 1,
  auto_priority_by_rate: true,
})
const importAccountResults = ref<ImportAccountItem[]>([])

const organizeDialog = ref(false)
const organizeLoading = ref(false)
const organizeResults = ref<OrganizeGroupsItem[]>([])
const organizeMessage = ref('')

const cleanupDialog = ref(false)
const cleanupLoading = ref(false)
const cleanupExecuting = ref(false)
const cleanupHasExecuted = ref(false)
const cleanupItems = ref<CleanupInvalidAccountsItem[]>([])

const concurrencyDialog = ref(false)
const concurrencyExecuting = ref(false)
const concurrencyHasExecuted = ref(false)
const targetConcurrency = ref(100)
const concurrencyMessage = ref('')
const concurrencyResults = ref<SetConcurrencyItem[]>([])

const syncModelsDialog = ref(false)
const syncModelsExecuting = ref(false)
const syncModelsMessage = ref('')
const syncModelsResults = ref<SyncUpstreamModelsItem[]>([])
const syncModelsTotal = ref(0)
const syncModelsSuccessCount = computed(() => syncModelsResults.value.filter(r => r.status === 'success').length)
const syncModelsFailedCount = computed(() => syncModelsResults.value.filter(r => r.status === 'failed').length)
const syncModelsSkippedCount = computed(() => syncModelsResults.value.filter(r => r.status === 'skipped').length)
const syncModelsProcessedCount = computed(() => syncModelsResults.value.length)

function handleSyncModelsDialogBeforeClose(done: () => void) {
  if (syncModelsExecuting.value) {
    return
  }
  done()
}

const upstreamGroupOptions = computed(() => {
  const rows: Array<{ key: string; label: string; rate: string | number; source: BindingSourceGroup }> = []
  for (const upstream of upstreams.value) {
    const groups = snapshotsByUpstream.value[upstream.id] || []
    for (const group of groups) {
      const source = {
        upstream_id: upstream.id,
        upstream_name: upstream.name,
        group_id: group.group_id,
        group_name: group.group_name || group.group_id,
      }
      rows.push({
        key: `${upstream.id}::${group.group_id}`,
        label: `${upstream.name} / ${source.group_name} (${group.rate || '—'})`,
        rate: group.rate || '—',
        source,
      })
    }
  }
  return rows
})

const importSourceGroups = computed(() => snapshotsByUpstream.value[importGroupsForm.value.upstream_id] || [])

function isImportableGeneratedKey(item: GeneratedUpstreamKey) {
  return item.id !== null
    && item.has_key_value
    && item.status !== 'failed'
    && item.status !== 'orphaned'
    && !(item.imported_website_id === importAccountsForm.value.website_id && item.imported_account_id)
}

const importableGeneratedKeys = computed(() =>
  importGeneratedKeys.value.filter(isImportableGeneratedKey),
)

const importedGeneratedKeyCount = computed(() =>
  importGeneratedKeys.value.filter((item) =>
    item.imported_website_id === importAccountsForm.value.website_id && Boolean(item.imported_account_id),
  ).length,
)

const missingPlaintextKeyCount = computed(() =>
  importGeneratedKeys.value.filter((item) => !item.has_key_value).length,
)

const selectedWebsiteBindings = computed(() => {
  if (!selectedWebsite.value) return []
  return bindings.value.filter((binding) => binding.website_id === selectedWebsite.value?.id)
})

const selectedAccountGroups = computed(() => {
  const selected = new Set(importAccountsForm.value.upstream_key_ids)
  const rows = importableGeneratedKeys.value.filter((item) => item.id !== null && selected.has(item.id))
  const seen = new Set<string>()
  const groups: Array<{ group_id: string; group_name: string }> = []
  for (const row of rows) {
    if (seen.has(row.group_id)) continue
    seen.add(row.group_id)
    groups.push({ group_id: row.group_id, group_name: row.group_name })
  }
  return groups
})

async function loadWebsites() {
  websiteLoading.value = true
  try {
    const res = await websitesApi.list()
    websites.value = res.data
    if (!selectedWebsite.value && res.data.length > 0) selectedWebsite.value = res.data[0]
  } finally {
    websiteLoading.value = false
  }
}

async function onSelectedWebsiteChange(value: number | string) {
  const nextId = Number(value)
  const next = websites.value.find((site) => site.id === nextId)
  if (!next) return
  selectedWebsite.value = next
  await loadWebsiteGroups()
}

async function loadUpstreamGroups() {
  const upstreamRes = await upstreamsApi.list()
  upstreams.value = upstreamRes.data
  const entries: Record<number, any[]> = {}
  await Promise.all(upstreams.value.map(async (upstream) => {
    try {
      const res = await upstreamsApi.latestSnapshot(upstream.id)
      entries[upstream.id] = Object.values(res.data.snapshot?.groups || {})
    } catch {
      entries[upstream.id] = []
    }
  }))
  snapshotsByUpstream.value = entries
}

async function loadWebsiteGroups() {
  if (!selectedWebsite.value) return
  groupsLoading.value = true
  try {
    const res = await websitesApi.groups(selectedWebsite.value.id)
    websiteGroups.value = res.data
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '拉取分组失败')
  } finally {
    groupsLoading.value = false
  }
}

async function loadBindingWebsiteGroups(websiteId: number) {
  if (!websiteId) {
    bindingWebsiteGroups.value = []
    return
  }
  try {
    const res = await websitesApi.groups(websiteId)
    bindingWebsiteGroups.value = res.data
  } catch {
    bindingWebsiteGroups.value = []
  }
}

async function loadImportTargetGroups(websiteId: number) {
  if (!websiteId) {
    importTargetGroups.value = []
    return
  }
  const frozenId = websiteId
  try {
    const res = await websitesApi.groups(frozenId)
    if (importAccountsForm.value.website_id !== frozenId) return
    importTargetGroups.value = res.data
  } catch {
    if (importAccountsForm.value.website_id !== frozenId) return
    importTargetGroups.value = []
  }
}

async function loadBindings() {
  bindingLoading.value = true
  try {
    const res = await websitesApi.listBindings()
    bindings.value = res.data
  } finally {
    bindingLoading.value = false
  }
}

async function loadLogs() {
  logLoading.value = true
  try {
    const res = await websitesApi.logs({ limit: 50 })
    logs.value = res.data
  } finally {
    logLoading.value = false
  }
}

async function syncImportStatus() {
  const websiteId = importAccountsForm.value.website_id
  const upstreamId = importAccountsForm.value.upstream_id
  if (!websiteId || !upstreamId) return false
  syncingImportStatus.value = true
  let reloaded = false
  try {
    const res = await websitesApi.syncImportedUpstreamKeys(websiteId, { upstream_id: upstreamId })
    // 校验请求完成时表单未切换
    if (importAccountsForm.value.website_id !== websiteId || importAccountsForm.value.upstream_id !== upstreamId) return false
    const items = res.data.items
    importSyncStatus.value = {
      total: items.length,
      cleared: items.filter(i => i.status === 'stale_cleared').length,
      failed: items.filter(i => i.status === 'check_failed').length,
    }
    if (importSyncStatus.value.cleared > 0) {
      ElMessage.success(`已清除 ${importSyncStatus.value.cleared} 个失效导入标记`)
    }
    if (importAccountsForm.value.upstream_id === upstreamId) {
      await loadImportGeneratedKeys(upstreamId)
      reloaded = true
    }
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '同步导入状态失败')
  } finally {
    syncingImportStatus.value = false
  }
  return reloaded
}

async function reorderImportPriorities() {
  const websiteId = importAccountsForm.value.website_id
  const upstreamId = importAccountsForm.value.upstream_id
  if (!websiteId || !upstreamId) {
    ElMessage.error('请选择目标网站和来源上游')
    return
  }
  reorderingPriorities.value = true
  try {
    const res = await websitesApi.reorderAccountPriorities(websiteId, { upstream_id: upstreamId })
    if (importAccountsForm.value.website_id !== websiteId || importAccountsForm.value.upstream_id !== upstreamId) return
    ElMessage[res.data.success ? 'success' : 'warning'](res.data.message)
    await Promise.all([
      loadImportGeneratedKeys(upstreamId),
      loadLogs(),
    ])
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '重排优先级失败')
  } finally {
    reorderingPriorities.value = false
  }
}

async function loadImportGeneratedKeys(upstreamId: number) {
  importGeneratedKeys.value = []
  if (!upstreamId) return
  generatedKeyLoading.value = true
  const frozenId = upstreamId
  try {
    const res = await upstreamsApi.generatedKeys(frozenId)
    if (importAccountsForm.value.upstream_id !== frozenId) return  // 已切换到其他上游
    importGeneratedKeys.value = res.data
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '加载上游 Key 失败')
  } finally {
    generatedKeyLoading.value = false
  }
}

async function loadAll() {
  await Promise.all([loadWebsites(), loadUpstreamGroups(), loadBindings(), loadLogs()])
  if (selectedWebsite.value) await loadWebsiteGroups()
}

function selectWebsite(row: WebsiteData) {
  selectedWebsite.value = row
  loadWebsiteGroups()
}

function openWebsiteCreate() {
  editingWebsiteId.value = null
  websiteForm.value = defaultWebsiteForm()
  websiteDrawer.value = true
}

function openWebsiteEdit(row: WebsiteData) {
  editingWebsiteId.value = row.id
  websiteForm.value = {
    name: row.name,
    site_type: row.site_type,
    base_url: row.base_url,
    api_prefix: row.api_prefix,
    auth_type: row.auth_type,
    auth_config: { ...row.auth_config_masked },
    groups_endpoint: row.groups_endpoint,
    group_update_endpoint: row.group_update_endpoint,
    enabled: row.enabled,
    auto_sync_enabled: row.auto_sync_enabled,
    timeout_seconds: row.timeout_seconds,
  }
  websiteDrawer.value = true
}

async function saveWebsite() {
  const valid = await websiteFormRef.value?.validate().catch(() => false)
  if (!valid) return
  savingWebsite.value = true
  try {
    if (editingWebsiteId.value) {
      await websitesApi.update(editingWebsiteId.value, websiteForm.value)
      ElMessage.success('保存成功')
    } else {
      await websitesApi.create(websiteForm.value)
      ElMessage.success('创建成功')
    }
    websiteDrawer.value = false
    await loadWebsites()
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '保存失败')
  } finally {
    savingWebsite.value = false
  }
}

async function toggleWebsiteSync(row: WebsiteData) {
  try {
    await websitesApi.update(row.id, { auto_sync_enabled: row.auto_sync_enabled })
    ElMessage.success(row.auto_sync_enabled ? '已启用自动同步' : '已停用自动同步')
  } catch {
    row.auto_sync_enabled = !row.auto_sync_enabled
    ElMessage.error('操作失败')
  }
}

async function testWebsite(row: WebsiteData & { _testing?: boolean }) {
  row._testing = true
  try {
    const res = await websitesApi.test(row.id)
    ElMessage[res.data.success ? 'success' : 'error'](res.data.detail || res.data.message)
    await loadWebsites()
  } finally {
    row._testing = false
  }
}

/** 处理「更多」下拉菜单中的操作 */
function handleMoreAction(cmd: string, row: WebsiteData & { _testing?: boolean }) {
  switch (cmd) {
    case 'test': testWebsite(row); break
    case 'binding': openBindingCreate(row); break
    case 'importGroups': openImportGroups(row); break
    case 'importAccounts': openImportAccounts(row); break
    case 'delete': deleteWebsite(row); break
  }
}

async function deleteWebsite(row: WebsiteData) {
  try {
    await ElMessageBox.confirm(`确认删除网站 "${row.name}"？`, '删除确认', { type: 'warning' })
    await websitesApi.delete(row.id)
    ElMessage.success('已删除')
    selectedWebsite.value = null
    websiteGroups.value = []
    await loadAll()
  } catch {}
}

async function openBindingCreate(site?: WebsiteData | null, target?: WebsiteGroup) {
  editingBindingId.value = null
  bindingForm.value = defaultBindingForm()
  if (site) bindingForm.value.website_id = site.id
  await loadBindingWebsiteGroups(bindingForm.value.website_id)
  if (target) {
    bindingForm.value.target_group_id = target.id
    bindingForm.value.target_group_name = target.name
  } else {
    const first = bindingWebsiteGroups.value[0]
    if (first) {
      bindingForm.value.target_group_id = first.id
      bindingForm.value.target_group_name = first.name
    }
  }
  sourceGroupKeys.value = []
  bindingDrawer.value = true
}

async function openBindingEdit(row: GroupBindingData) {
  editingBindingId.value = row.id
  bindingForm.value = {
    website_id: row.website_id,
    target_group_id: row.target_group_id,
    target_group_name: row.target_group_name,
    source_groups: [...row.source_groups],
    percent: row.percent,
    algorithm: row.algorithm,
    enabled: row.enabled,
  }
  sourceGroupKeys.value = row.source_groups.map(item => `${item.upstream_id}::${item.group_id}`)
  await loadBindingWebsiteGroups(row.website_id)
  bindingDrawer.value = true
}

async function onBindingWebsiteChange(value: number) {
  bindingForm.value.target_group_id = ''
  bindingForm.value.target_group_name = ''
  await loadBindingWebsiteGroups(value)
  const first = bindingWebsiteGroups.value[0]
  if (first) {
    bindingForm.value.target_group_id = first.id
    bindingForm.value.target_group_name = first.name
  }
}

function onTargetGroupChange(value: string) {
  const group = bindingWebsiteGroups.value.find(item => item.id === value)
  bindingForm.value.target_group_name = group?.name || value
}

function onSourceGroupsChange(values: string[]) {
  const options = new Map(upstreamGroupOptions.value.map(item => [item.key, item.source]))
  bindingForm.value.source_groups = values.map(value => options.get(value)).filter((item): item is BindingSourceGroup => Boolean(item))
}

function openGroupCreate() {
  editingGroupId.value = null
  groupForm.value = {
    name: '',
    description: '',
  }
  groupFormVisible.value = true
}

function openGroupEdit(row: WebsiteGroup) {
  editingGroupId.value = row.id
  groupForm.value = {
    name: row.name,
    description: row.description || '',
  }
  groupFormVisible.value = true
}

async function saveWebsiteGroup() {
  if (!selectedWebsite.value) return
  const websiteId = selectedWebsite.value.id
  if (!groupFormRef.value) return

  await groupFormRef.value.validate(async (valid) => {
    if (!valid) return
    groupFormSaving.value = true
    try {
      if (editingGroupId.value) {
        await websitesApi.updateGroup(websiteId, editingGroupId.value, {
          name: groupForm.value.name,
          description: groupForm.value.description,
        })
        ElMessage.success('编辑成功')
      } else {
        await websitesApi.createGroup(websiteId, {
          name: groupForm.value.name,
          description: groupForm.value.description,
        })
        ElMessage.success('新增成功')
      }
      groupFormVisible.value = false
      await Promise.all([loadWebsiteGroups(), loadBindings()])
    } catch (e: any) {
      ElMessage.error(e.response?.data?.detail || e.message || '保存失败')
    } finally {
      groupFormSaving.value = false
    }
  })
}

async function saveBinding() {
  if (!bindingForm.value.source_groups.length) {
    ElMessage.error('请选择至少一个监听上游分组')
    return
  }
  const valid = await bindingFormRef.value?.validate().catch(() => false)
  if (!valid) return
  savingBinding.value = true
  try {
    if (editingBindingId.value) {
      await websitesApi.updateBinding(editingBindingId.value, bindingForm.value)
    } else {
      await websitesApi.createBinding(bindingForm.value)
    }
    ElMessage.success('保存成功，已尝试同步')
    bindingDrawer.value = false
    await Promise.all([loadBindings(), loadLogs()])
    if (selectedWebsite.value?.id === bindingForm.value.website_id) await loadWebsiteGroups()
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '保存失败')
  } finally {
    savingBinding.value = false
  }
}

// 选择上游分组弹窗相关状态与方法
const groupSelectVisible = ref(false)
const groupSearchQuery = ref('')
const groupRateMin = ref<number | null>(null)
const groupRateMax = ref<number | null>(null)
const selectedUpstreamId = ref<number | ''>('')
const tempSelectedKeys = ref<string[]>([])

function openGroupSelectModal() {
  tempSelectedKeys.value = [...sourceGroupKeys.value]
  groupSearchQuery.value = ''
  selectedUpstreamId.value = ''
  groupRateMin.value = null
  groupRateMax.value = null
  groupSelectVisible.value = true
}

function getGroupLabel(key: string) {
  const found = upstreamGroupOptions.value.find(item => item.key === key)
  return found ? found.label : key
}

function removeSelectedKey(key: string) {
  sourceGroupKeys.value = sourceGroupKeys.value.filter(k => k !== key)
  onSourceGroupsChange(sourceGroupKeys.value)
}

function getGroupDetails(key: string) {
  return upstreamGroupOptions.value.find(item => item.key === key)
}

const upstreamCounts = computed(() => {
  const counts: Record<number, number> = {}
  for (const upstream of upstreams.value) {
    const groups = snapshotsByUpstream.value[upstream.id] || []
    counts[upstream.id] = groups.length
  }
  return counts
})

function normalizeRateBound(value: unknown): number | null {
  if (value === null || value === undefined || value === '') return null
  const parsed = Number(value)
  return Number.isFinite(parsed) ? parsed : null
}

const filteredGroupsForModal = computed(() => {
  const query = groupSearchQuery.value.trim().toLowerCase()
  return upstreamGroupOptions.value.filter(item => {
    // 1. 上游站点过滤
    if (selectedUpstreamId.value !== '' && item.source.upstream_id !== selectedUpstreamId.value) {
      return false
    }

    // 2. 关键词过滤：只匹配 group_name、group_id
    if (query) {
      const matchGroupName = item.source.group_name.toLowerCase().includes(query)
      const matchGroupId = String(item.source.group_id).toLowerCase().includes(query)
      if (!matchGroupName && !matchGroupId) {
        return false
      }
    }

    // 3. 倍率范围过滤
    const min = normalizeRateBound(groupRateMin.value)
    const max = normalizeRateBound(groupRateMax.value)
    if (min !== null || max !== null) {
      const rateVal = parseFloat(String(item.rate))
      if (isNaN(rateVal)) {
        return false
      }
      if (min !== null && rateVal < min) {
        return false
      }
      if (max !== null && rateVal > max) {
        return false
      }
    }

    return true
  })
})

const isAllFilteredSelected = computed(() => {
  if (filteredGroupsForModal.value.length === 0) return false
  return filteredGroupsForModal.value.every(item => tempSelectedKeys.value.includes(item.key))
})

const isSomeFilteredSelected = computed(() => {
  if (filteredGroupsForModal.value.length === 0) return false
  const selectedCount = filteredGroupsForModal.value.filter(item => tempSelectedKeys.value.includes(item.key)).length
  return selectedCount > 0 && selectedCount < filteredGroupsForModal.value.length
})

function toggleSelectAllFiltered(checked: boolean) {
  if (checked) {
    const keysToAdd = filteredGroupsForModal.value.map(item => item.key)
    tempSelectedKeys.value = Array.from(new Set([...tempSelectedKeys.value, ...keysToAdd]))
  } else {
    const keysToRemove = new Set(filteredGroupsForModal.value.map(item => item.key))
    tempSelectedKeys.value = tempSelectedKeys.value.filter(key => !keysToRemove.has(key))
  }
}

function toggleGroupKey(key: string) {
  const idx = tempSelectedKeys.value.indexOf(key)
  if (idx > -1) {
    tempSelectedKeys.value.splice(idx, 1)
  } else {
    tempSelectedKeys.value.push(key)
  }
}

function removeTempKey(key: string) {
  tempSelectedKeys.value = tempSelectedKeys.value.filter(k => k !== key)
}

function clearAllTempKeys() {
  tempSelectedKeys.value = []
}

function confirmGroupSelection() {
  sourceGroupKeys.value = [...tempSelectedKeys.value]
  onSourceGroupsChange(sourceGroupKeys.value)
  groupSelectVisible.value = false
}

function adjustPercent(amount: number) {
  let val = Number(bindingForm.value.percent) || 0
  val = Math.max(0, Math.min(100, val + amount))
  bindingForm.value.percent = Number(val.toFixed(2))
}

function formatRate(rate: string | number) {
  if (typeof rate === 'number') return rate.toFixed(2)
  const parsed = parseFloat(String(rate))
  if (!isNaN(parsed)) return parsed.toFixed(2)
  return rate
}


async function syncBinding(row: GroupBindingData & { _syncing?: boolean }) {
  row._syncing = true
  try {
    const res = await websitesApi.syncNow(row.id)
    ElMessage[res.data.status === 'success' ? 'success' : 'error'](res.data.message)
    await loadLogs()
    if (selectedWebsite.value?.id === row.website_id) await loadWebsiteGroups()
  } finally {
    row._syncing = false
  }
}

async function syncAllWebsiteBindings() {
  if (!selectedWebsite.value) return
  batchSyncLoading.value = true
  try {
    const res = await websitesApi.syncWebsiteBindings(selectedWebsite.value.id)
    ElMessage.success(res.data.message)
    // 刷新相关数据
    await Promise.all([loadLogs(), loadWebsiteGroups(), loadBindings()])
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '批量同步失败')
  } finally {
    batchSyncLoading.value = false
  }
}

async function organizeWebsiteGroups() {
  if (!selectedWebsite.value) return
  try {
    await ElMessageBox.confirm(
      '一键整理分组将根据当前的“分组管理”绑定关系，自动执行已导入账号的校验补齐，以及未导入账号的自动创建。确认执行？',
      '一键整理分组',
      { type: 'info' }
    )
  } catch {
    return
  }

  organizeLoading.value = true
  try {
    const res = await websitesApi.organizeGroups(selectedWebsite.value.id)
    organizeMessage.value = res.data.message
    organizeResults.value = res.data.items
    organizeDialog.value = true
    // 刷新相关数据
    await Promise.all([loadLogs(), loadWebsiteGroups(), loadBindings()])
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '一键整理分组失败')
  } finally {
    organizeLoading.value = false
  }
}

async function openCleanupDialog() {
  if (!selectedWebsite.value) return
  cleanupItems.value = []
  cleanupHasExecuted.value = false
  cleanupDialog.value = true
  cleanupLoading.value = true
  try {
    const res = await websitesApi.cleanupPreview(selectedWebsite.value.id)
    if (res.data.success) {
      cleanupItems.value = res.data.items
    } else {
      ElMessage.error(res.data.message || '加载失效账号候选预览失败')
      cleanupDialog.value = false
    }
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '加载失效账号候选预览失败')
    cleanupDialog.value = false
  } finally {
    cleanupLoading.value = false
  }
}

async function executeCleanup() {
  if (!selectedWebsite.value) return
  try {
    await ElMessageBox.confirm(
      '确认清理失效账号？此操作将永久从目标站删除测试失败或不存在的账号，本地 orphaned 键将清空导入关联。',
      '确认清理',
      { type: 'warning' }
    )
  } catch {
    return
  }

  cleanupExecuting.value = true
  try {
    const res = await websitesApi.cleanupExecute(selectedWebsite.value.id)
    if (res.data.success) {
      cleanupItems.value = res.data.items
      cleanupHasExecuted.value = true
      ElMessage.success(res.data.message || '清理完成')
      await Promise.all([loadLogs(), loadWebsiteGroups(), loadBindings()])
    } else {
      ElMessage.error(res.data.message || '执行清理失败')
    }
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '执行清理失败')
  } finally {
    cleanupExecuting.value = false
  }
}

function openConcurrencyDialog() {
  if (!selectedWebsite.value) return
  targetConcurrency.value = 100
  concurrencyHasExecuted.value = false
  concurrencyResults.value = []
  concurrencyMessage.value = ''
  concurrencyDialog.value = true
}

async function submitSetConcurrency() {
  if (!selectedWebsite.value) return
  try {
    await ElMessageBox.confirm(
      `确认将当前网站中由 SmartUp 导入账号的并发数一键设置为 ${targetConcurrency.value}？`,
      '确认修改并发数',
      { type: 'warning' }
    )
  } catch {
    return
  }

  concurrencyExecuting.value = true
  try {
    const res = await websitesApi.setConcurrency(selectedWebsite.value.id, {
      concurrency: targetConcurrency.value
    })
    concurrencyMessage.value = res.data.message
    concurrencyResults.value = res.data.items
    concurrencyHasExecuted.value = true
    if (res.data.success) {
      ElMessage.success('设置完成')
    } else {
      ElMessage.warning(res.data.message || '部分账号设置并发失败')
    }
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '设置并发失败')
  } finally {
    concurrencyExecuting.value = false
  }
}

async function triggerSyncUpstreamModels() {
  if (!selectedWebsite.value) return
  try {
    await ElMessageBox.confirm(
      '确认开始同步上游模型？此操作将仅拉取当前网站中由 SmartUp 导入账号的上游支持模型，并自动更新写入对应的模型白名单/映射配置。',
      '确认同步上游模型',
      { type: 'warning' }
    )
  } catch {
    return
  }

  syncModelsResults.value = []
  syncModelsMessage.value = ''
  syncModelsTotal.value = 0
  syncModelsExecuting.value = true
  syncModelsDialog.value = true

  let hasProcessedStart = false
  let gotComplete = false

  try {
    const authStore = useAuthStore()
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
    }
    if (authStore.token) {
      headers['Authorization'] = `Bearer ${authStore.token}`
    }

    const response = await fetch(`/api/websites/${selectedWebsite.value.id}/accounts/sync-upstream-models/stream`, {
      method: 'POST',
      headers,
    })

    if (!response.ok) {
      let errMsg = `请求失败 (${response.status})`
      try {
        const errJson = await response.json()
        if (errJson?.detail) errMsg = errJson.detail
      } catch {}
      throw new Error(errMsg)
    }

    const reader = response.body?.getReader()
    if (!reader) {
      throw new Error('无法读取响应流')
    }

    const decoder = new TextDecoder()
    let buffer = ''

    while (true) {
      const { done, value } = await reader.read()
      if (done) {
        break
      }

      buffer += decoder.decode(value, { stream: true })
      const lines = buffer.split('\n')
      buffer = lines.pop() || ''

      for (const line of lines) {
        if (!line.trim()) continue
        const eventObj = JSON.parse(line)
        const { event, data } = eventObj

        if (event === 'start') {
          syncModelsTotal.value = data.total_accounts || 0
          hasProcessedStart = true
        } else if (event === 'item') {
          syncModelsResults.value.push(data)
        } else if (event === 'complete') {
          syncModelsMessage.value = data.message
          gotComplete = true
          if (data.success) {
            ElMessage.success('同步完成')
          } else {
            ElMessage.warning(data.message || '部分账号同步模型失败')
          }
        } else if (event === 'error') {
          throw new Error(data.message || '流式同步出错')
        }
      }
    }

    if (buffer.trim()) {
      const eventObj = JSON.parse(buffer)
      const { event, data } = eventObj
      if (event === 'start') {
        syncModelsTotal.value = data.total_accounts || 0
        hasProcessedStart = true
      } else if (event === 'item') {
        syncModelsResults.value.push(data)
      } else if (event === 'complete') {
        syncModelsMessage.value = data.message
        gotComplete = true
        if (data.success) {
          ElMessage.success('同步完成')
        } else {
          ElMessage.warning(data.message || '部分账号同步模型失败')
        }
      } else if (event === 'error') {
        throw new Error(data.message || '流式同步出错')
      }
    }

    if (!gotComplete) {
      throw new Error('同步流异常中断，未获取到完整执行报告')
    }
  } catch (e: any) {
    ElMessage.error(e.message || '同步上游模型失败')
    if (!hasProcessedStart || syncModelsResults.value.length === 0) {
      syncModelsDialog.value = false
    }
  } finally {
    syncModelsExecuting.value = false
  }
}

async function toggleBinding(row: GroupBindingData) {
  try {
    await websitesApi.updateBinding(row.id, { enabled: row.enabled })
    ElMessage.success(row.enabled ? '已启用' : '已禁用')
    await loadLogs()
  } catch (e: any) {
    row.enabled = !row.enabled
    ElMessage.error(e.response?.data?.detail || '更新失败')
  }
}

async function deleteBinding(row: GroupBindingData) {
  try {
    await ElMessageBox.confirm('确认删除该绑定规则？', '删除确认', { type: 'warning' })
    await websitesApi.deleteBinding(row.id)
    ElMessage.success('已删除')
    await loadBindings()
  } catch {}
}

async function openImportGroups(site?: WebsiteData | null) {
  if (upstreams.value.length === 0) await loadUpstreamGroups()
  const target = site || selectedWebsite.value || websites.value[0]
  importGroupsForm.value = {
    website_id: target?.id || 0,
    upstream_id: upstreams.value[0]?.id || 0,
    group_ids: [],
    name_prefix: '',
  }
  importGroupResults.value = []
  importGroupsDialog.value = true
}

async function submitImportGroups() {
  if (!importGroupsForm.value.website_id || !importGroupsForm.value.upstream_id) {
    ElMessage.error('请选择目标网站和来源上游')
    return
  }
  importingGroups.value = true
  try {
    const res = await websitesApi.importGroupsFromUpstream(
      importGroupsForm.value.website_id,
      importGroupsForm.value.upstream_id,
      {
        group_ids: importGroupsForm.value.group_ids,
        name_prefix: importGroupsForm.value.name_prefix,
      },
    )
    importGroupResults.value = res.data.items
    ElMessage[res.data.success ? 'success' : 'warning'](res.data.message)
    if (selectedWebsite.value?.id === importGroupsForm.value.website_id) await loadWebsiteGroups()
    await loadImportTargetGroups(importGroupsForm.value.website_id)
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '导入上游分组失败')
  } finally {
    importingGroups.value = false
  }
}

async function openImportAccounts(site?: WebsiteData | null) {
  if (upstreams.value.length === 0) await loadUpstreamGroups()
  const target = site || selectedWebsite.value || websites.value[0]
  importAccountsForm.value = {
    website_id: target?.id || 0,
    upstream_id: upstreams.value[0]?.id || 0,
    upstream_key_ids: [],
    target_group_map: {},
    account_name_prefix: 'SmartUp',
    default_platform: 'openai',
    platform_mode: 'auto',
    concurrency: 100,
    priority: 1,
    auto_priority_by_rate: true,
  }
  importAccountResults.value = []
  importSyncStatus.value = null

  // 1. 立即打开弹窗，实现秒开体验
  importAccountsDialog.value = true

  // 2. 在后台并发加载分组、Keys，并在加载完成后自动执行同步
  void Promise.all([
    loadImportTargetGroups(importAccountsForm.value.website_id),
    loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
  ]).then(() => {
    void syncImportStatus()
  })
}

async function onImportAccountWebsiteChange(value: number) {
  importAccountsForm.value.target_group_map = {}
  void Promise.all([
    loadImportTargetGroups(value),
    loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
  ]).then(() => {
    void syncImportStatus()
  })
}

async function onImportAccountUpstreamChange(value: number) {
  importAccountsForm.value.upstream_key_ids = []
  importAccountsForm.value.target_group_map = {}
  importAccountResults.value = []
  void loadImportGeneratedKeys(value).then(() => {
    void syncImportStatus()
  })
}

function onPlatformModeChange(value: string) {
  if (value === 'auto') {
    importAccountsForm.value.default_platform = 'openai'
  }
}

function detectPlatform(item: { group_name?: string; group_id?: string; key_name?: string }) {
  const text = `${item.group_name || ''} ${item.group_id || ''} ${item.key_name || ''}`.toLowerCase()
  if (text.includes('claude') || text.includes('anthropic')) return 'Anthropic'
  if (text.includes('gemini')) return 'Gemini'
  if (text.includes('antigravity')) return 'Antigravity'
  return 'OpenAI 兼容'
}

function platformLabel(platform: string) {
  const map: Record<string, string> = {
    openai: 'OpenAI 兼容',
    anthropic: 'Anthropic',
    gemini: 'Gemini',
    antigravity: 'Antigravity',
  }
  return map[platform] || platform || '—'
}

function normalizeGroupName(name: string) {
  return String(name || '')
    .toLowerCase()
    .replace(/^smartup[-_\s]*/i, '')
    .replace(/^ai\d+pro/i, '')
    .replace(/[|｜]/g, ' ')
    .replace(/\s+/g, '')
    .trim()
}

function findTargetGroupForSource(sourceName: string, sourceId: string) {
  const sourceNorm = normalizeGroupName(sourceName || sourceId)
  if (!sourceNorm) return ''

  const exact = importTargetGroups.value.find(g =>
    normalizeGroupName(g.name) === sourceNorm
  )
  if (exact) return exact.id

  const fuzzy = importTargetGroups.value.find(g => {
    const targetNorm = normalizeGroupName(g.name)
    return targetNorm.includes(sourceNorm) || sourceNorm.includes(targetNorm)
  })
  return fuzzy?.id || ''
}

function autoFillAccountTargetGroups() {
  const selected = new Set(importAccountsForm.value.upstream_key_ids)
  const keys = importableGeneratedKeys.value.filter(item => item.id !== null && selected.has(item.id))
  const nextMap = { ...importAccountsForm.value.target_group_map }

  for (const item of keys) {
    if (!item.id || !selected.has(item.id)) continue
    if (nextMap[item.group_id]) continue

    const targetId = findTargetGroupForSource(item.group_name || item.group_id, item.group_id)
    if (targetId) nextMap[item.group_id] = targetId
  }

  importAccountsForm.value.target_group_map = nextMap
}

function selectAllImportableKeys() {
  const keys = importableGeneratedKeys.value
  importAccountsForm.value.upstream_key_ids = keys.map(item => item.id!)
  autoFillAccountTargetGroups()

  const matched = Object.keys(importAccountsForm.value.target_group_map).length
  ElMessage.success(`已选择 ${keys.length} 个 Key，自动匹配 ${matched} 个目标分组`)
}

function clearImportAccountSelection() {
  importAccountsForm.value.upstream_key_ids = []
  importAccountsForm.value.target_group_map = {}
}

async function submitImportAccounts() {
  if (!importAccountsForm.value.website_id || !importAccountsForm.value.upstream_id) {
    ElMessage.error('请选择目标网站和来源上游')
    return
  }
  if (importAccountsForm.value.upstream_key_ids.length === 0) {
    ElMessage.error('请选择要导入的上游 Key')
    return
  }
  importingAccounts.value = true
  try {
    const res = await websitesApi.importAccountsFromUpstreamKeys(importAccountsForm.value.website_id, {
      upstream_key_ids: importAccountsForm.value.upstream_key_ids,
      target_group_map: importAccountsForm.value.target_group_map,
      account_name_prefix: importAccountsForm.value.account_name_prefix,
      default_platform: importAccountsForm.value.default_platform,
      platform_mode: importAccountsForm.value.platform_mode,
      concurrency: importAccountsForm.value.concurrency,
      priority: importAccountsForm.value.priority,
      auto_priority_by_rate: importAccountsForm.value.auto_priority_by_rate,
    })
    importAccountResults.value = res.data.items
    ElMessage[res.data.success ? 'success' : 'warning'](res.data.message)
    await loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
  } catch (e: any) {
    ElMessage.error(e.response?.data?.detail || '创建账号管理账号失败')
  } finally {
    importingAccounts.value = false
  }
}

onMounted(loadAll)
</script>

<style scoped>
.websites-page { display: flex; flex-direction: column; gap: 18px; padding-bottom: 1rem; }

.page-block {
  padding: 1rem;
}

.page-header {
  border-radius: var(--radius-shell);
}

.panel-head {
  min-height: 48px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.panel-title { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.panel-sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.panel-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 4px;
}
.content-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
.cell-name { font-weight: 500; font-size: 14px; }
.cell-url { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.muted { color: var(--text-muted); font-size: 12px; }
.error-text { font-size: 12px; color: var(--color-danger); cursor: pointer; }
.rate-value { font-weight: 600; color: var(--color-primary-strong); font-family: monospace; }
.action-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
}
.action-row .el-button {
  justify-self: center;
}

.site-switcher {
  width: 180px;
  flex-shrink: 0;
}

.binding-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}
.binding-actions .el-button--danger,
.action-row .el-button--danger {
  --el-button-bg-color: transparent;
  --el-button-border-color: transparent;
}
.binding-actions .el-button--danger:hover,
.action-row .el-button--danger:hover {
  --el-button-bg-color: var(--el-color-danger-light-8, #fef0f0);
  --el-button-border-color: var(--el-color-danger-light-5, #fbc4c4);
}
.binding-list { min-height: 120px; }
.import-stats {
  margin: 0 0 8px;
  color: var(--text-muted);
  font-size: 12px;
}
.binding-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-color);
}
.binding-item:last-child { border-bottom: none; }
.binding-main { min-width: 0; }
.binding-title {
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.binding-meta { color: var(--text-muted); font-size: 12px; margin-top: 3px; }
.empty-hint {
  text-align: center;
  padding: 36px 16px;
  color: var(--text-muted);
  font-size: 13px;
}
.switch-line {
  min-height: 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text-secondary);
  font-size: 13px;
}
.dialog-note { margin-bottom: 12px; }
.result-panel {
  margin-top: 14px;
  border-top: 1px solid var(--border-color);
  padding-top: 12px;
}
.result-title {
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}
.mapping-panel {
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 12px;
}
.mapping-row {
  min-height: 38px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.mapping-row + .mapping-row {
  border-top: 1px solid var(--border-color);
}
.mapping-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-secondary);
  font-size: 13px;
}

@media (min-width: 1024px) {
  .content-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

@media (max-width: 768px) {
  .page-header {
    flex-direction: column;
    align-items: stretch;
  }
  .page-header .el-button { min-height: 44px; }
  .binding-item {
    align-items: flex-start;
    flex-direction: column;
  }
  .binding-actions { width: 100%; justify-content: flex-end; }
  .mapping-row {
    align-items: stretch;
    flex-direction: column;
    padding: 8px 0;
  }
  .mapping-row .el-select { width: 100% !important; }
}

/* Custom group selector layout styles */
.custom-selector-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px;
  background: #160c0a;
  border: 1px solid #3e2821;
  border-radius: 6px;
}

.selector-info-area {
  flex: 1;
  min-width: 0;
}

.selected-count-line {
  font-size: 12px;
  color: #a68d85;
}

.accent-bold-text {
  color: #df9b56;
  font-weight: 700;
}

.empty-placeholder-text {
  font-size: 12px;
  color: rgba(166, 141, 133, 0.6);
  margin-top: 4px;
}

.tags-container-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.custom-inline-tag {
  background: rgba(223, 155, 86, 0.08) !important;
  border-color: rgba(223, 155, 86, 0.2) !important;
  color: #df9b56 !important;
  max-width: 100%;
}

.btn-select-trigger {
  padding: 8px 16px;
  background: #df9b56;
  color: #1b110e;
  border: none;
  font-size: 12px;
  font-weight: 700;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.2s;
  flex-shrink: 0;
}

.btn-select-trigger:hover {
  background: #cb8440;
}

/* Custom Stepper Input */
.custom-percent-stepper {
  display: flex;
  border: 1px solid #3e2821;
  border-radius: 4px;
  background: #160c0a;
  overflow: hidden;
  height: 36px;
  align-items: center;
  width: 100%;
}

.stepper-btn {
  width: 36px;
  height: 100%;
  border: none;
  background: transparent;
  color: #a68d85;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}

.stepper-btn:hover {
  background: #271a16;
  color: #f5ecea;
}

.stepper-input {
  flex: 1;
  border: none;
  background: transparent;
  text-align: center;
  font-size: 13px;
  color: #f5ecea;
  outline: none;
  width: 100%;
}

.stepper-input::-webkit-inner-spin-button,
.stepper-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Custom Switch Toggle */
.switch-toggle-line {
  display: flex;
  align-items: center;
  min-height: 36px;
}

.custom-switch-toggle {
  width: 48px;
  height: 24px;
  border-radius: 12px;
  background: #160c0a;
  border: 1px solid #3e2821;
  padding: 2px;
  cursor: pointer;
  display: flex;
  align-items: center;
  position: relative;
  transition: all 0.2s;
}

.custom-switch-toggle.active {
  border-color: #df9b56;
}

.toggle-circle {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #a68d85;
  transition: transform 0.2s, background-color 0.2s;
  transform: translateX(0);
}

.custom-switch-toggle.active .toggle-circle {
  transform: translateX(24px);
  background: #df9b56;
}

/* Redesigned Button Actions */
.btn-cancel, .btn-save {
  font-size: 12px;
  font-weight: 700;
  border-radius: 4px;
  border: none !important;
  transition: all 0.2s;
}

.btn-cancel {
  background: #f5ecea !important;
  color: #1b110e !important;
}

.btn-cancel:hover {
  background: rgba(245, 236, 234, 0.9) !important;
}

.btn-save {
  background: #df9b56 !important;
  color: #1b110e !important;
}

.btn-save:hover {
  background: #cb8440 !important;
}
</style>

<style>
/* Custom Theme Dialog & Drawer */
.custom-binding-drawer .el-drawer__body,
.custom-binding-drawer .el-drawer__header,
.custom-binding-drawer .el-drawer__footer {
  background: #271a16 !important;
  color: #f5ecea !important;
}

.custom-binding-drawer .el-drawer__header {
  border-bottom: 1px solid #3e2821;
  margin-bottom: 0;
  padding: 16px 20px;
}

.custom-binding-drawer .el-drawer__title {
  color: #f5ecea !important;
  font-weight: 700;
}

.custom-binding-drawer .el-drawer__footer {
  border-top: 1px solid #3e2821;
  background: rgba(22, 12, 10, 0.3) !important;
  padding: 16px 20px;
}

.custom-binding-drawer .el-form-item__label {
  color: #a68d85 !important;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

/* Dialog Theme */
.custom-theme-dialog .el-dialog {
  background: #271a16 !important;
  border: 1px solid #3e2821;
  border-radius: 8px;
  width: min(85vw, 1200px) !important;
}

.custom-theme-dialog .el-dialog__header {
  border-bottom: 1px solid #3e2821;
  margin-right: 0;
  padding: 16px 20px 12px;
}

.custom-theme-dialog .el-dialog__title {
  color: #f5ecea !important;
  font-weight: 700;
  font-size: 15px;
}

.custom-theme-dialog .el-dialog__footer {
  border-top: 1px solid #3e2821;
  background: rgba(22, 12, 10, 0.3);
  padding: 12px 20px;
}

/* Select Option Input Search box */
.custom-theme-search .el-input__wrapper {
  background: #160c0a !important;
  border: 1px solid #3e2821 !important;
  box-shadow: none !important;
}

.custom-theme-search .el-input__inner {
  color: #f5ecea !important;
  font-size: 12px;
}

.custom-theme-search .el-input__inner::placeholder {
  color: rgba(166, 141, 133, 0.4) !important;
}

/* Element Select Box Theme */
.custom-select-wrapper {
  width: 100%;
}

.custom-theme-select {
  width: 100% !important;
}

.custom-theme-select .el-select__wrapper {
  background: #160c0a !important;
  border: 1px solid #3e2821 !important;
  box-shadow: none !important;
  width: 100% !important;
  min-height: 36px;
}

.custom-theme-select .el-select__placeholder {
  color: #f5ecea !important;
}

.custom-theme-select .el-select__selected-item {
  color: #f5ecea !important;
}
</style>

<style scoped>
/* Layout for selectors dialog */
.group-selector-layout {
  display: grid;
  grid-template-columns: 200px 1fr 240px;
  gap: 16px;
  height: 55vh;
  min-height: 450px;
  max-height: 750px;
  border: 1px solid #3e2821;
  border-radius: 8px;
  background: #271a16;
  overflow: hidden;
}

.left-panel, .middle-panel, .right-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.left-panel {
  border-right: 1px solid #3e2821;
}

.right-panel {
  border-left: 1px solid #3e2821;
}

.panel-header {
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 600;
  color: #f5ecea;
  background: rgba(22, 12, 10, 0.3);
  border-bottom: 1px solid #3e2821;
  min-height: 38px;
  display: flex;
  align-items: center;
}

.panel-header.flex-header {
  justify-content: space-between;
}

.list-container {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
}

/* Left panel sidebar category filters */
.site-filter-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 4px;
  cursor: pointer;
  margin-bottom: 4px;
  background: transparent;
  border: 1px solid transparent;
  font-size: 12px;
  color: #a68d85;
  width: 100%;
  text-align: left;
  transition: all 0.15s ease;
}

.site-filter-btn:hover {
  background: #160c0a;
  color: #f5ecea;
}

.site-filter-btn.active {
  background: rgba(223, 155, 86, 0.1);
  border-color: rgba(223, 155, 86, 0.4);
  color: #df9b56;
  font-weight: 600;
}

.site-count-badge {
  background: #160c0a;
  color: #a68d85;
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 9px;
}

.site-count-badge.badge-active {
  background: #f5ecea;
  color: #1b110e;
  font-weight: 700;
}

/* Middle panel group card items */
.group-card-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border-radius: 6px;
  cursor: pointer;
  margin-bottom: 8px;
  background: #160c0a;
  border: 1px solid rgba(62, 40, 33, 0.6);
  transition: all 0.15s ease;
}

.group-card-item:hover {
  border-color: #df9b56;
}

.group-card-item.selected {
  background: rgba(223, 155, 86, 0.04);
  border-color: #df9b56;
}

.card-left-part {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex: 1;
}

.card-details-info {
  min-width: 0;
  flex: 1;
}

.card-meta-line {
  display: flex;
  align-items: center;
}

.card-upstream-badge {
  background: rgba(223, 155, 86, 0.1);
  color: #df9b56;
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
}

.card-id-text {
  color: #a68d85;
  font-size: 10px;
  margin-left: 8px;
}

.card-name-title {
  font-size: 13px;
  color: #f5ecea;
  margin-top: 6px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-right-part {
  text-align: right;
  flex-shrink: 0;
}

.card-rate-label {
  font-size: 9px;
  color: #a68d85;
  display: block;
}

.card-rate-value {
  font-size: 13px;
  font-weight: 700;
  color: #df9b56;
}

.accent-text-bold {
  color: #df9b56;
  font-weight: 700;
}

/* Right panel selected card items */
.selected-card-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px;
  background: #160c0a;
  border: 1px solid #3e2821;
  border-radius: 4px;
  margin-bottom: 8px;
}

.selected-card-info-box {
  flex: 1;
  min-width: 0;
}

.selected-card-meta-line {
  font-size: 9px;
  color: #a68d85;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.selected-card-title-text {
  font-size: 12px;
  color: #f5ecea;
  font-weight: 500;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.btn-trash-item {
  background: transparent;
  border: none;
  color: #a68d85;
  cursor: pointer;
  padding: 4px;
  transition: color 0.15s;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn-trash-item:hover {
  color: #df9b56;
}

.btn-clear-link {
  background: transparent;
  border: none;
  color: #df9b56;
  font-size: 11px;
  cursor: pointer;
  transition: color 0.15s;
}

.btn-clear-link:hover {
  color: #cb8440;
}

.empty-layers-icon {
  font-size: 24px;
  color: rgba(166, 141, 133, 0.2);
  margin-bottom: 8px;
}

/* Combination Search and Filter Bar */
.dialog-filter-bar {
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
}

.keyword-search-input {
  flex: 1;
}

.rate-range-inputs {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

.rate-input-box {
  display: flex;
  align-items: center;
  background: #160c0a;
  border: 1px solid #3e2821;
  border-radius: 4px;
  height: 36px;
  padding: 0 10px;
  gap: 8px;
}

.rate-input-label {
  font-size: 11px;
  color: #a68d85;
  white-space: nowrap;
  font-weight: 600;
  text-transform: uppercase;
}

.rate-number-input {
  width: 80px;
  border: none;
  background: transparent;
  color: #f5ecea;
  outline: none;
  font-size: 12px;
  height: 100%;
  text-align: center;
}

.rate-number-input::placeholder {
  color: rgba(166, 141, 133, 0.3);
}

.rate-number-input::-webkit-inner-spin-button,
.rate-number-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Responsive dialog styling */
@media (max-width: 768px) {
  .dialog-filter-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }

  .rate-range-inputs {
    justify-content: space-between;
    width: 100%;
  }

  .rate-input-box {
    flex: 1;
    justify-content: center;
  }

  .rate-number-input {
    width: 100%;
  }

  .group-selector-layout {
    display: flex;
    flex-direction: column;
    height: auto;
    max-height: 480px;
    overflow-y: auto;
  }

  .left-panel {
    border-right: none;
    border-bottom: 1px solid #3e2821;
    max-height: 120px;
    height: auto;
  }

  .left-panel .list-container {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px;
  }

  .left-panel .site-filter-btn {
    margin-bottom: 0;
    padding: 4px 10px;
    width: auto;
  }

  .middle-panel {
    max-height: 240px;
  }

  .right-panel {
    border-left: none;
    border-top: 1px solid #3e2821;
    max-height: 160px;
  }
}
</style>
