<template>
  <UContainer class="py-8">
    <div class="mx-auto max-w-6xl space-y-4">
      <div class="space-y-1.5">
        <UBadge label="Super Admin" color="primary" variant="soft" class="rounded-full" />
        <h1 class="text-2xl font-bold text-highlighted sm:text-3xl">
          User management
        </h1>
      </div>

      <UAlert
        v-if="issuedPasswordMessage"
        title="Temporary password issued"
        :description="issuedPasswordMessage"
        color="success"
        icon="i-lucide-key-round"
      />

      <UCard class="border border-default bg-default shadow-sm" :ui="{ body: 'p-0 sm:p-0' }">
        <template #header>
          <div class="flex flex-col gap-2.5 lg:flex-row lg:items-center lg:justify-between">
            <div class="flex flex-col gap-2 sm:flex-row sm:items-center">
              <UInput
                v-model="searchQuery"
                size="lg"
                class="w-full sm:w-72"
                placeholder="Search name, username, or phone"
              />

              <UButton
                label="Refresh"
                color="neutral"
                variant="outline"
                icon="i-lucide-refresh-cw"
                size="lg"
                :loading="loadingUsers"
                @click="refreshUsers"
              />
            </div>

            <UButton
              label="Add User"
              size="lg"
              icon="i-lucide-plus"
              class="justify-center"
              @click="openCreateModal"
            />
          </div>
        </template>

        <div class="overflow-x-auto">
          <UTable
            :data="filteredUsers"
            :columns="columns"
            :loading="loadingUsers"
            :empty="searchQuery.trim() ? 'No matching users found.' : 'No users available.'"
            sticky="header"
            caption="Users"
            class="min-w-[820px]"
          >
            <template #fullName-cell="{ row }">
              <div class="min-w-0 space-y-0.5 py-1">
                <div class="font-semibold leading-tight text-highlighted">
                  {{ row.original.fullName }}
                </div>
                <div class="text-xs text-muted">
                  @{{ row.original.username }}
                </div>
              </div>
            </template>

            <template #phoneNumber-cell="{ row }">
              <span class="text-sm" :class="row.original.phoneNumber ? 'text-default' : 'text-muted'">
                {{ row.original.phoneNumber || 'Not set' }}
              </span>
            </template>

            <template #role-cell="{ row }">
              <UBadge
                :label="row.original.role === 'super_admin' ? 'Super Admin' : 'Staff'"
                :color="row.original.role === 'super_admin' ? 'primary' : 'neutral'"
                variant="soft"
              />
            </template>

            <template #status-cell="{ row }">
              <div class="space-y-1.5 py-1">
                <div class="flex flex-wrap gap-1.5">
                  <UBadge
                    :label="row.original.mustChangePassword ? 'Password reset' : 'Password ready'"
                    :color="row.original.mustChangePassword ? 'warning' : 'success'"
                    variant="soft"
                    size="sm"
                  />
                  <UBadge
                    :label="row.original.passkeyCount > 0 ? 'Passkey ready' : 'No passkey'"
                    :color="row.original.passkeyCount > 0 ? 'success' : 'neutral'"
                    variant="soft"
                    size="sm"
                  />
                </div>

                <div class="text-xs text-muted">
                  {{ row.original.passkeyCount }} passkey{{ row.original.passkeyCount === 1 ? '' : 's' }}
                </div>
              </div>
            </template>

            <template #lastLoginAt-cell="{ row }">
              <span class="text-xs text-muted sm:text-sm">
                {{ formatDateTime(row.original.lastLoginAt, 'Never') }}
              </span>
            </template>

            <template #actions-cell="{ row }">
              <div class="flex flex-wrap justify-end gap-1.5 py-1">
                <UButton
                  label="Edit"
                  color="neutral"
                  variant="outline"
                  icon="i-lucide-pencil-line"
                  size="sm"
                  @click="openEditModal(row.original)"
                />

                <UButton
                  label="Reset Password"
                  color="neutral"
                  variant="outline"
                  icon="i-lucide-key-round"
                  size="sm"
                  :loading="resettingUserId === row.original.id"
                  @click="resetPassword(row.original)"
                />
              </div>
            </template>
          </UTable>
        </div>
      </UCard>

      <UModal
        v-model:open="editorOpen"
        :title="isEditMode ? 'Edit User' : 'Add User'"
        :dismissible="!savingUser"
        :close="!savingUser"
        :content="{ class: 'sm:max-w-xl' }"
      >
        <template #body>
          <UForm :state="userForm" :validate="validateUserForm" class="space-y-4" @submit="saveUser">
            <UFormField name="fullName" label="Display Name" required>
              <UInput v-model="userForm.fullName" size="lg" class="w-full" />
            </UFormField>

            <UFormField name="username" label="Username" required>
              <UInput
                v-model="userForm.username"
                size="lg"
                class="w-full"
                :disabled="isEditMode"
              />
            </UFormField>

            <UFormField name="phoneNumber" label="Phone Number" required>
              <UInput
                v-model="userForm.phoneNumber"
                size="lg"
                type="tel"
                class="w-full"
                placeholder="e.g. +60123456789"
              />
            </UFormField>

            <UFormField name="role" label="Role" required>
              <USelect
                v-model="userForm.role"
                size="lg"
                class="w-full"
                :items="roleOptions"
                :disabled="isEditingCurrentUser"
              />
            </UFormField>

            <div class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
              <UButton
                label="Cancel"
                color="neutral"
                variant="ghost"
                class="justify-center"
                :disabled="savingUser"
                @click="closeEditor"
              />

              <UButton
                type="submit"
                :label="isEditMode ? 'Save Changes' : 'Create User'"
                class="justify-center"
                :loading="savingUser"
              />
            </div>
          </UForm>
        </template>
      </UModal>
    </div>
  </UContainer>
