<template>
  <div class="profile-page">
    <div class="profile-screen">
      <section class="card profile-card">
        <div class="top-row">
          <label class="avatar-wrap" :aria-label="t('profile.changeAvatar')">
            <input
              type="file"
              accept="image/*"
              class="avatar-input"
              @change="onAvatarFileChange"
            />
            <div class="avatar">
              <v-progress-circular
                v-if="avatarUploading"
                indeterminate
                size="32"
                width="2"
                class="avatar-loading"
              />
              <template v-else>
                <img v-if="avatarImage" :src="avatarImage" :alt="displayName" class="avatar-img" />
                <span v-else>{{ avatarText }}</span>
                <span class="avatar-overlay">
                  <v-icon size="18">mdi-camera</v-icon>
                </span>
              </template>
            </div>
          </label>
          <div class="info-col">
            <div class="name-text">{{ displayName }}</div>
            <div class="acc-text">{{ t('profile.uidLabel', { uid: userIdText }) }}</div>
            <div class="tag-text">{{ userTag }}</div>
          </div>
          <button class="edit-btn" type="button" @click="onEditProfile">{{ t('profile.edit') }}</button>
        </div>
      </section>

      <section class="card wallet-card">
        <div class="wallet-head">
          <span class="wallet-title">{{ t('profile.walletOverview') }}</span>
          <button class="wallet-link" type="button" @click="goWallet">{{ t('profile.walletDetail') }} &gt;</button>
        </div>
        <div class="wallet-balance">${{ totalBalance }}</div>
        <div class="wallet-sub">
          {{ t('profile.walletSub', { available: availableBalance, frozen: frozenBalance }) }}
        </div>
      </section>

      <section class="card menu-card">
        <div class="menu-title">{{ t('profile.accountSettings') }}</div>
        <button v-for="item in settingItems" :key="item.label" class="menu-item" type="button" @click="goSetting(item)">
          <span>{{ item.label }}</span>
          <span v-if="item.action === 'locale'" class="menu-locale">{{ currentLocaleLabel }}</span>
          <span v-else-if="item.action === 'wallet'" class="menu-locale">{{ walletAddressShort }}</span>
          <span v-else class="menu-arrow">&gt;</span>
        </button>
      </section>

      <button class="logout-btn" type="button" :disabled="logoutLoading" @click="logout">
        {{ t('common.logout') }}
      </button>
    </div>

    <v-dialog v-model="localeDialogOpen" max-width="360">
      <v-card class="locale-dialog-card" rounded="xl" elevation="0">
        <div class="locale-dialog-title">{{ t('profile.selectLanguage') }}</div>
        <button
          v-for="opt in localeStore.localeOptions"
          :key="opt.value"
          class="locale-option"
          type="button"
          @click="chooseLocale(opt.value)"
        >
          <span>{{ opt.label }}</span>
          <span v-if="opt.value === localeStore.currentLocale" class="locale-selected">✓</span>
        </button>
      </v-card>
    </v-dialog>

    <v-dialog v-model="walletDialogOpen" max-width="420">
      <v-card class="wallet-dialog-card" rounded="xl" elevation="0">
        <div class="wallet-dialog-title">{{ t('profile.currentWalletAddress') }}</div>
        <div class="wallet-dialog-address">{{ walletAddressText }}</div>
        <div class="wallet-dialog-actions">
          <button class="wallet-copy-btn" type="button" :disabled="!walletAddress" @click="copyWalletAddress">
            {{ t('profile.copyAddress') }}
          </button>
        </div>
      </v-card>
    </v-dialog>

    <v-dialog v-model="editNameDialogOpen" max-width="420">
      <v-card class="name-dialog-card" rounded="xl" elevation="0">
        <div class="name-dialog-title">{{ t('profile.editNameTitle') }}</div>
        <v-text-field
          v-model="editingName"
          :label="t('profile.newUserName')"
          variant="outlined"
          density="comfortable"
          hide-details="auto"
          :error-messages="nameError ? [nameError] : []"
          :hint="t('profile.nameFormatHint')"
          persistent-hint
        />
        <div class="name-dialog-actions">
          <button class="name-dialog-cancel-btn" type="button" :disabled="isSaving" @click="closeEditNameDialog">
            {{ t('profile.cancel') }}
          </button>
          <button class="name-dialog-save-btn" type="button" :disabled="isSaving" @click="saveName">
            <v-progress-circular
              v-if="isSaving"
              indeterminate
              size="18"
              width="2"
              class="save-btn-spinner"
            />
            <span v-else>{{ t('profile.save') }}</span>
          </button>
        </div>
      </v-card>
    </v-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useLocaleStore } from '../stores/locale'
