<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'
import api from '@/api/client'
import PageHeader from '@/components/PageHeader.vue'
import AppCard from '@/components/AppCard.vue'
import { useLocaleStore } from '@/stores/locale'
import { isLocaleCode } from '@/i18n/types'

interface GeoFile {
  name: string
  exists: boolean
  size: number
  url: string
}

interface APIKeyItem {
  id: number
  name: string
  key_prefix: string
  enabled: boolean
  last_used_at?: string
  created_at: string
}

const { t } = useI18n()
const localeStore = useLocaleStore()

const form = ref<Record<string, string>>({})
const loading = ref(false)
const saving = ref(false)
const geoLoading = ref(false)
const geoUpdating = ref(false)
const geoReady = ref(false)
const geoFiles = ref<GeoFile[]>([])
const apiKeys = ref<APIKeyItem[]>([])
const apiKeysLoading = ref(false)
const creatingKey = ref(false)
const keyDialogVisible = ref(false)
const newKeyName = ref('')
const createdKey = ref('')

const localeOptions = computed(() =>
  localeStore.options.map((opt) => ({
    value: opt.value,
    label: t(opt.labelKey),
  })),
)

function formatTime(value?: string) {
  if (!value) return t('apiKey.neverUsed')
  return value.replace('T', ' ').slice(0, 19)
}