</template>

<script lang="ts" setup>
import type { FormError, FormSubmitEvent } from '@nuxt/ui'

import {
  DEFAULT_PHONE_COUNTRY_CODE,
  hasValidFullName,
  isValidPhoneNumber,
  isValidUsername,
  normalizeFullName,
  normalizePhoneNumber,
  normalizeUsername,
  type ManagedUser,
  type UserRole
} from '~~/shared/auth'

import { getErrorMessage } from '../../../utils/errors'
import { formatDateTime } from '../../../utils/formatters'

definePageMeta({
  middleware: 'super-admin'
})

const toast = useToast()
const apiClient = useApiClient()
const auth = useAuth()

const users = ref<ManagedUser[]>([])
const loadingUsers = ref(false)
const savingUser = ref(false)
const resettingUserId = ref<string | null>(null)
const issuedPasswordMessage = ref('')
const searchQuery = ref('')
const editorOpen = ref(false)
const editorMode = ref<'create' | 'edit'>('create')
const editingUserId = ref<string | null>(null)

const userForm = reactive({
  fullName: '',
  username: '',
  phoneNumber: DEFAULT_PHONE_COUNTRY_CODE,
  role: 'staff' as UserRole
})

const roleOptions = [
  { label: 'Staff', value: 'staff' },
  { label: 'Super Admin', value: 'super_admin' }
]

const columns = [
  { accessorKey: 'fullName', header: 'Display Name' },
  { accessorKey: 'phoneNumber', header: 'PIC Phone' },
  { accessorKey: 'role', header: 'Role' },
  { id: 'status', header: 'Status' },
  { accessorKey: 'lastLoginAt', header: 'Last Login' },
  { id: 'actions', header: 'Actions' }
]

const isEditMode = computed(() => editorMode.value === 'edit')
const isEditingCurrentUser = computed(() => {
  return isEditMode.value && editingUserId.value === auth.user.value?.id
})

const filteredUsers = computed(() => {
  const keyword = searchQuery.value.trim().toLowerCase()

  if (!keyword) {
    return users.value
  }

  return users.value.filter((user) => {
    return [
      user.fullName,
      user.username,
      user.phoneNumber || '',
      user.role
    ].some((value) => value.toLowerCase().includes(keyword))
  })
})

await refreshUsers()

function resetUserForm() {
  userForm.fullName = ''
  userForm.username = ''
  userForm.phoneNumber = DEFAULT_PHONE_COUNTRY_CODE
  userForm.role = 'staff'
  editingUserId.value = null
}

function openCreateModal() {
  editorMode.value = 'create'
  resetUserForm()
  editorOpen.value = true
}

