<template>
  <div class="container mx-auto p-4 max-w-2xl min-w-0">
    <h1 class="text-2xl font-bold mb-6">Profile</h1>

    <!-- User info card -->
    <div class="card card-app card-bg-base-200 mb-6 transition-all duration-200">
      <div class="card-body">
        <template v-if="initialLoad">
          <div class="flex items-center gap-4">
            <Skeleton class="size-14 rounded-full shrink-0" />
            <div class="flex flex-col gap-2">
              <Skeleton class="h-6 w-32" />
              <Skeleton class="h-4 w-48" />
            </div>
          </div>
        </template>
        <template v-else-if="me">
          <div class="flex flex-wrap items-center gap-4">
            <div class="avatar">
              <div class="rounded-full w-14 h-14 overflow-hidden flex items-center justify-center">
                <img
                  v-if="me.email && !gravatarError"
                  :src="useGravatarUrl(me.email, 80)"
                  alt=""
                  class="w-full h-full object-cover"
                  @error="gravatarError = true"
                >
                <div
                  v-else
                  class="bg-primary text-primary-content rounded-full w-14 h-14 flex items-center justify-center"
                >
                  <span class="text-2xl font-semibold">{{ (me.username || '?')[0].toUpperCase() }}</span>
                </div>
              </div>
            </div>
            <div class="flex flex-col gap-1">
              <h2 class="text-lg font-semibold">{{ me.username }}</h2>
              <div class="flex flex-wrap gap-1.5">
                <span
                  v-for="auth in (me.auths ?? [])"
                  :key="auth"
                  class="badge badge-sm badge-outline"
                >
                  {{ auth }}
                </span>
                <span v-if="!me.auths?.length" class="text-sm text-base-content/60">No roles</span>
              </div>
              <p class="text-sm text-base-content/80 mt-1">
                Email: {{ me.email || 'Not set' }}
              </p>
              <div v-if="!emailEditing" class="flex items-center gap-2 mt-1">
                <button
                  type="button"
                  class="btn btn-ghost btn-xs"
                  @click="startEditEmail"
                >
                  {{ me.email ? 'Edit' : 'Set' }} email
                </button>
              </div>
              <form v-else class="flex flex-wrap items-center gap-2 mt-2" @submit.prevent="saveEmail">
                <input
                  v-model="emailEdit"
                  type="email"
                  placeholder="email@example.com"
                  class="input input-bordered input-sm w-full max-w-xs"
                  autocomplete="email"
                >
                <button type="submit" class="btn btn-primary btn-sm" :disabled="loadingEmail">
                  {{ loadingEmail ? '…' : 'Save' }}
                </button>
                <button type="button" class="btn btn-ghost btn-sm" :disabled="loadingEmail" @click="cancelEditEmail">
                  Cancel
                </button>
                <p v-if="emailError" class="text-error text-sm w-full">{{ emailError }}</p>
              </form>
            </div>
          </div>
        </template>
      </div>
    </div>

    <!-- Upload tokens -->
    <div class="card card-app card-bg-base-200 mb-6 transition-all duration-200">
      <div class="card-body">
        <template v-if="initialLoad">
          <Skeleton class="h-6 w-32 mb-2" />
          <Skeleton class="h-4 w-full mb-4" />
          <Skeleton class="h-8 w-full mb-2" />
          <Skeleton class="h-9 w-36 mt-2" />
        </template>
        <template v-else>
          <h2 class="card-title gap-2">
            <icons-icon-key />
            Upload tokens
          </h2>
          <p class="text-sm opacity-80">Tokens for upload API. Generate and copy as needed.</p>
          <ul v-if="tokens?.length" class="list-none mt-2 space-y-2">
            <li
              v-for="(t, idx) in tokens"
              :key="t"
              class="font-mono text-sm flex flex-wrap items-center gap-2 p-2 rounded-lg bg-base-300/50"
            >
              <span class="break-all flex-1 min-w-0">{{ uploadTokenDisplay(t) }}</span>
              <span class="text-xs text-base-content/60 shrink-0">Token {{ idx + 1 }}</span>
              <button
                type="button"
                class="btn btn-ghost btn-xs shrink-0 gap-1 min-h-9 min-w-[4rem] touch-manipulation"
                aria-label="Copy token"
                :class="copiedToken === t ? 'btn-success' : ''"
                @click="copyToken(t)"
              >
                <template v-if="copiedToken === t">Copied!</template>
                <template v-else>Copy</template>
              </button>
            </li>
          </ul>
          <p v-else class="text-sm mt-2">No tokens yet.</p>
          <p v-if="tokenError" class="text-error text-sm mt-2">{{ tokenError }}</p>
          <button class="btn btn-primary btn-sm mt-2 min-h-11 touch-manipulation" :disabled="loadingTokens" @click="generateToken">
            {{ loadingTokens ? '…' : 'Generate token' }}
          </button>
        </template>
      </div>
    </div>

    <div class="card card-app card-bg-base-200 mb-6 transition-all duration-200">
      <div class="card-body">
        <h2 class="card-title gap-2">
          <icons-icon-settings />
          Change password
        </h2>
        <form @submit.prevent="changePass" class="flex flex-col gap-2">
          <PasswordInput
            v-model="newPass"
            placeholder="New password"
            autocomplete="new-password"
          />
          <p v-if="passMsg" class="text-sm" :class="passOk ? 'text-success' : 'text-error'">{{ passMsg }}</p>
          <button type="submit" class="btn btn-sm min-h-11 touch-manipulation" :disabled="loadingPass">Save password</button>
        </form>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { MeResponse } from '~/types/api'

