<!-- =====================================================================
  UnifiedSettingsModal.vue — 统一设置弹窗
  合并原 SettingsModal（AI/中继）与 OssSettingsModal（云存储），tab 分区切换
  ===================================================================== -->
<script setup lang="ts">
import { ref, watch } from 'vue'
import type { AiCfg, OssCfg } from '../../core/types'
import { store } from '../../core/store'
import { syncState, syncPending, canUploadNow } from '../../core/assets'

export type SettingsTab = 'ai' | 'oss' | 'relay'

const props = defineProps<{ visible: boolean; initialTab?: SettingsTab }>()
const emit = defineEmits<{
  (e: 'close'): void
  (e: 'toast', msg: string): void
}>()

const tab = ref<SettingsTab>('ai')
watch(() => props.visible, (v) => {
  if (v) { tab.value = props.initialTab || 'ai'; loadFromStore() }
}, { immediate: true })

/* ==================== AI 模型 ==================== */
const PRESETS: Record<string, { protocol: 'openai' | 'anthropic'; base: string; model: string; label: string }> = {
  zhipu:      { protocol: 'openai',    base: 'https://open.bigmodel.cn/api/paas/v4',                 model: 'glm-4.6',              label: '智谱 GLM (OpenAI 协议)' },
  zhipu_anth: { protocol: 'anthropic', base: 'https://open.bigmodel.cn/api/anthropic',              model: 'glm-4.6',              label: '智谱 GLM (Anthropic 协议)' },
  deepseek:   { protocol: 'openai',    base: 'https://api.deepseek.com',                            model: 'deepseek-chat',        label: 'DeepSeek' },
  qwen:       { protocol: 'openai',    base: 'https://dashscope.aliyuncs.com/compatible-mode/v1',   model: 'qwen-plus',            label: '通义千问' },
  kimi:       { protocol: 'openai',    base: 'https://api.moonshot.cn/v1',                          model: 'moonshot-v1-8k',       label: 'Kimi' },
  doubao:     { protocol: 'openai',    base: 'https://ark.cn-beijing.volces.com/api/v3',            model: 'doubao-pro-32k',       label: '豆包' },
  openai:     { protocol: 'openai',    base: 'https://api.openai.com/v1',                           model: 'gpt-4o-mini',          label: 'OpenAI' },
  anthropic:  { protocol: 'anthropic', base: 'https://api.anthropic.com',                           model: 'claude-sonnet-5',      label: 'Anthropic' },
  gemini:     { protocol: 'openai',    base: 'https://generativelanguage.googleapis.com/v1beta/openai', model: 'gemini-2.0-flash', label: 'Gemini' },
  groq:       { protocol: 'openai',    base: 'https://api.groq.com/openai/v1',                      model: 'llama-3.3-70b-versatile', label: 'Groq' },
  ollama:     { protocol: 'openai',    base: 'http://localhost:11434/v1',                           model: 'llama3.1',             label: 'Ollama (本地)' }
}

const PROTO_DEFAULTS: Record<string, { base: string; model: string }> = {
  openai:    { base: 'https://open.bigmodel.cn/api/paas/v4', model: 'glm-4.6' },
  anthropic: { base: 'https://open.bigmodel.cn/api/anthropic', model: 'glm-4.6' }
}

const aiForm = ref<AiCfg>({
  preset: 'zhipu', protocol: 'openai',
  base: '', key: '', model: '', proxy: '',
  imgBase: '', imgKey: '', imgModel: '',
  relayUrl: '', relayToken: '', relayDeviceId: ''
})

/* ==================== 云存储（OSS） ==================== */
const ossForm = ref<OssCfg>({
  enabled: false, provider: 'aliyun', dir: 'u-ppt',
  aliAccessKeyId: '', aliAccessKeySecret: '', aliEndpoint: '', aliBucket: '',
  qiniuAccessKey: '', qiniuSecretKey: '', qiniuBucket: '', qiniuUpHost: '', qiniuDomain: '',
  viewerBase: ''
})

/** 从 store 读取并填充两份表单 */
function loadFromStore() {
  const c = store.getCfg()
  aiForm.value = {
    preset: PRESETS[c.preset] ? c.preset : 'custom',
    protocol: c.protocol || 'openai',
    base: c.base, key: c.key, model: c.model, proxy: c.proxy,
    imgBase: c.imgBase || '',
    imgKey: c.imgKey || '',
    imgModel: c.imgModel || '',
    relayUrl: c.relayUrl || '',
    relayToken: c.relayToken || '',
    relayDeviceId: c.relayDeviceId || ''
  }
  ossForm.value = { ...ossForm.value, ...store.getOssCfg() }
}