function openEditModal(user: ManagedUser) {
  editorMode.value = 'edit'
  editingUserId.value = user.id
  userForm.fullName = user.fullName
  userForm.username = user.username
  userForm.phoneNumber = user.phoneNumber ? normalizePhoneNumber(user.phoneNumber) : DEFAULT_PHONE_COUNTRY_CODE
  userForm.role = user.role
  editorOpen.value = true
}

function closeEditor() {
  if (savingUser.value) {
    return
  }

  editorOpen.value = false
  resetUserForm()
}

function validateUserForm(state: typeof userForm): FormError[] {
  const errors: FormError[] = []

  if (!hasValidFullName(state.fullName)) {
    errors.push({ name: 'fullName', message: 'Enter a display name with at least 2 characters.' })
  }

  if (!isEditMode.value && !isValidUsername(state.username)) {
    errors.push({ name: 'username', message: 'Use 3 to 32 lowercase letters, numbers, dot, dash, or underscore.' })
  }

  if (!isValidPhoneNumber(state.phoneNumber)) {
    errors.push({ name: 'phoneNumber', message: 'Use a valid phone number with country code, e.g. +60123456789.' })
  }

  return errors
}

async function refreshUsers() {
  if (loadingUsers.value) {
    return
  }

  loadingUsers.value = true

  try {
    const response = await apiClient<{ users: ManagedUser[] }>('/api/admin/users')
    users.value = response.users
  } catch (error: any) {
    toast.add({
      title: 'Unable to load users',
      description: getErrorMessage(error, 'The user list could not be loaded.'),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    loadingUsers.value = false
  }
}

async function saveUser(event: FormSubmitEvent<typeof userForm>) {
  event.preventDefault()

  if (savingUser.value) {
    return
  }

  savingUser.value = true

  try {
    if (isEditMode.value && editingUserId.value) {
      await apiClient(`/api/admin/users/${editingUserId.value}`, {
        method: 'PATCH',
        body: {
          fullName: normalizeFullName(userForm.fullName),
          phoneNumber: normalizePhoneNumber(userForm.phoneNumber),
          role: userForm.role
        }
      })

      if (editingUserId.value === auth.user.value?.id) {
        await auth.refreshSession()
      }

      toast.add({
        title: 'User updated',
        description: `${normalizeFullName(userForm.fullName)} has been updated.`,
        color: 'success',
        icon: 'i-lucide-check-circle-2'
      })
    } else {
      const response = await apiClient<{
        user: ManagedUser
        defaultPassword: string
      }>('/api/admin/users', {
        method: 'POST',
        body: {
          fullName: normalizeFullName(userForm.fullName),
          username: normalizeUsername(userForm.username),
          phoneNumber: normalizePhoneNumber(userForm.phoneNumber),
          role: userForm.role
        }
      })

      issuedPasswordMessage.value = `${response.user.fullName} was created with the temporary password ${response.defaultPassword}.`

      toast.add({
        title: 'User created',
        description: `${response.user.fullName} can now sign in with the temporary password.`,
        color: 'success',
        icon: 'i-lucide-check-circle-2'
      })
    }

    closeEditor()
    await refreshUsers()
  } catch (error: any) {
    toast.add({
      title: isEditMode.value ? 'Update failed' : 'User creation failed',
      description: getErrorMessage(
        error,
        isEditMode.value ? 'Unable to update this user.' : 'Unable to create the new user.'
      ),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    savingUser.value = false
  }
}

async function resetPassword(user: ManagedUser) {
  if (resettingUserId.value) {
    return
  }

  resettingUserId.value = user.id

  try {
    const response = await apiClient<{
      user: ManagedUser
      defaultPassword: string
    }>(`/api/admin/users/${user.id}/reset-password`, {
      method: 'POST'
    })

    issuedPasswordMessage.value = `${user.fullName}'s password was reset to ${response.defaultPassword}. They must change it after login.`

    toast.add({
      title: 'Password reset',
      description: `${user.fullName} now has a fresh temporary password.`,
      color: 'success',
      icon: 'i-lucide-check-circle-2'
    })

    await refreshUsers()
  } catch (error: any) {
    toast.add({
      title: 'Reset failed',
      description: getErrorMessage(error, 'Unable to reset this password.'),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    resettingUserId.value = null
  }
}
</script>
