<script setup>
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { UserRound, ImageUp, KeyRound, CloudUpload, LogIn, LogOut, RefreshCw, Wifi, WifiOff, Info, ShieldCheck, Images, Camera, X, Lock, Folder, CircleCheck, TicketCheck, Star, ListTodo, Settings as SettingsIcon, FileText, CalendarClock, UploadCloud, IdCard, Users, Plus, Check, ArrowRight, Tags, Copy, Trash2 } from 'lucide-vue-next'
import { call, isNative } from '../api'
import { useAppStore } from '../store'
import { teams, teamsErr, teamsLoading, loadTeams as loadTeamsShared, switchTeam as switchTeamShared } from '../team'
import RemoteImg from '../components/RemoteImg.vue'
import ImagePreview from '../components/ImagePreview.vue'

const store = useAppStore(), { t } = useI18n(), native = isNative()
const router = useRouter()
const form = reactive({ avatarMode: '', avatarValue: '', imageMode: 'base64' })
const pwdForm = reactive({ old: '', next: '', confirm: '' })
const busy = ref(''), msg = ref('')
const loaded = ref(false)
const avatarOpen = ref(false)
const AVATAR_HIST_KEY = 'cc-avatar-history'
const avatarHistory = ref([]) // [{mode,value,preview?}]
const serverAvatars = ref([])
const previewOpen = ref(false)
const previewSrc = ref('')
const TABS = ['info', 'teams', 'assets', 'security', 'sync']
const tab = ref(TABS.includes(localStorage.getItem('cc-profile-tab')) ? localStorage.getItem('cc-profile-tab') : 'info')
const doneTodos = ref(0)
const resolvedTickets = ref(0)
const sync = computed(() => store.syncStatus)
// ---- 全局文件存储（管理员在设置页配置；此处只读，决定素材库可用性与提示文案） ----
const fsCfg = reactive({ mode: 'local', baseUrl: '' })
const serverStorage = computed(() => fsCfg.mode === 'server')

async function loadFileStorage() {
  try {
    const c = await call('GetFileStorageConfig')
    Object.assign(fsCfg, { mode: c.mode || 'local', baseUrl: c.baseUrl || '' })
  } catch {}
}

// ---- 素材库（服务器存储的图片管理：本人 / 团队管理员 / 超管三档范围） ----
const assets = ref([])
const assetsTotal = ref(0)
const assetsPage = ref(1)
const assetsScope = ref('mine')
const assetsTeamId = ref(0)
const assetsLoading = ref(false)
const assetsErr = ref('')
// 只有我担任 owner/admin 的团队才能看团队素材
const adminTeams = computed(() => teams.value.filter(x => ['owner', 'admin'].includes(x.role)))

async function loadAssets(reset = true) {
  if (!serverStorage.value || !sync.value.loggedIn) return
  if (reset) assetsPage.value = 1
  assetsLoading.value = true; assetsErr.value = ''
  try {
    const tid = assetsScope.value === 'team' ? Number(assetsTeamId.value) : 0
    const r = await call('ListServerFiles', assetsScope.value, tid, assetsPage.value)
    assets.value = reset ? (r.items || []) : assets.value.concat(r.items || [])
    assetsTotal.value = r.total || 0
  } catch (e) {
    assetsErr.value = errText(e)
    if (reset) { assets.value = []; assetsTotal.value = 0 }
  } finally { assetsLoading.value = false }
}
function reloadAssets() { loadAssets(true) }
function moreAssets() { assetsPage.value++; loadAssets(false) }
function onAssetsScope() {
  if (assetsScope.value === 'team' && !assetsTeamId.value && adminTeams.value.length) assetsTeamId.value = adminTeams.value[0].id
  reloadAssets()
}
async function deleteAsset(f) {
  if (!confirm(t('assetsDeleteConfirm'))) return
  try {
    await call('DeleteServerFile', f.id)
    assets.value = assets.value.filter(x => x.id !== f.id)
    if (assetsTotal.value > 0) assetsTotal.value--
    store.showToast({ type: 'success', key: 'assetsDeletedToast' })
  } catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
}
async function copyAsset(f) {
  try {
    await navigator.clipboard.writeText(f.url)
    store.showToast({ type: 'success', key: 'assetsCopiedToast' })
  } catch { store.showToast({ type: 'error', key: 'assetsCopyFailed' }) }
}
function openAssetPreview(f) {
  previewSrc.value = f.url
  previewOpen.value = true
}
function fmtSize(n) {
  if (n >= 1 << 20) return (n / (1 << 20)).toFixed(1) + ' MB'
  if (n >= 1024) return Math.round(n / 1024) + ' KB'
  return (n || 0) + ' B'
}