function applyPreset(key: string) {
  const p = PRESETS[key]
  if (!p) return
  aiForm.value.protocol = p.protocol
  aiForm.value.base = p.base
  aiForm.value.model = p.model
}

function onProviderChange() {
  if (aiForm.value.preset !== 'custom') applyPreset(aiForm.value.preset)
}

function applyProtoDefaults(p: string) {
  const d = PROTO_DEFAULTS[p] || PROTO_DEFAULTS.openai
  const other = PROTO_DEFAULTS[p === 'openai' ? 'anthropic' : 'openai']
  if (!aiForm.value.base.trim() || aiForm.value.base.trim() === other.base) aiForm.value.base = d.base
  if (!aiForm.value.model.trim() || aiForm.value.model.trim() === other.model) aiForm.value.model = d.model
}

function onProtocolChange() {
  applyProtoDefaults(aiForm.value.protocol)
}

/* ==================== 保存 ==================== */
function save() {
  if (tab.value === 'ai') {
    const f = aiForm.value
    store.setCfg({
      preset: f.preset,
      protocol: f.protocol,
      base: f.base.trim(),
      key: f.key.trim(),
      model: f.model.trim(),
      proxy: f.proxy.trim(),
      imgBase: (f.imgBase || '').trim(),
      imgKey: (f.imgKey || '').trim(),
      imgModel: (f.imgModel || '').trim(),
      relayUrl: (f.relayUrl || '').trim(),
      relayToken: (f.relayToken || '').trim(),
      relayDeviceId: (f.relayDeviceId || '').trim()
    })
    const label = f.preset === 'custom'
      ? (f.protocol === 'anthropic' ? 'Anthropic' : 'OpenAI') + ' 自定义'
      : (PRESETS[f.preset]?.label || f.preset)
    emit('toast', '已保存 AI 设置（' + label + '）')
  } else if (tab.value === 'oss') {
    saveOss()
  } else {
    // 中继 tab：只更新中继三项，AI 其余字段原样回写
    const f = aiForm.value
    const c = store.getCfg()
    store.setCfg({
      ...c,
      preset: f.preset,
      protocol: f.protocol,
      base: f.base.trim(),
      key: f.key.trim(),
      model: f.model.trim(),
      proxy: f.proxy.trim(),
      imgBase: (f.imgBase || '').trim(),
      imgKey: (f.imgKey || '').trim(),
      imgModel: (f.imgModel || '').trim(),
      relayUrl: (f.relayUrl || '').trim(),
      relayToken: (f.relayToken || '').trim(),
      relayDeviceId: (f.relayDeviceId || '').trim()
    })
    emit('toast', '已保存 Agent 中继设置')
  }
  emit('close')
}

function saveOss() {
  const c = ossForm.value
  store.setOssCfg({
    enabled: c.enabled,
    provider: c.provider,
    dir: c.dir.trim(),
    aliAccessKeyId: c.aliAccessKeyId.trim(),
    aliAccessKeySecret: c.aliAccessKeySecret.trim(),
    aliEndpoint: c.aliEndpoint.trim(),
    aliBucket: c.aliBucket.trim(),
    qiniuAccessKey: c.qiniuAccessKey.trim(),
    qiniuSecretKey: c.qiniuSecretKey.trim(),
    qiniuBucket: c.qiniuBucket.trim(),
    qiniuUpHost: c.qiniuUpHost.trim(),
    qiniuDomain: c.qiniuDomain.trim(),
    viewerBase: c.viewerBase.trim()
  })
  emit('toast', c.enabled ? '已保存云存储设置（已启用）' : '已保存云存储设置（未启用）')
}

async function manualSync() {
  if (!canUploadNow()) {
    emit('toast', '当前不可同步：需桌面版 + 已联网 + 已启用并保存配置')
    return
  }
  const r = await syncPending()
  emit('toast', `同步完成：成功 ${r.done}，失败 ${r.fail}`)
}
</script>