import { useToastStore } from '../stores/toast'
import { useUserStore, type UserInfo } from '../stores/user'
import { setSelfUsername, setSelfHeaderImg } from '@/api/user'
import { upload } from '@/api/fileUpload'
import type { LocaleCode } from '@/plugins/i18n'

interface SettingItem {
  label: string
  route?: string
  action?: 'locale' | 'wallet'
}

const router = useRouter()
const { t } = useI18n()
const localeStore = useLocaleStore()
const userStore = useUserStore()
const toastStore = useToastStore()
const localeDialogOpen = ref(false)
const walletDialogOpen = ref(false)
const logoutLoading = ref(false)
const editNameDialogOpen = ref(false)
const editingName = ref('')
const nameError = ref<string | null>(null)
const isSaving = ref(false)
const avatarUploading = ref(false)

const currentLocaleLabel = computed(() => {
  return (
    localeStore.localeOptions.find((opt) => opt.value === localeStore.currentLocale)?.label ??
    String(localeStore.currentLocale)
  )
})

function readStringFromUser(keys: string[]): string {
  const user = userStore.user as Record<string, unknown> | null
  if (!user) return ''
  for (const key of keys) {
    const value = user[key]
    if (typeof value === 'string' && value.trim()) return value.trim()
  }
  return ''
}

const walletAddress = computed(() => {
  const user = userStore.user as Record<string, unknown> | null
  if (!user) return ''
  const candidateKeys = ['walletAddress', 'address', 'wallet', 'walletAddr', 'ethAddress']
  for (const key of candidateKeys) {
    const value = user[key]
    if (typeof value === 'string' && value.trim()) return value.trim()
  }
  return ''
})

const walletAddressText = computed(() => walletAddress.value || t('profile.walletAddressUnavailable'))
const walletAddressShort = computed(() => {
  const value = walletAddress.value
  if (!value) return t('profile.unbound')
  if (value.length <= 14) return value
  return `${value.slice(0, 6)}...${value.slice(-4)}`
})

const rawUser = computed(() => (userStore.user ?? {}) as Record<string, unknown>)
const userNameRaw = computed(() => {
  const v = rawUser.value.userName
  return typeof v === 'string' && v.trim() ? v.trim() : ''
})
const displayName = computed(() => userNameRaw.value || t('profile.defaultName'))
const userIdText = computed(() => {
  const uid = rawUser.value.id ?? rawUser.value.ID
  if (uid == null || uid === '') return '--'
  return String(uid)
})
const avatarImage = computed(() => userStore.avatarUrl || '')
const avatarText = computed(() => {
  const first = displayName.value.trim().charAt(0)
  return first ? first.toUpperCase() : 'U'
})
const hasVip = computed(() => {
  const user = rawUser.value
  const candidates = [user.isVip, user.vip, user.vipLevel, user.memberLevel]
  return candidates.some((v) => {
    if (typeof v === 'boolean') return v
    if (typeof v === 'number') return v > 0
    if (typeof v === 'string') return v.trim() === '1' || v.trim().toLowerCase() === 'vip'
    return false
  })
})
const userTag = computed(() => (hasVip.value ? t('profile.vipTrader') : t('profile.trader')))
const totalBalance = computed(() => userStore.balance || '0.00')
const availableBalance = computed(() => {
  const val = readStringFromUser(['availableBalance', 'available', 'walletAvailable'])
  return val || totalBalance.value
})
const frozenBalance = computed(() => {
  return readStringFromUser(['frozenBalance', 'frozen', 'walletFrozen']) || '0.00'
})
const settingItems = computed<SettingItem[]>(() => [
  { label: t('profile.walletManage'), action: 'wallet' },
  { label: t('profile.apiKeyManage'), route: '/api-key' },
  { label: t('profile.language'), action: 'locale' },
])

function goSetting(item: SettingItem) {
  if (item.action === 'wallet') {
    walletDialogOpen.value = true
    return
  }
  if (item.action === 'locale') {
    localeDialogOpen.value = true
    return
  }
  if (!item.route) return
  router.push(item.route)
}

function chooseLocale(locale: LocaleCode) {
  localeStore.setLocale(locale)
  localeDialogOpen.value = false
}