// ---- 个人资料（昵称/头衔/邮箱/简介/技术栈标签） ----
const profile = reactive({ nickname: '', title: '', email: '', bio: '', techTags: [] })
const tagInput = ref('')
const profileMsg = ref('')

async function loadProfile() {
  try {
    const p = await call('GetMyProfile')
    Object.assign(profile, { nickname: p.nickname || '', title: p.title || '', email: p.email || '', bio: p.bio || '', techTags: p.techTags || [] })
  } catch {}
}
function addTag() {
  const v = tagInput.value.trim()
  if (!v) return
  if (!profile.techTags.some(x => x.toLowerCase() === v.toLowerCase())) profile.techTags.push(v)
  tagInput.value = ''
}
function removeTag(i) { profile.techTags.splice(i, 1) }
async function saveProfile() {
  if (busy.value) return
  busy.value = 'profile'; profileMsg.value = ''
  if (tagInput.value.trim()) addTag()
  try {
    const p = await call('SaveMyProfile', { ...profile })
    Object.assign(profile, { nickname: p.nickname, title: p.title, email: p.email, bio: p.bio, techTags: p.techTags || [] })
    store.showToast({ type: 'success', key: 'profileSavedToast' })
  } catch (e) { profileMsg.value = errText(e) }
  finally { busy.value = '' }
}

// ---- 我的团队（状态共享自 team.js，切换会联动窗口标题） ----
const newTeamName = ref('')

async function loadTeams() {
  if (!sync.value.loggedIn) return
  await loadTeamsShared()
}
async function switchTeam(tm) {
  if (tm.current) return
  try { await switchTeamShared(tm.id) } catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
}
async function createTeam() {
  const name = newTeamName.value.trim()
  if (!name || busy.value) return
  busy.value = 'team'
  try {
    await call('TeamCreate', name)
    newTeamName.value = ''
    await loadTeams()
    store.showToast({ type: 'success', key: 'teamCreatedToast' })
  } catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
  finally { busy.value = '' }
}

function setTab(v) {
  tab.value = v
  localStorage.setItem('cc-profile-tab', v)
  if (v === 'teams') loadTeams()
  // 素材库可用性跟随全局配置，进入时先刷新配置再拉列表（管理员可能刚在设置页改过）
  if (v === 'assets') { loadTeams(); loadFileStorage().then(() => reloadAssets()) }
  if (v === 'sync') loadProjSync()
}
// 按时段问候，让页面更像“我的空间”而不是后台表单
const greeting = computed(() => {
  const h = new Date().getHours()
  const key = h < 6 ? 'greetNight' : h < 11 ? 'greetMorning' : h < 14 ? 'greetNoon' : h < 18 ? 'greetAfternoon' : 'greetEvening'
  return t(key)
})
// 新密码强度：0 无 / 1 弱 / 2 中 / 3 强
const pwdStrength = computed(() => {
  const v = pwdForm.next
  if (!v) return 0
  let s = v.length >= 6 ? 1 : 0
  if (v.length >= 10) s++
  if (/[A-Za-z]/.test(v) && /[0-9]/.test(v)) s++
  if (/[^A-Za-z0-9]/.test(v)) s++
  return Math.max(1, Math.min(3, s - (v.length < 6 ? 1 : 0)))
})
const strengthLabel = computed(() => [null, 'pwdWeak', 'pwdMedium', 'pwdStrong'][pwdStrength.value])

const errText = e => {
  const code = String(e).split(':')[0].trim()
  return t('errors.' + code) !== 'errors.' + code ? t('errors.' + code) : String(e)
}
// 后端存 UTC（RFC3339），展示时转为本地时区
const localSyncTime = computed(() => {
  const s = sync.value.lastSyncAt
  if (!s) return ''
  const d = new Date(/[zZ]$|[+-]\d\d:?\d\d$/.test(s) ? s : s + 'Z')
  if (isNaN(d.getTime())) return s.replace('T', ' ')
  const p = n => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
})
const scopeTags = [
  { icon: ListTodo, key: 'todos' },
  { icon: TicketCheck, key: 'tickets' },
  { icon: SettingsIcon, key: 'settings' },
  { icon: Star, key: 'scopeFavs' },
  { icon: Folder, key: 'projects' },
  { icon: FileText, key: 'scopeDocs' }
]

async function load() {
  try {
    const saved = await call('GetSettings')
    form.avatarMode = saved.avatarMode || ''
    form.avatarValue = saved.avatarValue || ''
    form.imageMode = saved.imageMode || 'base64'
  } catch {}
  loaded.value = true
  store.refreshSyncStatus()
  try {
    const [ts, ks] = await Promise.all([call('ListTodos', 'all', 0), call('ListTickets', 'all', 0)])
    doneTodos.value = ts.filter(x => x.status === 'done').length
    resolvedTickets.value = ks.filter(x => ['resolved', 'closed'].includes(x.status)).length
  } catch {}
}
async function persist() {
  if (!loaded.value) return
  await store.saveSettings({ avatarMode: form.avatarMode, avatarValue: form.avatarValue, imageMode: form.imageMode })
}
watch(() => [form.avatarMode, form.avatarValue, form.imageMode], persist)

