<template>
  <v-container fluid class="pa-6">
    <v-row>
      <!-- System Settings -->
      <v-col cols="12" lg="6">
        <v-card elevation="0" border rounded="lg" class="mb-4">
          <v-card-title class="d-flex align-center">
            <v-icon class="mr-2">mdi-cog</v-icon>
            系统设置
          </v-card-title>
          <v-progress-linear v-if="settingsLoading" indeterminate color="primary" />
          <v-divider />
          <v-card-text>
            <v-text-field v-model="settings.system_name" label="系统名称" variant="outlined" density="compact" class="mb-3" :rules="[required('系统名称')]" />
            <v-text-field v-model="settings.system_title" label="系统标题" variant="outlined" density="compact" class="mb-3" :rules="[required('系统标题')]" />

            <v-divider class="my-4" />
            <div class="text-subtitle-2 mb-3">告警阈值</div>
            <v-row dense>
              <v-col cols="4">
                <v-text-field v-model="settings.cpu_alert_threshold" label="CPU %" variant="outlined" density="compact" type="number" :rules="[required('阈值'), numberRange(1, 100, '阈值')]" />
              </v-col>
              <v-col cols="4">
                <v-text-field v-model="settings.mem_alert_threshold" label="内存 %" variant="outlined" density="compact" type="number" :rules="[required('阈值'), numberRange(1, 100, '阈值')]" />
              </v-col>
              <v-col cols="4">
                <v-text-field v-model="settings.disk_alert_threshold" label="磁盘 %" variant="outlined" density="compact" type="number" :rules="[required('阈值'), numberRange(1, 100, '阈值')]" />
              </v-col>
            </v-row>

            <v-divider class="my-4" />
            <div class="text-subtitle-2 mb-3">连接池</div>
            <v-row dense>
              <v-col cols="6">
                <v-text-field v-model="settings.db_pool_size" label="连接池大小" variant="outlined" density="compact" type="number" :rules="[required(), isNumber()]" />
              </v-col>
              <v-col cols="6">
                <v-text-field v-model="settings.db_max_overflow" label="溢出连接数" variant="outlined" density="compact" type="number" :rules="[required(), isNumber()]" />
              </v-col>
            </v-row>
          </v-card-text>
          <v-card-actions class="px-4 pb-4">
            <v-spacer />
            <v-btn color="primary" variant="flat" @click="saveSettings" :loading="saving">保存设置</v-btn>
          </v-card-actions>
        </v-card>

        <TerminalQuickCommandsSettings />

        <!-- Telegram Settings -->
        <v-card elevation="0" border rounded="lg">
          <v-card-title class="d-flex align-center">
            <v-icon class="mr-2">mdi-send</v-icon>
            Telegram 推送
          </v-card-title>
          <v-divider />
          <v-card-text>
            <v-text-field v-model="settings.telegram_bot_token" label="Bot Token" variant="outlined" density="compact" class="mb-3" :type="showToken ? 'text' : 'password'" :append-inner-icon="showToken ? 'mdi-eye' : 'mdi-eye-off'" @click:append-inner="showToken = !showToken" />
            <v-text-field v-model="settings.telegram_chat_id" label="Chat ID" variant="outlined" density="compact" class="mb-3" />
            <v-btn size="small" variant="tonal" prepend-icon="mdi-message-text" @click="testTelegram" :loading="testingTg">发送测试消息</v-btn>
          </v-card-text>
        </v-card>
      </v-col>

      <!-- Security Settings -->
      <v-col cols="12" lg="6">
        <!-- Password Change -->
        <v-card elevation="0" border rounded="lg" class="mb-4">
          <v-card-title class="d-flex align-center">
            <v-icon class="mr-2">mdi-lock</v-icon>
            修改密码
          </v-card-title>
          <v-divider />
          <v-card-text>
            <v-text-field v-model="pwForm.current" label="当前密码" variant="outlined" density="compact" type="password" class="mb-3" :rules="[required('密码')]" />
            <v-text-field v-model="pwForm.new_pw" label="新密码" variant="outlined" density="compact" type="password" class="mb-3" :rules="[required('密码')]" />
            <v-text-field v-model="pwForm.confirm" label="确认新密码" variant="outlined" density="compact" type="password" class="mb-3" :rules="[required('确认密码'), matchOther(() => pwForm.new_pw)]" />
            <v-text-field
              v-if="auth.admin?.totp_enabled"
              v-model="pwForm.totp_code"
              label="TOTP 验证码"
              variant="outlined"
              density="compact"
              type="text"
              inputmode="numeric"
              maxlength="6"
              class="mb-3"
              :rules="auth.admin?.totp_enabled ? [required('验证码')] : []"
            />
          </v-card-text>
          <v-card-actions class="px-4 pb-4">
            <v-spacer />
            <v-btn color="primary" variant="flat" @click="changePassword" :loading="changingPw">修改密码</v-btn>
          </v-card-actions>
        </v-card>

        <!-- TOTP -->
        <v-card elevation="0" border rounded="lg" class="mb-4">
          <v-card-title class="d-flex align-center">
            <v-icon class="mr-2">mdi-shield-key</v-icon>
            双因素认证 (TOTP)
          </v-card-title>
          <v-divider />
          <v-card-text>
            <div class="d-flex align-center mb-3">
              <span class="text-body-2">状态：</span>
              <v-chip :color="auth.admin?.totp_enabled ? 'success' : 'grey'" size="small" variant="tonal" label class="ml-2">
                {{ auth.admin?.totp_enabled ? '已启用' : '未启用' }}
              </v-chip>
            </div>
            <div v-if="totpQr" class="text-center mb-3">
              <img :src="totpQr" alt="TOTP QR" style="max-width: 200px" />
              <div v-if="totpSecret" class="d-flex align-center justify-center ga-2 mt-2">
                <code class="text-caption pa-1 bg-grey-lighten-4 rounded" style="user-select: all">{{ totpSecret }}</code>
                <v-btn size="x-small" variant="text" icon="mdi-content-copy" @click="copyTotpSecret" />
              </div>
              <div class="text-caption text-medium-emphasis mt-1">用认证器 App 扫描二维码或手动输入密钥</div>
            </div>
            <div v-if="!auth.admin?.totp_enabled">
              <v-btn v-if="!totpQr" size="small" variant="tonal" prepend-icon="mdi-qrcode" @click="setupTotp">生成二维码</v-btn>
              <div v-else class="d-flex ga-2 align-center">
                <v-text-field v-model="totpCode" label="验证码" variant="outlined" density="compact" style="max-width: 160px" />
                <v-btn color="primary" variant="flat" size="small" @click="enableTotp" :loading="enablingTotp">启用</v-btn>
              </div>
            </div>
            <v-btn v-else size="small" variant="tonal" color="error" prepend-icon="mdi-shield-off" @click="disableTotp">禁用 TOTP</v-btn>
          </v-card-text>
        </v-card>

        <!-- API Key -->
        <v-card elevation="0" border rounded="lg" class="mb-4">
          <v-card-title class="d-flex align-center">
            <v-icon class="mr-2">mdi-key</v-icon>
            API Key
          </v-card-title>
          <v-divider />
          <v-card-text>
            <div class="d-flex align-center ga-2">
              <v-text-field :model-value="showApiKey ? apiKeyValue : '••••••••'" label="API Key" variant="outlined" density="compact" readonly :type="showApiKey ? 'text' : 'password'" style="max-width: 320px" />
              <v-btn variant="text" size="small" :icon="showApiKey ? 'mdi-eye-off' : 'mdi-eye'" @click="revealApiKey" />
              <v-btn variant="text" size="small" icon="mdi-content-copy" @click="copyApiKey" />
            </div>
          </v-card-text>
        </v-card>

        <!-- IP Allowlist -->
        <v-card elevation="0" border rounded="lg">
          <v-card-title class="d-flex align-center">
            <v-icon class="mr-2">mdi-ip-network</v-icon>
            IP 白名单
          </v-card-title>
          <v-divider />
          <v-card-text>
            <v-switch v-model="ipAllowlistEnabled" label="启用 IP 白名单" color="primary" density="compact" hide-details class="mb-3" @update:model-value="toggleAllowlist" />
            <v-textarea v-model="ipList" label="IP 列表（每行一个）" variant="outlined" density="compact" rows="4" class="mb-2" />
            <v-btn size="small" variant="tonal" @click="saveAllowlist" :loading="savingAllowlist">保存</v-btn>
          </v-card-text>
        </v-card>
      </v-col>
    </v-row>

    <!-- API Key Reveal Dialog -->
    <v-dialog v-model="showRevealDialog" max-width="400">
      <v-card border>
        <v-card-title>验证身份</v-card-title>
        <v-card-text>
          <div class="text-body-2 text-medium-emphasis mb-3">请输入当前密码以查看 API Key</div>
          <v-text-field v-model="revealPassword" label="当前密码" variant="outlined" density="compact" type="password" autofocus @keydown.enter="doRevealApiKey" :rules="[required('密码')]" />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showRevealDialog = false">取消</v-btn>
          <v-btn color="primary" variant="flat" @click="doRevealApiKey" :loading="revealingKey">确认</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- TOTP Disable Dialog -->
    <v-dialog v-model="showDisableTotp" max-width="400">
      <v-card border>
        <v-card-title>禁用 TOTP</v-card-title>
        <v-card-text>
          <v-text-field v-model="disableTotpPassword" label="当前密码" variant="outlined" density="compact" type="password" class="mb-2" :rules="[required()]" />
          <v-text-field v-model="disableTotpCode" label="验证码" variant="outlined" density="compact" :rules="[required()]" />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showDisableTotp = false">取消</v-btn>
          <v-btn color="error" variant="flat" @click="doDisableTotp" :loading="disablingTotp">禁用</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-container>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { http } from '@/api'