async function copyWalletAddress() {
  if (!walletAddress.value) return
  try {
    await navigator.clipboard.writeText(walletAddress.value)
    walletDialogOpen.value = false
    toastStore.show(t('profile.copySuccess'))
  } catch {
    toastStore.show(t('profile.copyFailed'), 'error')
  }
}

function onEditProfile() {
  editNameDialogOpen.value = true
  editingName.value = userNameRaw.value
  nameError.value = null
}

function goWallet() {
  router.push('/wallet')
}

function validateUserName(name: string): string | null {
  const v = name.trim()
  if (!v) return t('profile.nameRequired')
  if (v.length < MIN_USER_NAME_LEN) return t('profile.nameTooShort', { min: MIN_USER_NAME_LEN })
  if (v.length > MAX_USER_NAME_LEN) return t('profile.nameTooLong', { max: MAX_USER_NAME_LEN })
  const allowedRe = /^[a-z0-9_]+$/i
  if (!allowedRe.test(v)) return t('profile.nameInvalidFormat')
  return null
}

function closeEditNameDialog() {
  if (isSaving.value) return
  editNameDialogOpen.value = false
  nameError.value = null
}

async function saveName() {
  if (isSaving.value) return
  const err = validateUserName(editingName.value)
  if (err) {
    nameError.value = err
    return
  }

  const trimmed = editingName.value.trim()
  const token = userStore.token
  const u = userStore.user as UserInfo | null
  if (!token || !u) {
    toastStore.show(t('error.pleaseLogin'), 'error')
    return
  }

  isSaving.value = true
  nameError.value = null
  try {
    const authHeaders = userStore.getAuthHeaders()
    if (!authHeaders) {
      toastStore.show(t('error.pleaseLogin'), 'error')
      return
    }

    const res = await setSelfUsername(authHeaders, { username: trimmed })
    if (res.code !== 0 && res.code !== 200) {
      const errMsg = res.msg || t('profile.nameSaveFailed')
      nameError.value = errMsg
      toastStore.show(errMsg, 'error')
      return
    }

    // 接口成功后刷新用户信息，确保 userName/headerImg 等字段一致
    await userStore.fetchUserInfo()
    toastStore.show(t('profile.nameSaved'))
    editNameDialogOpen.value = false
  } catch (e) {
    const errMsg = e instanceof Error ? e.message : t('profile.nameSaveFailed')
    nameError.value = errMsg
    toastStore.show(errMsg, 'error')
  } finally {
    isSaving.value = false
  }
}

async function onAvatarFileChange(e: Event) {
  const input = e.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file || !file.type.startsWith('image/')) return
  if (!userStore.isLoggedIn) {
    toastStore.show(t('error.pleaseLogin'), 'error')
    return
  }
  const authHeaders = userStore.getAuthHeaders()
  if (!authHeaders) {
    toastStore.show(t('error.pleaseLogin'), 'error')
    return
  }
  avatarUploading.value = true
  try {
    const uploadRes = await upload(file, authHeaders)
    const fileUrl = uploadRes.data?.file?.url
    if (!fileUrl || (uploadRes.code !== 0 && uploadRes.code !== 200)) {
      toastStore.show(uploadRes.msg || t('profile.avatarUploadFailed'), 'error')
      return
    }
    const setRes = await setSelfHeaderImg(authHeaders, { headerImg: fileUrl })
    if (setRes.code !== 0 && setRes.code !== 200) {
      toastStore.show(setRes.msg || t('profile.avatarUploadFailed'), 'error')
      return
    }
    await userStore.fetchUserInfo()
    toastStore.show(t('profile.avatarUploadSuccess'))
  } catch (err) {
    const msg = err instanceof Error ? err.message : t('profile.avatarUploadFailed')
    toastStore.show(msg, 'error')
  } finally {
    avatarUploading.value = false
    input.value = ''
  }
}

const MIN_USER_NAME_LEN = 2
const MAX_USER_NAME_LEN = 20

async function logout() {
  if (logoutLoading.value) return
  logoutLoading.value = true
  try {
    await userStore.logout()
    router.push('/login')
  } catch {
    toastStore.show(t('error.requestFailed'), 'error')
  } finally {
    logoutLoading.value = false
  }
}

onMounted(() => {
  if (!userStore.isLoggedIn) return
  userStore.fetchUserInfo()
  userStore.fetchUsdcBalance()
})
</script>

<style scoped>
.profile-page {
  min-height: 100vh;
  background: #ffffff;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 0;
}