function loadLocalAvatarHistory() {
  try {
    const raw = JSON.parse(localStorage.getItem(AVATAR_HIST_KEY) || '[]')
    return Array.isArray(raw) ? raw.filter(x => x && x.value).slice(0, 12) : []
  } catch { return [] }
}
function saveLocalAvatarHistory(list) {
  avatarHistory.value = list.slice(0, 12)
  localStorage.setItem(AVATAR_HIST_KEY, JSON.stringify(avatarHistory.value.map(({ mode, value }) => ({ mode, value }))))
}
async function loadAvatarHistory() {
  if (sync.value.loggedIn) {
    try {
      const items = await call('ListAvatarHistory')
      avatarHistory.value = (items || []).map(x => ({ id: x.id, mode: x.mode, value: x.value, createdAt: x.createdAt }))
      // 首次：把本地残留历史迁移到线上
      const local = loadLocalAvatarHistory()
      if (local.length && !avatarHistory.value.length) {
        for (const it of [...local].reverse()) {
          try { await call('PushAvatarHistory', it.mode || 'base64', it.value) } catch { /* ignore */ }
        }
        localStorage.removeItem(AVATAR_HIST_KEY)
        const again = await call('ListAvatarHistory')
        avatarHistory.value = (again || []).map(x => ({ id: x.id, mode: x.mode, value: x.value, createdAt: x.createdAt }))
      }
      return
    } catch { /* 回退本地 */ }
  }
  avatarHistory.value = loadLocalAvatarHistory()
}
async function pushAvatarHistory(mode, value) {
  if (!value) return
  if (sync.value.loggedIn) {
    try {
      const items = await call('PushAvatarHistory', mode || 'base64', value)
      avatarHistory.value = (items || []).map(x => ({ id: x.id, mode: x.mode, value: x.value, createdAt: x.createdAt }))
      await refreshHistPreviews()
      return
    } catch { /* 回退本地 */ }
  }
  const next = [{ mode: mode || 'base64', value }, ...avatarHistory.value.filter(x => x.value !== value)]
  saveLocalAvatarHistory(next)
  await refreshHistPreviews()
}
async function resolveHistPreview(item) {
  if (item._src) return item._src
  if (item.mode === 'url' || /^https?:\/\//i.test(item.value)) {
    try {
      const { resolveImageSrc } = await import('../api')
      item._src = await resolveImageSrc(item.value)
    } catch { item._src = item.value }
  } else if (item.mode === 'path') {
    try { item._src = await call('ReadImageAsDataURL', item.value) } catch { item._src = '' }
  } else {
    item._src = item.value
  }
  return item._src
}
async function loadServerAvatars() {
  serverAvatars.value = []
  if (!serverStorage.value || !sync.value.loggedIn) return
  try {
    const r = await call('ListServerFiles', 'mine', 0, 1)
    serverAvatars.value = (r.items || []).filter(f => f.kind === 'avatar')
  } catch {}
}
const histPreviews = ref({})
async function refreshHistPreviews() {
  const map = {}
  for (const it of avatarHistory.value) {
    map[it.value] = await resolveHistPreview(it)
  }
  histPreviews.value = map
}
// 存储走向由后端按管理员全局配置实时决定（auto）：server 时上传返回 url，否则 base64。
async function pickAvatar() {
  try {
    const r = await call('PickAvatarImage', 'auto')
    if (r && r.value) {
      if (form.avatarValue) await pushAvatarHistory(form.avatarMode, form.avatarValue)
      form.avatarMode = r.mode || 'base64'
      form.avatarValue = r.value
      await pushAvatarHistory(form.avatarMode, form.avatarValue)
    }
  } catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
}
async function clearAvatar() {
  if (form.avatarValue) await pushAvatarHistory(form.avatarMode, form.avatarValue)
  form.avatarMode = ''
  form.avatarValue = ''
}
function selectHistory(item) {
  form.avatarMode = item.mode || 'base64'
  form.avatarValue = item.value
}
async function selectServerAvatar(f) {
  form.avatarMode = 'url'
  form.avatarValue = f.url
  await pushAvatarHistory('url', f.url)
}
// 打开弹窗时刷新全局配置，保证提示文案与实际走向一致
watch(avatarOpen, async v => {
  if (!v) return
  await loadFileStorage()
  await loadAvatarHistory()
  await refreshHistPreviews()
  await loadServerAvatars()
})
async function syncNow() {
  if (busy.value) return
  busy.value = 'sync'; msg.value = ''
  try {
    const st = await call('SyncNow')
    store.syncStatus = st
    store.showToast({ type: 'success', key: 'syncDoneToast', params: { pushed: st.pushed, pulled: st.pulled } })
  } catch (e) { msg.value = errText(e); store.showToast({ type: 'error', key: 'syncFailToast' }) }
  finally { busy.value = '' }
}
// ---- 项目云同步：自动/手动模式、手动拉取、认领入口与忽略恢复 ----
const projSyncMode = ref('auto')
const ignoredProjects = ref([])
const pendingCount = ref(0)