<template>
  <div class="modal-mask" :class="{ hidden: !visible }" @click.self="emit('close')">
    <div class="modal unified-modal">
      <h3>设置</h3>

      <!-- tab 栏 -->
      <div class="tab-bar">
        <button class="tab-btn" :class="{ active: tab === 'ai' }" @click="tab = 'ai'">AI 模型</button>
        <button class="tab-btn" :class="{ active: tab === 'oss' }" @click="tab = 'oss'">云存储</button>
        <button class="tab-btn" :class="{ active: tab === 'relay' }" @click="tab = 'relay'">Agent 中继</button>
      </div>

      <!-- 内容区：统一 min-height，避免切 tab 时弹窗高度跳动 -->
      <div class="settings-body">
      <!-- ==================== AI 模型 ==================== -->
      <template v-if="tab === 'ai'">
        <p class="modal-tip">配置大模型服务商。数据仅保存在本地浏览器。</p>

        <div class="form-row">
          <label>服务商</label>
          <select v-model="aiForm.preset" @change="onProviderChange">
            <optgroup label="国内">
              <option value="zhipu">智谱 GLM (OpenAI 协议)</option>
              <option value="zhipu_anth">智谱 GLM (Anthropic 协议)</option>
              <option value="deepseek">DeepSeek</option>
              <option value="qwen">通义千问</option>
              <option value="kimi">Kimi</option>
              <option value="doubao">豆包</option>
            </optgroup>
            <optgroup label="海外">
              <option value="openai">OpenAI</option>
              <option value="anthropic">Anthropic</option>
              <option value="gemini">Gemini</option>
              <option value="groq">Groq</option>
            </optgroup>
            <optgroup label="本地">
              <option value="ollama">Ollama</option>
            </optgroup>
            <option value="custom">自定义</option>
          </select>
        </div>

        <div class="form-row">
          <label>API 协议</label>
          <select v-model="aiForm.protocol" @change="onProtocolChange">
            <option value="openai">OpenAI</option>
            <option value="anthropic">Anthropic</option>
          </select>
        </div>

        <div class="form-row">
          <label>Base URL</label>
          <input type="text" v-model="aiForm.base" placeholder="https://..." />
        </div>

        <div class="form-row">
          <label>API Key</label>
          <input type="password" v-model="aiForm.key" placeholder="sk-..." autocomplete="off" />
        </div>

        <div class="form-row">
          <label>模型</label>
          <input type="text" v-model="aiForm.model" placeholder="模型名称" />
        </div>

        <div class="form-row">
          <label>代理 URL（可选）</label>
          <input type="text" v-model="aiForm.proxy" placeholder="留空则直连" />
        </div>

        <div class="section-title">图像模型（可选，用于 AI 配图）</div>

        <div class="form-row">
          <label>图像 Base URL</label>
          <input type="text" v-model="aiForm.imgBase" placeholder="留空则复用上方 Base URL" />
        </div>

        <div class="form-row">
          <label>图像 API Key</label>
          <input type="password" v-model="aiForm.imgKey" placeholder="留空则复用上方 Key" autocomplete="off" />
        </div>

        <div class="form-row">
          <label>图像模型</label>
          <input type="text" v-model="aiForm.imgModel" placeholder="dall-e-3" />
        </div>
      </template>

      <!-- ==================== 云存储 ==================== -->
      <template v-else-if="tab === 'oss'">
        <p class="modal-tip">
          开启后，图片/视频等媒体自动上传对象存储，避免撑爆本地。离线时先暂存本地，联网后自动同步云端。密钥仅保存在本地。
        </p>

        <div class="form-row">
          <label>启用云存储</label>
          <label class="switch-line">
            <input type="checkbox" v-model="ossForm.enabled" />
            <span>{{ ossForm.enabled ? '开' : '关（维持本地内嵌）' }}</span>
          </label>
        </div>

        <div class="form-row">
          <label>服务商</label>
          <select v-model="ossForm.provider">
            <option value="aliyun">阿里云 OSS</option>
            <option value="qiniu">七牛云 Kodo</option>
          </select>
        </div>

        <div class="form-row">
          <label>所属目录</label>
          <input type="text" v-model="ossForm.dir" placeholder="如 u-ppt/images，可留空" />
        </div>

        <div class="form-row">
          <label>查看器地址</label>
          <input type="text" v-model="ossForm.viewerBase" placeholder="如 https://img.1216.top，生成分享链接必填" />
        </div>

        <!-- 阿里云 -->
        <template v-if="ossForm.provider === 'aliyun'">
          <div class="section-title">阿里云 OSS</div>
          <div class="form-row">
            <label>AccessKeyId</label>
            <input type="text" v-model="ossForm.aliAccessKeyId" placeholder="LTAI..." autocomplete="off" />
          </div>
          <div class="form-row">
            <label>AccessKeySecret</label>
            <input type="password" v-model="ossForm.aliAccessKeySecret" placeholder="密钥" autocomplete="off" />
          </div>
          <div class="form-row">
            <label>Endpoint</label>
            <input type="text" v-model="ossForm.aliEndpoint" placeholder="oss-cn-hangzhou.aliyuncs.com" />
          </div>
          <div class="form-row">
            <label>Bucket</label>
            <input type="text" v-model="ossForm.aliBucket" placeholder="bucket 名称" />
          </div>
        </template>

        <!-- 七牛云 -->
        <template v-else>
          <div class="section-title">七牛云 Kodo</div>
          <div class="form-row">
            <label>AccessKey</label>
            <input type="text" v-model="ossForm.qiniuAccessKey" placeholder="AK" autocomplete="off" />
          </div>
          <div class="form-row">
            <label>SecretKey</label>
            <input type="password" v-model="ossForm.qiniuSecretKey" placeholder="SK" autocomplete="off" />
          </div>
          <div class="form-row">
            <label>Bucket</label>
            <input type="text" v-model="ossForm.qiniuBucket" placeholder="空间名称" />
          </div>
          <div class="form-row">
            <label>加速域名</label>
            <input type="text" v-model="ossForm.qiniuDomain" placeholder="https://cdn.example.com" />
          </div>
          <div class="form-row">
            <label>上传域名（可选）</label>
            <input type="text" v-model="ossForm.qiniuUpHost" placeholder="留空自动探测区域" />
          </div>
        </template>

        <div class="sync-bar">
          <div class="sync-info">
            <div>
              待同步 {{ syncState.pending }} 项<template v-if="syncState.syncing">（同步中…）</template>
              <span v-if="syncState.lastError" class="sync-err">· 有错误</span>
            </div>
            <div v-if="syncState.lastError" class="sync-err-detail">{{ syncState.lastError }}</div>
          </div>
          <button class="btn" @click="manualSync" :disabled="syncState.syncing">立即同步</button>
        </div>
      </template>

      <!-- ==================== Agent 中继 ==================== -->
      <template v-else>
        <p class="modal-tip">通过 u-relay 中继接收远端 Agent 指令。可选功能，三项配置齐备即自动启用。</p>

        <div class="form-row">
          <label>中继 URL</label>
          <input type="text" v-model="aiForm.relayUrl" placeholder="wss://u-work.1216.top（可省略 /ws/miniapp）" />
        </div>

        <div class="form-row">
          <label>中继 Token</label>
          <input type="password" v-model="aiForm.relayToken" placeholder="设备配对 Token" autocomplete="off" />
        </div>

        <div class="form-row">
          <label>设备 ID</label>
          <input type="text" v-model="aiForm.relayDeviceId" placeholder="device_id" />
        </div>
      </template>
      </div>

      <div class="modal-actions">
        <button class="btn" @click="emit('close')">取消</button>
        <button class="btn primary" @click="save">保存</button>
      </div>
    </div>
  </div>