.profile-screen {
  width: 100%;
  max-width: 100%;
  min-height: 0;
  background: #fcfcfc;
  font-family: Inter, sans-serif;
  padding: 16px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  box-sizing: border-box;
}

.card {
  width: 100%;
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 16px;
  box-sizing: border-box;
}

.profile-card {
  padding: 20px;
}

.top-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.avatar-wrap {
  cursor: pointer;
  display: block;
  flex-shrink: 0;
}

.avatar-input {
  position: absolute;
  width: 0.1px;
  height: 0.1px;
  opacity: 0;
  overflow: hidden;
  z-index: -1;
}

.avatar {
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: #5b5bd6;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: 700;
  flex-shrink: 0;
  overflow: hidden;
  position: relative;
}

.avatar-loading {
  color: #ffffff !important;
}

.avatar-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  opacity: 0;
  transition: opacity 0.2s;
}

.avatar-wrap:hover .avatar-overlay {
  opacity: 1;
}

.avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.info-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.name-text {
  color: #111827;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.acc-text {
  color: #6b7280;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.2;
}

.tag-text {
  color: #5b5bd6;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
}

.edit-btn {
  height: 34px;
  padding: 0 12px;
  border-radius: 12px;
  border: 1px solid #e5e7eb;
  background: #fcfcfc;
  color: #111827;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.wallet-card {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.wallet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.wallet-title {
  color: #111827;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
}

.wallet-link {
  border: 0;
  background: transparent;
  color: #5b5bd6;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}

.wallet-balance {
  color: #111827;
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
}

.wallet-sub {
  color: #6b7280;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.2;
}

.wallet-actions {
  display: flex;
  gap: 10px;
}

.action-btn {
  flex: 1;
  height: 40px;
  border-radius: 12px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.action-primary {
  border: 0;
  background: #5b5bd6;
  color: #ffffff;
}

.action-secondary {
  border: 1px solid #e5e7eb;
  background: #fcfcfc;
  color: #111827;
}

.menu-card {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.menu-title {
  color: #111827;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
}

.menu-item {
  height: 44px;
  padding: 0 4px;
  border: 0;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #111827;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}

.menu-arrow {
  color: #9ca3af;
  font-size: 14px;
  font-weight: 600;
}

.menu-locale {
  color: #6b7280;
  font-size: 13px;
  font-weight: 600;
}

.logout-btn {
  width: 100%;
  height: 48px;
  border: 0;
  border-radius: 12px;
  background: #fee2e2;
  color: #dc2626;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.logout-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.locale-dialog-card {
  border: 1px solid #e5e7eb;
  background: #ffffff;
  padding: 8px;
}

.locale-dialog-title {
  padding: 10px 10px 6px;
  color: #111827;
  font-size: 14px;
  font-weight: 700;
}

.locale-option {
  width: 100%;
  height: 42px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  padding: 0 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #111827;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}

.locale-option:hover {
  background: #f9fafb;
}

.locale-selected {
  color: #5b5bd6;
  font-weight: 700;
}

.wallet-dialog-card {
  border: 1px solid #e5e7eb;
  background: #ffffff;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.wallet-dialog-title {
  color: #111827;
  font-size: 15px;
  font-weight: 700;
}

.wallet-dialog-address {
  border-radius: 10px;
  border: 1px solid #e5e7eb;
  background: #fcfcfc;
  padding: 12px;
  color: #111827;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.wallet-dialog-actions {
  display: flex;
  justify-content: flex-end;
}

.wallet-copy-btn {
  height: 34px;
  border-radius: 10px;
  border: 0;
  padding: 0 14px;
  background: #5b5bd6;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.wallet-copy-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.name-dialog-card {
  border: 1px solid #e5e7eb;
  background: #ffffff;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.name-dialog-title {
  color: #111827;
  font-size: 15px;
  font-weight: 700;
  padding: 2px 2px 0;
}

.name-dialog-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding-top: 2px;
}

.name-dialog-cancel-btn {
  height: 34px;
  border-radius: 10px;
  border: 1px solid #e5e7eb;
  background: #fcfcfc;
  color: #111827;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0 14px;
}

.name-dialog-cancel-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.name-dialog-save-btn {
  height: 34px;
  min-width: 72px;
  border-radius: 10px;
  border: 0;
  background: #5b5bd6;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.name-dialog-save-btn:disabled {
  opacity: 0.8;
  cursor: not-allowed;
}

.save-btn-spinner {
  color: #ffffff;
}
</style>