async function loadProjSync() {
  projSyncMode.value = store.settings.projectSyncMode || 'auto'
  if (!sync.value.loggedIn) { ignoredProjects.value = []; pendingCount.value = 0; return }
  try { ignoredProjects.value = (await call('ListCloudIgnoredProjects')) || [] } catch { ignoredProjects.value = [] }
  try { pendingCount.value = ((await call('ListCloudPendingProjects')) || []).length } catch { pendingCount.value = 0 }
}
async function changeProjSyncMode() {
  await store.saveSettings({ projectSyncMode: projSyncMode.value })
  store.showToast({ type: 'success', key: projSyncMode.value === 'auto' ? 'projSyncAutoToast' : 'projSyncManualToast' })
}
async function syncProjectsNow() {
  if (busy.value) return
  busy.value = 'projsync'
  try {
    const st = await call('SyncProjectsNow')
    store.syncStatus = st
    store.showToast({ type: 'success', key: 'syncDoneToast', params: { pushed: st.pushed, pulled: st.pulled } })
    await loadProjSync()
  } catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
  finally { busy.value = '' }
}
async function unignoreProject(name) {
  try {
    await call('UnignoreCloudProject', name)
    store.showToast({ type: 'success', key: 'projUnignoredToast', params: { name } })
    await loadProjSync()
  } catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
}
function openClaim() {
  store.cloudClaimOpen = true
}
// 认领弹窗关闭后刷新待认领计数
watch(() => store.cloudClaimOpen, v => { if (!v && tab.value === 'sync') loadProjSync() })
async function syncLogout() {
  await call('SyncLogout')
  store.showToast({ type: 'success', key: 'logoutToast' })
  await store.refreshSyncStatus()
}
async function changePassword() {
  if (busy.value) return
  if (pwdForm.next.length < 6) { msg.value = t('errors.SYNC_PASSWORD_TOO_SHORT'); return }
  if (pwdForm.next !== pwdForm.confirm) { msg.value = t('passwordMismatch'); return }
  busy.value = 'password'; msg.value = ''
  try {
    await call('SyncChangePassword', pwdForm.old, pwdForm.next)
    pwdForm.old = ''; pwdForm.next = ''; pwdForm.confirm = ''
    store.showToast({ type: 'success', key: 'passwordChangedToast' })
  } catch (e) { msg.value = errText(e) }
  finally { busy.value = '' }
}
function onKey(e) {
  if (e.key === 'Escape') avatarOpen.value = false
}
onMounted(async () => {
  load()
  loadProfile()
  await loadFileStorage()
  if (tab.value === 'teams') loadTeams()
  if (tab.value === 'assets') { loadTeams(); reloadAssets() }
  if (tab.value === 'sync') loadProjSync()
  addEventListener('keydown', onKey)
})
onUnmounted(() => removeEventListener('keydown', onKey))
</script>