</template>

<style scoped>
/* 弹窗加宽（仅本组件） */
.unified-modal { width: 520px; display: flex; flex-direction: column; }

/* 内容区统一最小高度：以最高 tab（云存储）为基准，切 tab 不再跳动 */
.settings-body { min-height: 440px; }

/* tab 栏：下划线高亮 */
.tab-bar {
  display: flex;
  gap: 18px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--ui-border);
}
.tab-btn {
  border: none;
  background: transparent;
  padding: 8px 2px;
  font-size: 13.5px;
  color: var(--ui-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab-btn.active { color: var(--ui-primary, #5b5bd6); border-bottom-color: var(--ui-primary, #5b5bd6); font-weight: 600; }

/* 紧凑化：label 与输入同行 */
.form-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}
.form-row > label {
  display: block;
  width: 110px;
  flex-shrink: 0;
  text-align: right;
  white-space: nowrap;
  margin-bottom: 0;
}
.form-row > select,
.form-row > input { flex: 1; min-width: 0; }

.section-title {
  margin: 18px 0 10px;
  padding-top: 14px;
  border-top: 1px solid var(--ui-border);
  font-size: 13px;
  font-weight: 600;
  color: var(--ui-text);
}
.section-title.first { margin-top: 0; padding-top: 0; border-top: none; }

.switch-line {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ui-muted);
  flex: 1;
}
.switch-line input { width: auto; }

.sync-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--ui-border);
}
.sync-info { font-size: 12px; color: var(--ui-muted); }
.sync-err { color: #e5484d; }
.sync-err-detail {
  margin-top: 4px;
  max-width: 420px;
  word-break: break-all;
  font-size: 12px;
  line-height: 1.5;
  color: #e5484d;
}
</style>