import { useAuthStore } from '@/stores/auth'
import { useSnackbar } from '@/composables/useSnackbar'
import { required, numberRange, isNumber, matchOther } from '@/utils/validation'
import TerminalQuickCommandsSettings from '@/components/TerminalQuickCommandsSettings.vue'
import type { SettingsResponse, AllowlistResponse, SettingItem } from '@/types/api'

const snackbar = useSnackbar()

const auth = useAuthStore()

// ── Settings ──
const settingsLoading = ref(false)
const settings = ref({
  system_name: '', system_title: '',
  cpu_alert_threshold: 80, mem_alert_threshold: 80, disk_alert_threshold: 80,
  db_pool_size: 10, db_max_overflow: 20,
  telegram_bot_token: '', telegram_chat_id: '',
})
const saving = ref(false)
const testingTg = ref(false)
const showToken = ref(false)

// ── Password ──
const pwForm = ref({ current: '', new_pw: '', confirm: '', totp_code: '' })
const changingPw = ref(false)

// ── TOTP ──
const totpQr = ref('')
const totpSecret = ref('')
const totpCode = ref('')
const enablingTotp = ref(false)
const showDisableTotp = ref(false)
const disableTotpPassword = ref('')
const disableTotpCode = ref('')
const disablingTotp = ref(false)