<template><div class="page profile-page">
  <header class="page-head sticky-head"><div><h1>{{ t('profilePage') }}</h1><p>{{ t('profileSubtitle') }}</p></div></header>
  <div v-if="!native" class="preview-notice panel"><Info /><div><b>{{ t('previewModeTitle') }}</b><small>{{ t('previewModeSync') }}</small></div></div>

  <section class="profile-hero">
    <i class="hero-orb a" aria-hidden="true" /><i class="hero-orb b" aria-hidden="true" /><i class="hero-orb c" aria-hidden="true" />
    <i class="ph-grid" aria-hidden="true" />
    <div class="profile-hero-main">
      <button class="profile-avatar editable" :title="t('avatarEdit')" @click="avatarOpen = true">
        <span class="ph-ring" aria-hidden="true" />
        <span class="ph-photo">
          <img v-if="store.avatarSrc" :src="store.avatarSrc" alt="" />
          <b v-else-if="sync.username">{{ sync.username[0].toUpperCase() }}</b>
          <UserRound v-else />
        </span>
        <i v-if="sync.loggedIn" class="profile-dot" :class="sync.lastError ? 'err' : (sync.online ? 'on' : 'off')" />
        <span class="avatar-edit-mask"><Camera /></span>
      </button>
      <div class="profile-id">
        <small class="ph-greet">{{ greeting }}</small>
        <b class="ph-name">{{ profile.nickname || (sync.loggedIn ? sync.username : t('notLoggedIn')) }}</b>
        <small v-if="profile.title" class="ph-title-tag">{{ profile.title }}</small>
        <div v-if="sync.loggedIn" class="profile-badges">
          <span class="p-badge" :class="sync.online ? 'on' : 'off'"><component :is="sync.online ? Wifi : WifiOff" />{{ sync.online ? t('online') : t('offline') }}</span>
          <span v-if="sync.lastSyncAt" class="p-badge dim"><CalendarClock />{{ localSyncTime.slice(5, 16) }}</span>
          <span v-else class="p-badge dim">{{ t('neverSynced') }}</span>
          <span v-if="sync.pending > 0" class="p-badge warn"><UploadCloud />{{ t('pendingPush', { n: sync.pending }) }}</span>
        </div>
        <p v-else class="profile-guest-hint">{{ t('profileGuest') }}</p>
      </div>
      <div class="profile-hero-actions">
        <template v-if="sync.loggedIn">
          <button class="btn primary" :disabled="!!busy || sync.syncing" @click="syncNow"><RefreshCw :class="{ spin: busy === 'sync' || sync.syncing }" />{{ busy === 'sync' || sync.syncing ? t('syncingBtn') : t('syncNowBtn') }}</button>
          <button class="btn secondary ghost-btn" @click="syncLogout"><LogOut />{{ t('logoutBtn') }}</button>
        </template>
        <button v-else class="btn primary" :disabled="!native" @click="store.loginOpen = true"><LogIn />{{ t('loginOrRegister') }}</button>
      </div>
    </div>
    <p v-if="sync.lastError" class="db-message">{{ errText(sync.lastError) }}</p>
    <p v-if="msg" class="db-message">{{ msg }}</p>
    <div class="ph-stats">
      <div class="ph-stat"><span class="ph-stat-ico folder"><Folder /></span><div><b>{{ store.dashboard.projects }}</b><span>{{ t('projects') }}</span></div></div>
      <div class="ph-stat"><span class="ph-stat-ico done"><CircleCheck /></span><div><b>{{ doneTodos }}</b><span>{{ t('phDoneTodos') }}</span></div></div>
      <div class="ph-stat"><span class="ph-stat-ico ticket"><TicketCheck /></span><div><b>{{ resolvedTickets }}</b><span>{{ t('phResolvedTickets') }}</span></div></div>
      <div class="ph-stat"><span class="ph-stat-ico star"><Star /></span><div><b>{{ store.favorites.length }}</b><span>{{ t('favoriteProjects') }}</span></div></div>
    </div>
  </section>

  <div class="profile-layout">
    <nav class="profile-side" role="tablist">
      <button role="tab" :aria-selected="tab === 'info'" :class="{ active: tab === 'info' }" @click="setTab('info')"><IdCard />{{ t('profileTabInfo') }}</button>
      <button role="tab" :aria-selected="tab === 'teams'" :class="{ active: tab === 'teams' }" @click="setTab('teams')"><Users />{{ t('profileTabTeams') }}</button>
      <button role="tab" :aria-selected="tab === 'assets'" :class="{ active: tab === 'assets' }" @click="setTab('assets')"><Images />{{ t('assetsTab') }}</button>
      <button role="tab" :aria-selected="tab === 'security'" :class="{ active: tab === 'security' }" @click="setTab('security')"><ShieldCheck />{{ t('profileSecurity') }}</button>
      <button role="tab" :aria-selected="tab === 'sync'" :class="{ active: tab === 'sync' }" @click="setTab('sync')"><CloudUpload />{{ t('profileTabSync') }}</button>
    </nav>
    <div class="profile-main">

  <section v-if="tab === 'info'" class="panel profile-card">
    <header class="pc-head">
      <span class="pc-badge id"><IdCard /></span>
      <div><b>{{ t('profileTabInfo') }}</b><small>{{ t('profileInfoHint') }}</small></div>
    </header>
    <div class="pc-form">
      <label class="pc-field">
        <span>{{ t('profileNickname') }}</span>
        <div class="pc-input"><UserRound /><input v-model="profile.nickname" :placeholder="sync.username || t('profileNicknamePh')" maxlength="32" /></div>
      </label>
      <label class="pc-field">
        <span>{{ t('profileJobTitle') }}</span>
        <div class="pc-input"><IdCard /><input v-model="profile.title" :placeholder="t('profileJobTitlePh')" maxlength="48" /></div>
      </label>
      <label class="pc-field">
        <span>{{ t('profileEmail') }}</span>
        <div class="pc-input"><Info /><input v-model="profile.email" type="email" placeholder="you@example.com" maxlength="128" /></div>
      </label>
      <label class="pc-field pc-field-wide">
        <span>{{ t('profileBio') }}</span>
        <textarea v-model="profile.bio" class="pc-textarea" :placeholder="t('profileBioPh')" maxlength="300" rows="3" />
      </label>
      <div class="pc-field pc-field-wide">
        <span class="pc-tags-label"><Tags />{{ t('profileTags') }}</span>
        <div class="tag-editor">
          <span v-for="(tg, i) in profile.techTags" :key="tg" class="tech-tag">{{ tg }}<button type="button" :title="t('delete')" @click="removeTag(i)"><X /></button></span>
          <input v-model="tagInput" :placeholder="t('profileTagsPh')" maxlength="24" @keydown.enter.prevent="addTag" @keydown.188.prevent="addTag" @blur="addTag" />
        </div>
        <small class="pc-hint">{{ t('profileTagsHint') }}</small>
      </div>
    </div>
    <p v-if="profileMsg" class="db-message">{{ profileMsg }}</p>
    <div class="pc-actions">
      <button class="btn primary" :disabled="!!busy" @click="saveProfile"><Check />{{ busy === 'profile' ? t('saving') : t('profileSaveBtn') }}</button>
    </div>
  </section>

  <section v-else-if="tab === 'teams'" class="panel profile-card">
    <header class="pc-head">
      <span class="pc-badge team"><Users /></span>
      <div><b>{{ t('profileTabTeams') }}</b><small>{{ t('profileTeamsHint') }}</small></div>
    </header>
    <div v-if="!sync.loggedIn" class="pc-empty">
      <span class="pc-empty-ico"><Users /></span>
      <p>{{ t('teamLoginHint') }}</p>
      <button class="btn primary" :disabled="!native" @click="store.loginOpen = true"><LogIn />{{ t('loginOrRegister') }}</button>
    </div>
    <template v-else>
      <p v-if="teamsErr" class="db-message">{{ errText(teamsErr) }}</p>
      <p v-if="teamsLoading" class="pc-hint"><RefreshCw class="spin" /> {{ t('loading') }}</p>
      <div v-else-if="teams.length" class="team-pick-list">
        <button v-for="tm in teams" :key="tm.id" class="team-pick" :class="{ current: tm.current }" @click="switchTeam(tm)">
          <span class="team-pick-badge">{{ tm.name[0] }}</span>
          <span class="team-pick-main"><b>{{ tm.name }}</b><small>{{ t('teamRole_' + tm.role) }} · {{ t('teamMembersCount', { n: tm.members }) }}</small></span>
          <Check v-if="tm.current" class="team-pick-check" />
        </button>
      </div>
      <p v-else-if="!teamsErr" class="pc-hint">{{ t('teamNoneHint') }}</p>
      <div class="team-create-row">
        <input v-model="newTeamName" :placeholder="t('teamNamePh')" maxlength="64" @keyup.enter="createTeam" />
        <button class="btn secondary" :disabled="!newTeamName.trim() || !!busy" @click="createTeam"><Plus />{{ t('teamCreateBtn') }}</button>
      </div>
      <div class="pc-actions">
        <button class="btn secondary" @click="router.push('/team')">{{ t('teamGoHome') }}<ArrowRight /></button>
      </div>
    </template>
  </section>

  <section v-else-if="tab === 'assets'" class="panel profile-card">
    <header class="pc-head">
      <span class="pc-badge img"><Images /></span>
      <div><b>{{ t('assetsTab') }}</b><small>{{ sync.userId === 1 ? t('assetsHintAdmin') : t('assetsHint') }}</small></div>
    </header>
    <div v-if="!sync.loggedIn" class="pc-empty">
      <span class="pc-empty-ico"><Images /></span>
      <p>{{ t('syncLoginHint') }}</p>
      <button class="btn primary" :disabled="!native" @click="store.loginOpen = true"><LogIn />{{ t('loginOrRegister') }}</button>
    </div>
    <div v-else-if="!serverStorage" class="pc-empty">
      <span class="pc-empty-ico"><Images /></span>
      <p>{{ t('assetsNeedServer') }}</p>
    </div>
    <template v-else>
      <div class="assets-bar">
        <select v-model="assetsScope" class="fs-select slim" @change="onAssetsScope">
          <option value="mine">{{ t('assetsScopeMine') }}</option>
          <option v-if="adminTeams.length" value="team">{{ t('assetsScopeTeam') }}</option>
          <option v-if="sync.userId === 1" value="all">{{ t('assetsScopeAll') }}</option>
        </select>
        <select v-if="assetsScope === 'team'" v-model.number="assetsTeamId" class="fs-select slim" @change="reloadAssets">
          <option v-for="tm in adminTeams" :key="tm.id" :value="tm.id">{{ tm.name }}</option>
        </select>
        <span class="assets-count">{{ t('assetsCount', { n: assetsTotal }) }}</span>
        <button class="btn secondary" :disabled="assetsLoading" @click="reloadAssets"><RefreshCw :class="{ spin: assetsLoading }" />{{ t('assetsRefresh') }}</button>
      </div>
      <p v-if="assetsErr" class="db-message">{{ assetsErr }}</p>
      <div v-if="assets.length" class="assets-grid">
        <figure v-for="f in assets" :key="f.id" class="asset-card">
          <button type="button" class="asset-thumb" @click="openAssetPreview(f)"><RemoteImg :src="f.url" /></button>
          <figcaption>
            <b :title="f.original || f.name">{{ f.kind === 'avatar' ? t('assetsKindAvatar') : t('assetsKindContent') }} · {{ fmtSize(f.size) }}</b>
            <small v-if="assetsScope !== 'mine'">{{ f.username || ('#' + f.userId) }}</small>
            <small>{{ (f.createdAt || '').slice(0, 10) }}</small>
          </figcaption>
          <span class="asset-ops">
            <button type="button" :title="t('assetsCopy')" @click="copyAsset(f)"><Copy /></button>
            <button type="button" class="danger" :title="t('delete')" @click="deleteAsset(f)"><Trash2 /></button>
          </span>
        </figure>
      </div>
      <p v-else-if="!assetsLoading && !assetsErr" class="pc-hint">{{ t('assetsEmpty') }}</p>
      <div v-if="assets.length && assets.length < assetsTotal" class="pc-actions assets-more">
        <button class="btn secondary" :disabled="assetsLoading" @click="moreAssets">{{ assetsLoading ? t('loading') : t('assetsLoadMore') }}</button>
      </div>
    </template>
  </section>

  <section v-else-if="tab === 'security'" class="panel profile-card">
    <header class="pc-head">
      <span class="pc-badge shield"><ShieldCheck /></span>
      <div><b>{{ t('changePasswordBtn') }}</b><small>{{ t('changePasswordHint') }}</small></div>
    </header>
    <template v-if="sync.loggedIn">
      <div class="pc-form">
        <label class="pc-field">
          <span>{{ t('oldPasswordLabel') }}</span>
          <div class="pc-input"><Lock /><input v-model="pwdForm.old" type="password" autocomplete="current-password" /></div>
        </label>
        <label class="pc-field">
          <span>{{ t('newPasswordLabel') }}</span>
          <div class="pc-input"><KeyRound /><input v-model="pwdForm.next" type="password" :placeholder="t('passwordPh')" autocomplete="new-password" /></div>
          <div v-if="pwdForm.next" class="pc-strength" :data-level="pwdStrength">
            <i /><i /><i />
            <em>{{ t(strengthLabel) }}</em>
          </div>
        </label>
        <label class="pc-field">
          <span>{{ t('confirmPasswordLabel') }}</span>
          <div class="pc-input" :class="{ err: pwdForm.confirm && pwdForm.confirm !== pwdForm.next }"><KeyRound /><input v-model="pwdForm.confirm" type="password" autocomplete="new-password" @keyup.enter="changePassword" /></div>
        </label>
      </div>
      <div class="pc-actions">
        <button class="btn primary" :disabled="!native || !!busy || !pwdForm.old || !pwdForm.next" @click="changePassword"><KeyRound />{{ busy === 'password' ? t('changingPassword') : t('changePasswordBtn') }}</button>
      </div>
    </template>
    <div v-else class="pc-empty">
      <span class="pc-empty-ico"><UserRound /></span>
      <p>{{ t('syncLoginHint') }}</p>
      <button class="btn primary" :disabled="!native" @click="store.loginOpen = true"><LogIn />{{ t('loginOrRegister') }}</button>
    </div>
  </section>

  <section v-else class="panel profile-card">
    <header class="pc-head">
      <span class="pc-badge cloud"><CloudUpload /></span>
      <div><b>{{ t('profileTabSync') }}</b><small>{{ t('profileSyncHint') }}</small></div>
    </header>
    <div class="pc-stats">
      <div class="pc-stat"><span class="pc-stat-ico user"><UserRound /></span><div><span>{{ t('accountLabel') }}</span><b>{{ sync.loggedIn ? sync.username : t('notLoggedIn') }}</b></div></div>
      <div class="pc-stat"><span class="pc-stat-ico" :class="sync.online ? 'net-on' : 'net-off'"><component :is="sync.online ? Wifi : WifiOff" /></span><div><span>{{ t('connectionState') }}</span><b :class="sync.online ? 'ok' : 'warn'">{{ sync.online ? t('online') : t('offline') }}</b></div></div>
      <div class="pc-stat"><span class="pc-stat-ico time"><CalendarClock /></span><div><span>{{ t('lastSyncLabel') }}</span><b>{{ localSyncTime || t('neverSynced') }}</b></div></div>
      <div class="pc-stat"><span class="pc-stat-ico push" :class="{ warn: sync.pending > 0 }"><UploadCloud /></span><div><span>{{ t('pendingLabel') }}</span><b :class="{ warn: sync.pending > 0 }">{{ sync.pending || 0 }}</b></div></div>
    </div>
    <div class="pc-scope">
      <small>{{ t('syncScope') }}</small>
      <div class="pc-scope-tags">
        <span v-for="s in scopeTags" :key="s.key" class="pc-tag"><component :is="s.icon" />{{ t(s.key) }}</span>
      </div>
    </div>
    <template v-if="sync.loggedIn">
      <div class="proj-sync">
        <header class="proj-sync-head">
          <b><Folder />{{ t('projSyncTitle') }}</b>
          <small>{{ t('projSyncHint') }}</small>
        </header>
        <div class="proj-sync-row">
          <label class="proj-sync-mode">
            <span>{{ t('projSyncModeLabel') }}</span>
            <select v-model="projSyncMode" @change="changeProjSyncMode">
              <option value="auto">{{ t('projSyncModeAuto') }}</option>
              <option value="manual">{{ t('projSyncModeManual') }}</option>
            </select>
          </label>
          <button class="btn secondary" :disabled="!!busy" @click="syncProjectsNow">
            <RefreshCw :class="{ spin: busy === 'projsync' }" />{{ busy === 'projsync' ? t('syncingBtn') : t('projSyncNowBtn') }}
          </button>
          <button v-if="pendingCount" class="btn primary" @click="openClaim">
            <CloudUpload />{{ t('projClaimBtn', { n: pendingCount }) }}
          </button>
        </div>
        <div v-if="ignoredProjects.length" class="proj-ignored">
          <small>{{ t('projIgnoredTitle') }}</small>
          <div class="proj-ignored-list">
            <span v-for="n in ignoredProjects" :key="n" class="proj-ignored-item">
              {{ n }}<button type="button" :title="t('projUnignoreBtn')" @click="unignoreProject(n)"><X /></button>
            </span>
          </div>
        </div>
      </div>
    </template>
  </section>

    </div>
  </div>

  <Teleport to="body">
    <div v-if="avatarOpen" class="overlay" @click.self="avatarOpen = false">
      <section class="modal avatar-modal" @click.stop>
        <header>
          <h2><Images class="panel-icon" />{{ t('avatarModalTitle') }}</h2>
          <button type="button" @click="avatarOpen = false"><X /></button>
        </header>
        <div class="avatar-modal-body">
          <div class="avatar-row">
            <span class="avatar-preview"><img v-if="store.avatarSrc" :src="store.avatarSrc" alt="" /><UserRound v-else /></span>
            <div class="avatar-controls">
              <div class="sync-actions">
                <button class="btn secondary" :disabled="!native" @click="pickAvatar"><ImageUp />{{ t('avatarPick') }}</button>
                <button v-if="form.avatarValue" class="btn secondary" @click="clearAvatar"><X />{{ t('avatarClear') }}</button>
              </div>
            </div>
          </div>
          <p class="auto-update-hint">{{ t('storageFollowHint', { mode: serverStorage ? t('fsModeServer') : t('fsModeLocal') }) }}</p>
          <div v-if="avatarHistory.length" class="avatar-hist">
            <b>{{ t('avatarHistory') }}</b>
            <div class="avatar-hist-grid">
              <button v-for="it in avatarHistory" :key="it.value" type="button" class="avatar-hist-item" :class="{ on: form.avatarValue === it.value }" :title="t('avatarReselect')" @click="selectHistory(it)">
                <img v-if="histPreviews[it.value]" :src="histPreviews[it.value]" alt="" />
                <UserRound v-else />
              </button>
            </div>
          </div>
          <div v-if="serverAvatars.length" class="avatar-hist">
            <b>{{ t('avatarServerHistory') }}</b>
            <div class="avatar-hist-grid">
              <button v-for="f in serverAvatars" :key="f.id" type="button" class="avatar-hist-item" :class="{ on: form.avatarValue === f.url }" :title="t('avatarReselect')" @click="selectServerAvatar(f)">
                <RemoteImg :src="f.url" />
              </button>
            </div>
          </div>
        </div>
      </section>
    </div>
  </Teleport>
  <ImagePreview :open="previewOpen" :src="previewSrc" @close="previewOpen = false" />
</div></template>