const api = useMapApi()
const toast = useToast()
const initialLoad = ref(true)
const me = useState<MeResponse | null>('me', () => null)
const tokens = ref<string[]>([])
const uploadPrefix = ref('')
const newPass = ref('')
const loadingTokens = ref(false)
const loadingPass = ref(false)
const passMsg = ref('')
const passOk = ref(false)
const tokenError = ref('')
const copiedToken = ref<string | null>(null)
const gravatarError = ref(false)
const emailEditing = ref(false)
const emailEdit = ref('')
const loadingEmail = ref(false)
const emailError = ref('')
let copiedTimeout: ReturnType<typeof setTimeout> | null = null

function startEditEmail() {
  emailError.value = ''
  emailEdit.value = me.value?.email ?? ''
  emailEditing.value = true
}

function cancelEditEmail() {
  emailEditing.value = false
  emailError.value = ''
}

async function saveEmail() {
  emailError.value = ''
  loadingEmail.value = true
  try {
    await api.meUpdate({ email: emailEdit.value.trim() || undefined })
    const data = await api.me()
    me.value = data
    emailEditing.value = false
    gravatarError.value = false
    toast.success('Email updated')
  } catch (e: unknown) {
    emailError.value = e instanceof Error ? e.message : 'Failed to update email'
  } finally {
    loadingEmail.value = false
  }
}

function uploadTokenDisplay(token: string): string {
  const base = (uploadPrefix.value ?? '').replace(/\/+$/, '')
  return base ? `${base}/client/${token}` : `client/${token}`
}

async function copyToken(token: string) {
  const text = uploadTokenDisplay(token)
  try {
    await navigator.clipboard.writeText(text)
    copiedToken.value = token
    toast.success('Copied to clipboard', 2000)
    if (copiedTimeout) clearTimeout(copiedTimeout)
    copiedTimeout = setTimeout(() => {
      copiedToken.value = null
    }, 2000)
  } catch {
    toast.error('Failed to copy')
  }
}

onMounted(async () => {
  try {
    const data = await api.me()
    me.value = data
    tokens.value = data.tokens ?? []
    uploadPrefix.value = data.prefix ?? ''
  } catch {
    me.value = null
    tokens.value = []
    uploadPrefix.value = ''
  } finally {
    initialLoad.value = false
  }
})

async function generateToken() {
  tokenError.value = ''
  loadingTokens.value = true
  try {
    await api.meTokens()
    const data = await api.me()
    me.value = data
    tokens.value = data.tokens ?? []
    uploadPrefix.value = data.prefix ?? ''
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : ''
    tokenError.value = msg === 'Forbidden'
      ? 'You need "upload" permission to generate tokens. Ask an admin to add it to your account.'
      : (msg || 'Failed to generate token')
  } finally {
    loadingTokens.value = false
  }
}

async function changePass() {
  passMsg.value = ''
  loadingPass.value = true
  try {
    await api.mePassword(newPass.value)
    passMsg.value = 'Password updated.'
    passOk.value = true
    newPass.value = ''
  } catch (e: unknown) {
    passMsg.value = e instanceof Error ? e.message : 'Failed'
    passOk.value = false
  } finally {
    loadingPass.value = false
  }
}
</script>