// ── API Key ──
const showApiKey = ref(false)
const apiKeyValue = ref('')
const showRevealDialog = ref(false)
const revealPassword = ref('')
const revealingKey = ref(false)

// ── IP Allowlist ──
const ipAllowlistEnabled = ref(false)
const ipList = ref('')
const savingAllowlist = ref(false)

// ── Data loading ──
async function loadSettings() {
  settingsLoading.value = true
  try {
    const res = await http.get<SettingsResponse>('/settings/')
    const items: SettingItem[] = Array.isArray(res) ? res : []
    const knownKeys = Object.keys(settings.value)
    for (const item of items) {
      const key = item.key
      if (key && knownKeys.includes(key)) {
        const val = item.value
        // Type-cast numeric strings back to numbers for number inputs
        if (typeof val === 'string' && /^\d+(\.\d+)?$/.test(val)) {
          (settings.value as Record<string, unknown>)[key] = Number(val)
        } else {
          (settings.value as Record<string, unknown>)[key] = val
        }
      }
    }
  } catch {
    snackbar('加载设置失败', 'error')
  } finally {
    settingsLoading.value = false
  }
}

async function loadAllowlist() {
  try {
    const res = await http.get<AllowlistResponse>('/settings/ip-allowlist')
    ipAllowlistEnabled.value = res.enabled || false
    ipList.value = ([...(res.manual_ips || []), ...(res.subscription_ips || [])]).join('\n')
  } catch {
    snackbar('加载白名单失败', 'error')
  }
}