function formatBytes(n: number) {
  if (!n) return t('common.none')
  if (n < 1024) return `${n} B`
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`
  return `${(n / 1024 / 1024).toFixed(2)} MB`
}

async function loadAPIKeys() {
  apiKeysLoading.value = true
  try {
    const { data } = await api.get('/api-keys')
    apiKeys.value = data.items || []
  } finally {
    apiKeysLoading.value = false
  }
}

async function loadGeo() {
  geoLoading.value = true
  try {
    const { data } = await api.get('/system/geo')
    geoReady.value = !!data.ready
    geoFiles.value = data.files || []
  } finally {
    geoLoading.value = false
  }
}

async function load() {
  loading.value = true
  try {
    const { data } = await api.get('/settings')
    form.value = data
    localeStore.applyFromSettings(data.ui_locale)
  } finally {
    loading.value = false
  }
  void loadGeo()
  void loadAPIKeys()
}

function onLocaleChange(value: string) {
  if (isLocaleCode(value)) {
    localeStore.setLocale(value)
  }
}

async function save() {
  saving.value = true
  try {
    await api.put('/settings', form.value)
    if (form.value.ui_locale && isLocaleCode(form.value.ui_locale)) {
      localeStore.setLocale(form.value.ui_locale)
    }
    ElMessage.success(t('settings.saved'))
    await loadGeo()
  } finally {
    saving.value = false
  }
}

async function reloadEngine() {
  await api.post('/system/reload')
  ElMessage.success(t('settings.engineReloaded'))
}

async function updateGeo(force = false) {
  geoUpdating.value = true
  try {
    const { data } = await api.post('/system/geo/update', { force })
    geoReady.value = !!data.ready
    geoFiles.value = data.files || []
    const updated: string[] = data.updated || []
    if (updated.length) {
      ElMessage.success(t('geo.updated', { files: updated.join('、') }))
    } else {
      ElMessage.success(t('geo.upToDate'))
    }
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } }
    ElMessage.error(err.response?.data?.error || t('geo.updateFailed'))
  } finally {
    geoUpdating.value = false
  }
}

function openCreateKey() {
  newKeyName.value = ''
  createdKey.value = ''
  keyDialogVisible.value = true
}

async function createAPIKey() {
  creatingKey.value = true
  try {
    const { data } = await api.post('/api-keys', {
      name: newKeyName.value.trim() || 'default',
    })
    createdKey.value = data.key
    ElMessage.success(t('apiKey.created'))
    await loadAPIKeys()
  } finally {
    creatingKey.value = false
  }
}

async function copyCreatedKey() {
  if (!createdKey.value) return
  await navigator.clipboard.writeText(createdKey.value)
  ElMessage.success(t('apiKey.copied'))
}

async function revokeAPIKey(row: APIKeyItem) {
  await ElMessageBox.confirm(
    t('apiKey.confirmRevoke', { name: row.name, prefix: row.key_prefix }),
    t('common.confirm'),
    { type: 'warning' },
  )
  await api.delete(`/api-keys/${row.id}`)
  ElMessage.success(t('apiKey.revoked'))
  loadAPIKeys()
}

onMounted(load)
</script>

<template>
  <div class="page">
    <PageHeader :title="t('settings.title')" :description="t('settings.desc')">
      <template #actions>
        <el-button @click="reloadEngine">{{ t('settings.reloadEngine') }}</el-button>
        <el-button type="primary" :loading="saving" @click="save">{{ t('common.save') }}</el-button>
      </template>
    </PageHeader>

    <AppCard :title="t('settings.inboundApi')" padded v-loading="loading">
      <el-form label-width="120px">
        <div class="section-title">{{ t('settings.appearance') }}</div>
        <el-form-item :label="t('settings.uiLocale')">
          <el-select v-model="form.ui_locale" class="w-full" @change="onLocaleChange">
            <el-option
              v-for="opt in localeOptions"
              :key="opt.value"
              :label="opt.label"
              :value="opt.value"
            />
          </el-select>
        </el-form-item>

        <div class="section-title">{{ t('settings.proxyInbound') }}</div>
        <el-form-item :label="t('settings.httpPort')">
          <el-input v-model="form.http_port" />
        </el-form-item>
        <el-form-item :label="t('settings.socksPort')">
          <el-input v-model="form.socks_port" />
        </el-form-item>
        <el-form-item :label="t('settings.proxyUser')">
          <el-input v-model="form.proxy_auth_user" :placeholder="t('settings.proxyUserPlaceholder')" clearable />
        </el-form-item>
        <el-form-item :label="t('settings.proxyPass')">
          <el-input
            v-model="form.proxy_auth_pass"
            type="password"
            show-password
            :placeholder="t('settings.proxyPassPlaceholder')"
          />
          <p class="form-hint">{{ t('settings.proxyAuthHint') }}</p>
        </el-form-item>

        <div class="section-title">{{ t('settings.adminApi') }}</div>
        <el-form-item :label="t('settings.apiPort')">
          <el-input v-model="form.api_port" />
          <p class="form-hint">{{ t('settings.apiPortHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('settings.mihomoApi')">
          <el-input v-model="form.mihomo_api_port" />
        </el-form-item>
        <el-form-item :label="t('settings.apiSecret')">
          <el-input v-model="form.api_secret" :placeholder="t('settings.apiSecretPlaceholder')" />
        </el-form-item>

        <div class="section-title">{{ t('settings.scheduler') }}</div>
        <el-form-item :label="t('settings.healthInterval')">
          <el-input v-model="form.health_interval_sec" />
          <p class="form-hint">{{ t('settings.seconds') }}</p>
        </el-form-item>
        <el-form-item :label="t('settings.logLevel')">
          <el-select v-model="form.log_level" class="w-full">
            <el-option label="info" value="info" />
            <el-option label="warning" value="warning" />
            <el-option label="error" value="error" />
            <el-option label="debug" value="debug" />
          </el-select>
        </el-form-item>

        <div class="section-title">{{ t('settings.security') }}</div>
        <el-form-item :label="t('settings.authEnabled')">
          <el-switch v-model="form.auth_enabled" active-value="true" inactive-value="false" />
        </el-form-item>
        <el-form-item :label="t('settings.loginMaxAttempts')">
          <el-input v-model="form.login_max_attempts" />
          <p class="form-hint">{{ t('settings.loginMaxAttemptsHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('settings.loginLockMinutes')">
          <el-input v-model="form.login_lock_minutes" />
          <p class="form-hint">{{ t('settings.loginLockMinutesHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('settings.newPassword')">
          <el-input v-model="form.admin_password" type="password" show-password :placeholder="t('settings.newPasswordPlaceholder')" />
        </el-form-item>
      </el-form>
    </AppCard>

    <AppCard v-loading="apiKeysLoading">
      <template #header>
        <div class="card-header-row">
          <h3 class="app-card__title">{{ t('settings.apiKeys') }}</h3>
          <el-button type="primary" @click="openCreateKey">{{ t('settings.applyKey') }}</el-button>
        </div>
      </template>
      <div class="card-toolbar card-toolbar--desc">
        <p class="form-hint form-hint--flush">
          {{ t('settings.apiKeysHint') }}
          <code class="inline-code">Authorization: Bearer &lt;key&gt;</code>
          <code class="inline-code">X-API-Key: &lt;key&gt;</code>
        </p>
      </div>
      <el-table :data="apiKeys" size="small" :empty-text="t('apiKey.empty')">
        <el-table-column prop="name" :label="t('common.name')" min-width="120" />
        <el-table-column prop="key_prefix" :label="t('apiKey.prefix')" min-width="140">
          <template #default="{ row }">
            <code class="inline-code">{{ row.key_prefix }}</code>
          </template>
        </el-table-column>
        <el-table-column :label="t('apiKey.lastUsed')" width="168">
          <template #default="{ row }">{{ formatTime(row.last_used_at) }}</template>
        </el-table-column>
        <el-table-column :label="t('apiKey.createdAt')" width="168">
          <template #default="{ row }">{{ formatTime(row.created_at) }}</template>
        </el-table-column>
        <el-table-column :label="t('common.actions')" width="80" fixed="right">
          <template #default="{ row }">
            <el-button size="small" type="danger" link @click="revokeAPIKey(row)">{{ t('common.revoke') }}</el-button>
          </template>
        </el-table-column>
      </el-table>
    </AppCard>

    <AppCard :title="t('geo.title')" padded v-loading="geoLoading">
      <el-form label-width="140px">
        <el-form-item :label="t('geo.autoDownload')">
          <el-switch v-model="form.geo_auto_download" active-value="true" inactive-value="false" />
          <p class="form-hint">{{ t('geo.autoDownloadHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('geo.countryMmdb')">
          <el-input v-model="form.geo_country_mmdb_url" clearable />
          <p class="form-hint">{{ t('geo.countryMmdbHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('geo.geoip')">
          <el-input v-model="form.geo_geoip_url" clearable />
          <p class="form-hint">{{ t('geo.geoipHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('geo.geosite')">
          <el-input v-model="form.geo_geosite_url" clearable />
          <p class="form-hint">{{ t('geo.geositeHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('geo.localStatus')">
          <div class="geo-status">
            <el-tag :type="geoReady ? 'success' : 'warning'" size="small">
              {{ geoReady ? t('geo.ready') : t('geo.notReady') }}
            </el-tag>
            <ul v-if="geoFiles.length" class="geo-file-list">
              <li v-for="f in geoFiles" :key="f.name">
                <span class="geo-file-name">{{ f.name }}</span>
                <span :class="f.exists ? 'geo-file-ok' : 'geo-file-miss'">
                  {{ f.exists ? formatBytes(f.size) : t('geo.missing') }}
                </span>
              </li>
            </ul>
          </div>
        </el-form-item>
        <el-form-item label=" ">
          <div class="inline-actions">
            <el-button type="primary" :loading="geoUpdating" @click="updateGeo(false)">
              {{ t('geo.downloadMissing') }}
            </el-button>
            <el-button :loading="geoUpdating" @click="updateGeo(true)">
              {{ t('geo.forceUpdate') }}
            </el-button>
          </div>
          <p class="form-hint">{{ t('geo.updateHint') }}</p>
        </el-form-item>
      </el-form>
    </AppCard>

    <el-dialog
      v-model="keyDialogVisible"
      :title="createdKey ? t('apiKey.dialogSave') : t('apiKey.dialogCreate')"
      width="520px"
      destroy-on-close
      :close-on-click-modal="!createdKey"
      :show-close="!!createdKey"
    >
      <template v-if="!createdKey">
        <el-form label-width="80px">
          <el-form-item :label="t('apiKey.name')">
            <el-input v-model="newKeyName" :placeholder="t('apiKey.namePlaceholder')" />
          </el-form-item>
        </el-form>
      </template>
      <template v-else>
        <p class="form-hint">{{ t('apiKey.onceHint') }}</p>
        <el-input :model-value="createdKey" readonly class="u-mt-4">
          <template #append>
            <el-button @click="copyCreatedKey">{{ t('common.copy') }}</el-button>
          </template>
        </el-input>
      </template>
      <template #footer>
        <el-button v-if="createdKey" type="primary" @click="keyDialogVisible = false">{{ t('common.saved') }}</el-button>
        <template v-else>
          <el-button @click="keyDialogVisible = false">{{ t('common.cancel') }}</el-button>
          <el-button type="primary" :loading="creatingKey" @click="createAPIKey">{{ t('common.create') }}</el-button>
        </template>
      </template>
    </el-dialog>
  </div>
</template>