// ── Actions ──
async function saveSettings() {
  saving.value = true
  try {
    const entries = Object.entries(settings.value).filter(([key]) =>
      ['system_name', 'system_title', 'cpu_alert_threshold', 'mem_alert_threshold', 'disk_alert_threshold', 'db_pool_size', 'db_max_overflow', 'telegram_bot_token', 'telegram_chat_id'].includes(key)
    )
    for (const [key, value] of entries) {
      await http.put(`/settings/${key}`, { value })
    }
    snackbar('设置已保存')
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '保存失败'
    snackbar(msg, 'error')
  } finally { saving.value = false }
}

async function testTelegram() {
  testingTg.value = true
  try {
    await http.post('/settings/telegram/test')
    snackbar('测试消息已发送')
  } catch (e: any) { snackbar(e.message || '发送失败', 'error') }
  finally { testingTg.value = false }
}

async function changePassword() {
  if (pwForm.value.new_pw !== pwForm.value.confirm) {
    snackbar('两次密码不一致', 'error')
    return
  }
  changingPw.value = true
  try {
    const body: Record<string, string> = {
      current_password: pwForm.value.current,
      new_password: pwForm.value.new_pw,
    }
    if (auth.admin?.totp_enabled && pwForm.value.totp_code) {
      body.totp_code = pwForm.value.totp_code
    }
    await http.put('/auth/password', body)
    pwForm.value = { current: '', new_pw: '', confirm: '', totp_code: '' }
    snackbar('密码已修改')
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '修改失败'
    snackbar(msg, 'error')
  } finally { changingPw.value = false }
}

async function setupTotp() {
  try {
    const res = await http.post<{ qr_code: string; secret?: string }>('/auth/totp/setup')
    totpQr.value = res.qr_code
    totpSecret.value = res.secret || ''
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '生成失败'
    snackbar(msg, 'error')
  }
}

async function enableTotp() {
  enablingTotp.value = true
  try {
    await http.post('/auth/totp/enable', { code: totpCode.value })
    await auth.fetchProfile()
    totpQr.value = ''
    totpCode.value = ''
    snackbar('TOTP 已启用')
  } catch (e: any) { snackbar(e.message || '启用失败', 'error') }
  finally { enablingTotp.value = false }
}

function disableTotp() {
  showDisableTotp.value = true
}

async function doDisableTotp() {
  disablingTotp.value = true
  try {
    await http.post('/auth/totp/disable', {
      admin_id: auth.admin?.id,
      current_password: disableTotpPassword.value,
      totp_code: disableTotpCode.value,
    })
    await auth.fetchProfile()
    showDisableTotp.value = false
    disableTotpPassword.value = ''
    disableTotpCode.value = ''
    snackbar('TOTP 已禁用')
  } catch (e: any) { snackbar(e.message || '禁用失败', 'error') }
  finally { disablingTotp.value = false }
}

function copyTotpSecret() {
  if (totpSecret.value) {
    navigator.clipboard.writeText(totpSecret.value)
    snackbar('密钥已复制')
  }
}

async function revealApiKey() {
  if (showApiKey.value) { showApiKey.value = false; return }
  showRevealDialog.value = true
  revealPassword.value = ''
}

async function doRevealApiKey() {
  if (!revealPassword.value) {
    snackbar('请输入密码', 'error')
    return
  }
  revealingKey.value = true
  try {
    const res = await http.post<{ api_key: string }>('/settings/api-key/reveal', { current_password: revealPassword.value })
    apiKeyValue.value = res.api_key
    showApiKey.value = true
    showRevealDialog.value = false
    revealPassword.value = ''
  } catch (e: any) { snackbar(e.message || '验证失败', 'error') }
  finally { revealingKey.value = false }
}

function copyApiKey() {
  if (apiKeyValue.value) {
    navigator.clipboard.writeText(apiKeyValue.value)
    snackbar('已复制到剪贴板')
  }
}

async function toggleAllowlist() {
  try {
    await http.post('/settings/ip-allowlist/toggle', { enabled: ipAllowlistEnabled.value })
  } catch (e: any) { snackbar(e.message || '操作失败', 'error') }
}

async function saveAllowlist() {
  savingAllowlist.value = true
  try {
    const ips = ipList.value.split('\n').map(s => s.trim()).filter(Boolean)
    await http.post('/settings/ip-allowlist', { ips })
    snackbar('白名单已保存')
  } catch (e: any) { snackbar(e.message || '保存失败', 'error') }
  finally { savingAllowlist.value = false }
}


onMounted(() => {
  loadSettings()
  loadAllowlist()
  auth.fetchProfile()
})
</script>
