<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import dayjs from 'dayjs'
import debounce from 'lodash/debounce'
import { Search, HatGlasses, SquarePen, Trash2, Eye, Shield, RotateCcw } from '@lucide/vue'
import { Badge } from '@/components/ui/badge'
import { Box } from '@/components/ui/box'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import {
  AccordionRoot,
  AccordionItem,
  AccordionTrigger,
  AccordionContent,
} from '@/components/ui/accordion'
import { CheckboxRoot, CheckboxControl, CheckboxLabel } from '@/components/ui/checkbox'
import { DialogRoot, DialogContent, DialogCloseTrigger } from '@/components/ui/dialog'
import { Lucide } from '@/components/ui/lucide'
import DataTable from '@/components/ui/usage/DataTable.vue'
import type { TableHeader } from '@/components/ui/usage/DataTable.vue'
import { usePermissions } from '@/composables/usePermissions'
import { EMPLOYERS } from '@/constants/employers'
import { getApiErrorMessage } from '@/core/utils/getApiErrorMessage'
import { listRoles } from '@/modules/role/services/role.service'
import type { RoleListItem } from '@/modules/role/types/role.types'
import { useImpersonate } from '../composables/useImpersonate'
import { useDeletedUserList } from '../composables/useDeletedUserList'
import { useUserList } from '../composables/useUserList'
import {
  assignUserRoles as assignUserRolesService,
  deleteUser as deleteUserService,
  restoreUser as restoreUserService,
} from '../services/user.service'
import type { UserRole, UserListItem } from '../types/user.types'
import { AlertRoot, AlertTitle, AlertDescription } from '@/components/ui/alert'
import type { BadgeVariants } from '@/components/ui/styles/badge.styles'

type StatusFilterChip = {
  label: string
  value: string
  variant: BadgeVariants['variant']
}

const STATUS_FILTER_CHIPS: StatusFilterChip[] = [
  { label: 'Semua', value: '', variant: 'ghost' },
  { label: 'Aktif', value: 'active', variant: 'success' },
  { label: 'Tidak Aktif', value: 'inactive', variant: 'danger' },
  { label: 'Menunggu', value: 'pending', variant: 'pending' },
]

function getEmployerShortLabel(name: string): string {
  const match = name.match(/\(([^)]+)\)/)
  if (match?.[1]) return match[1]
  if (name.startsWith('Pusat Perubatan An-Nisa')) return "Pusat Perubatan An-Nisa'"
  if (name.startsWith('Kel Infra')) return 'Kel Infra'
  return name
}

const UNIT_FILTER_CHIPS = [
  { label: 'Semua', value: '' },
  ...EMPLOYERS.map((employer) => ({
    label: getEmployerShortLabel(employer.name),
    value: employer.name,
  })),
]

const router = useRouter()
const { hasPermission } = usePermissions()

const deleteConfirmationOpen = ref(false)
const userToDelete = ref<UserListItem | null>(null)
const deleting = ref(false)
const deleteError = ref<string | null>(null)

const assignRolesOpen = ref(false)
const userToAssignRoles = ref<UserListItem | null>(null)
const availableRoles = ref<RoleListItem[]>([])
const selectedRoleIds = ref<Set<string>>(new Set())
const loadingRoles = ref(false)
const savingRoles = ref(false)
const assignRolesError = ref<string | null>(null)

const restoreConfirmationOpen = ref(false)
const userToRestore = ref<UserListItem | null>(null)
const restoring = ref(false)
const restoreError = ref<string | null>(null)

function goToEditUser(userId: string) {
  router.push({ name: 'edit-user', params: { id: userId } })
}

function goToCreateUser() {
  router.push({ name: 'create-user' })
}

function goToViewUser(userId: string) {
  router.push({ name: 'view-user', params: { id: userId } })
}

function formatUserRoles(roles: UserRole[] | undefined): string {
  return roles?.map((role) => role.name).join(', ') || '-'
}

type QuickDatePreset = {
  label: string
  getRange: () => { from: string; to: string }
}

function formatDateInput(value: dayjs.Dayjs) {
  return value.format('YYYY-MM-DD')
}

const QUICK_DATE_PRESETS: QuickDatePreset[] = [
  {
    label: 'Bulan ini',
    getRange: () => ({
      from: formatDateInput(dayjs().startOf('month')),
      to: formatDateInput(dayjs().endOf('month')),
    }),
  },
  {
    label: 'Bulan lepas',
    getRange: () => {
      const prev = dayjs().subtract(1, 'month')
      return {
        from: formatDateInput(prev.startOf('month')),
        to: formatDateInput(prev.endOf('month')),
      }
    },
  },
  {
    label: 'Tahun ini',
    getRange: () => ({
      from: formatDateInput(dayjs().startOf('year')),
      to: formatDateInput(dayjs().endOf('year')),
    }),
  },
]

function applyJoinDatePreset(preset: QuickDatePreset) {
  const { from, to } = preset.getRange()
  joinDateFrom.value = from
  joinDateTo.value = to
}

function applyLeaveDatePreset(preset: QuickDatePreset) {
  const { from, to } = preset.getRange()
  leaveDateFrom.value = from
  leaveDateTo.value = to
}

function getUserCompanyName(
  item: Pick<UserListItem, 'company_name' | 'employments'>,
): string {
  if (item.company_name) return item.company_name
  const employments = item.employments ?? []
  const current = employments.find((employment) => employment.is_current)
  return (current ?? employments[0])?.company_name ?? '-'
}

const totalUsersLabel = computed(() => {
  const value = stats.value.total || pagination.value.total
  return value.toLocaleString()
})

const joinedThisMonthCountLabel = computed(() => stats.value.joined_this_month.toLocaleString())

function statusBadgeVariant(status: string) {
  if (status === 'active') return 'success'
  if (status === 'inactive') return 'danger'
  return 'pending'
}

function isStatusFilterActive(value: string) {
  return statusFilter.value === value
}

function setStatusFilter(value: string) {
  statusFilter.value = value
}

function isUnitFilterActive(value: string) {
  return unitFilter.value === value
}

function setUnitFilter(value: string) {
  unitFilter.value = value
}

function formatDeletedAt(value: string | null | undefined): string {
  if (!value) return '-'
  return dayjs(value).format('DD MMM YYYY, HH:mm')
}

function formatUserDate(value: string | null | undefined): string {
  if (!value) return '-'
  return dayjs(value).format('DD MMM YYYY')
}

function openDeleteConfirmation(user: UserListItem) {
  userToDelete.value = user
  deleteError.value = null
  deleteConfirmationOpen.value = true
}

async function confirmDelete() {
  if (!userToDelete.value || deleting.value) {
    return
  }

  deleting.value = true
  deleteError.value = null

  try {
    await deleteUserService(userToDelete.value.id)
    deleteConfirmationOpen.value = false
    userToDelete.value = null
    await Promise.all([fetchUsers(page.value), fetchDeletedUsers(deletedPage.value)])
  } catch (err) {
    deleteError.value = getApiErrorMessage(err, 'Gagal mengpadam akaun pengguna.')
  } finally {
    deleting.value = false
  }
}

async function loadAvailableRoles() {
  if (availableRoles.value.length) {
    return
  }

  loadingRoles.value = true
  assignRolesError.value = null

  try {
    const response = await listRoles()
    availableRoles.value = response.data.filter((role) => role.guard_name === 'api')
  } catch (err) {
    assignRolesError.value = getApiErrorMessage(err, 'Gagal memuatkan senarai peranan.')
    availableRoles.value = []
  } finally {
    loadingRoles.value = false
  }
}

async function openAssignRolesDialog(user: UserListItem) {
  userToAssignRoles.value = user
  selectedRoleIds.value = new Set(user.roles?.map((role) => role.id) ?? [])
  assignRolesError.value = null
  assignRolesOpen.value = true
  await loadAvailableRoles()
}

function setRoleChecked(roleId: string, checked: boolean) {
  const next = new Set(selectedRoleIds.value)
  if (checked) {
    next.add(roleId)
  } else {
    next.delete(roleId)
  }
  selectedRoleIds.value = next
}

async function confirmAssignRoles() {
  if (!userToAssignRoles.value || savingRoles.value) {
    return
  }

  if (!selectedRoleIds.value.size) {
    assignRolesError.value = 'Sila pilih sekurang-kurangnya satu peranan.'
    return
  }

  savingRoles.value = true
  assignRolesError.value = null

  try {
    await assignUserRolesService(
      userToAssignRoles.value.id,
      Array.from(selectedRoleIds.value),
    )
    assignRolesOpen.value = false
    userToAssignRoles.value = null
    await fetchUsers(page.value)
  } catch (err) {
    assignRolesError.value = getApiErrorMessage(err, 'Gagal menetapkan peranan pengguna.')
  } finally {
    savingRoles.value = false
  }
}

function openRestoreConfirmation(user: UserListItem) {
  userToRestore.value = user
  restoreError.value = null
  restoreConfirmationOpen.value = true
}

async function confirmRestore() {
  if (!userToRestore.value || restoring.value) {
    return
  }

  restoring.value = true
  restoreError.value = null

  try {
    await restoreUserService(userToRestore.value.id)
    restoreConfirmationOpen.value = false
    userToRestore.value = null
    await Promise.all([fetchUsers(page.value), fetchDeletedUsers(deletedPage.value)])
  } catch (err) {
    restoreError.value = getApiErrorMessage(err, 'Gagal memulihkan akaun pengguna.')
  } finally {
    restoring.value = false
  }
}

const headers: TableHeader[] = [
  { title: 'Bil.', key: '#', sortable: false },
  { title: 'Name', key: 'name', sortable: true },
  { title: 'Jenis Anggota', key: 'member_type', sortable: true },
  {
    title: 'Unit',
    key: 'company_name',
    sortable: false,
    exportValue: (item) => getUserCompanyName(item),
  },
  { title: 'Jawatan', key: 'position', sortable: true },
  { title: 'No. Anggota', key: 'member_number', sortable: true, align: 'center' },
  {
    title: 'Tarikh Menjadi Anggota',
    key: 'join_date',
    sortable: true,
    exportValue: (item) => formatUserDate(item.join_date),
  },
  {
    title: 'Tarikh Berhenti',
    key: 'leave_date',
    sortable: true,
    exportValue: (item) => formatUserDate(item.leave_date),
  },
  {
    title: 'Peranan',
    key: 'roles',
    sortable: false,
    exportValue: (item) => formatUserRoles(item.roles),
  },
  { title: 'Status', key: 'status', sortable: true },
  { title: 'Tindakan', key: 'actions', sortable: false },
]

// deleted users table headers
const deletedHeaders: TableHeader[] = [
  { title: 'Bil.', key: '#', sortable: false },
  { title: 'Name', key: 'name', sortable: true },
  {
    title: 'Unit',
    key: 'company_name',
    sortable: false,
    exportValue: (item) => getUserCompanyName(item),
  },
  { title: 'Jawatan', key: 'position', sortable: true },
  { title: 'No. Anggota', key: 'member_number', sortable: true, align: 'center' },
  {
    title: 'Peranan',
    key: 'roles',
    sortable: false,
    exportValue: (item) => formatUserRoles(item.roles),
  },
  { title: 'Status', key: 'status', sortable: true },
  { title: 'Dipadam Pada', key: 'deleted_at', sortable: true },
  { title: 'Tindakan', key: 'actions', sortable: false },
]

const {
  users,
  loading,
  stats,
  statsLoading,
  statsError,
  error,
  search,
  statusFilter,
  unitFilter,
  joinDateFrom,
  joinDateTo,
  leaveDateFrom,
  leaveDateTo,
  hasJoinDateFilters,
  hasLeaveDateFilters,
  clearJoinDateFilters,
  clearLeaveDateFilters,
  sortBy,
  page,
  itemsPerPage,
  pagination,
  handleSortUpdate,
  fetchUsers,
} = useUserList()

const {
  users: deletedUsers,
  loading: deletedLoading,
  error: deletedError,
  search: deletedSearch,
  statusFilter: deletedStatusFilter,
  sortBy: deletedSortBy,
  page: deletedPage,
  itemsPerPage: deletedItemsPerPage,
  pagination: deletedPagination,
  handleSortUpdate: handleDeletedSortUpdate,
  fetchUsers: fetchDeletedUsers,
} = useDeletedUserList({ autoWatchFilters: false, autoFetchOnMount: false })

const debouncedDeletedFetch = debounce(() => {
  fetchDeletedUsers(1)
}, 400)

watch([search, statusFilter], () => {
  deletedSearch.value = search.value
  deletedStatusFilter.value = statusFilter.value
  debouncedDeletedFetch()
})

const {
  showImpersonateButton,
  canImpersonateUser,
  impersonateButtonTitle,
  impersonating,
  loading: impersonateLoading,
  refreshImpersonationStatus,
  impersonateUser,
} = useImpersonate()

onMounted(() => {
  refreshImpersonationStatus()
  deletedSearch.value = search.value
  deletedStatusFilter.value = statusFilter.value
  fetchDeletedUsers(1)
})
</script>

<template>
  <div class="w-full space-y-6">
    <div>
      <h2 class="text-lg font-medium">Senarai Daftar Anggota</h2>
      <p class="mt-1 text-sm opacity-70">Urus dan semak anggota koperasi.</p>
    </div>

    <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
      <Box class="p-5">
        <div class="flex items-start justify-between gap-4">
          <div>
            <div class="text-sm font-medium opacity-70">Jumlah Anggota</div>
            <div class="mt-2 text-3xl font-semibold tabular-nums">{{ totalUsersLabel }}</div>
            <div class="mt-1 text-xs opacity-60">Mengikut carian & penapis semasa</div>
          </div>
          <div class="flex size-10 items-center justify-center rounded-xl bg-primary/10 text-primary">
            <Lucide icon="Users" class="size-5" />
          </div>
        </div>
      </Box>

      <Box class="p-5">
        <div class="flex items-start justify-between gap-4">
          <div>
            <div class="text-sm font-medium opacity-70">Baru Sertai</div>
            <div class="mt-2 text-3xl font-semibold tabular-nums">{{ joinedThisMonthCountLabel }}</div>
            <div class="mt-1 text-xs opacity-60">Bulan ini (semua rekod)</div>
            <div v-if="statsError" class="mt-1 text-xs text-danger">{{ statsError }}</div>
          </div>
          <div class="flex size-10 items-center justify-center rounded-xl bg-primary/10 text-primary">
            <Lucide icon="UserPlus" class="size-5" />
          </div>
        </div>
      </Box>
    </div>

    <AlertRoot v-if="error" class="mt-6" variant="danger">
      <AlertTitle>Error</AlertTitle>
      <AlertDescription>{{ error }}</AlertDescription>
    </AlertRoot>

    <AccordionRoot class="w-full" variant="boxed">
      <AccordionItem raised="single" value="date-filters">
        <AccordionTrigger>Penapis Tarikh</AccordionTrigger>
        <AccordionContent>
          <div class="flex flex-col gap-3">
            <div class="rounded-lg border border-foreground/10 p-3">
              <div class="flex flex-wrap items-end gap-3">
                <div class="flex min-w-[16rem] flex-1 flex-col gap-1.5">
                  <span class="text-sm font-medium">Tarikh Menjadi Anggota</span>
                  <div class="flex flex-wrap items-center gap-2">
                    <span class="text-sm opacity-70">Pantas:</span>
                    <Badge v-for="preset in QUICK_DATE_PRESETS" :key="`join-${preset.label}`" variant="ghost"
                      look="outline" role="button" tabindex="0" @click="applyJoinDatePreset(preset)"
                      @keydown.enter="applyJoinDatePreset(preset)">
                      {{ preset.label }}
                    </Badge>
                  </div>
                  <div class="flex items-center gap-2">
                    <Input v-model="joinDateFrom" type="date" aria-label="Tarikh menjadi anggota dari" />
                    <span class="text-sm opacity-50">–</span>
                    <Input v-model="joinDateTo" type="date" aria-label="Tarikh menjadi anggota hingga" />
                  </div>
                </div>
                <Button v-if="hasJoinDateFilters" type="button" variant="ghost" look="outline"
                  @click="clearJoinDateFilters">
                  Reset
                </Button>
              </div>
            </div>
            <div class="rounded-lg border border-foreground/10 p-3">
              <div class="flex flex-wrap items-end gap-3">
                <div class="flex min-w-[16rem] flex-1 flex-col gap-1.5">
                  <span class="text-sm font-medium">Tarikh Berhenti</span>
                  <div class="flex flex-wrap items-center gap-2">
                    <span class="text-sm opacity-70">Pantas:</span>
                    <Badge v-for="preset in QUICK_DATE_PRESETS" :key="`leave-${preset.label}`" variant="ghost"
                      look="outline" role="button" tabindex="0" @click="applyLeaveDatePreset(preset)"
                      @keydown.enter="applyLeaveDatePreset(preset)">
                      {{ preset.label }}
                    </Badge>
                  </div>
                  <div class="flex items-center gap-2">
                    <Input v-model="leaveDateFrom" type="date" aria-label="Tarikh berhenti dari" />
                    <span class="text-sm opacity-50">–</span>
                    <Input v-model="leaveDateTo" type="date" aria-label="Tarikh berhenti hingga" />
                  </div>
                </div>
                <Button v-if="hasLeaveDateFilters" type="button" variant="ghost" look="outline"
                  @click="clearLeaveDateFilters">
                  Reset
                </Button>
              </div>
            </div>
          </div>
        </AccordionContent>
      </AccordionItem>
    </AccordionRoot>

    <DataTable :headers="headers" :items="users" :loading="loading" :pagination="pagination" :current-sort="sortBy"
      show-pagination exportable export-file-name="users" export-pdf-title="Senarai Daftar Anggota" v-model:page="page"
      v-model:items-per-page="itemsPerPage" @update:sort-by="handleSortUpdate">
      <template #toolbar>
        <div class="flex w-full flex-col gap-3">
          <div class="flex w-full flex-wrap items-center gap-3">
            <div class="relative w-full max-w-md flex-1">
              <Search
                class="pointer-events-none absolute top-1/2 left-3 z-10 size-4 -translate-y-1/2 text-foreground/50"
                aria-hidden="true" />
              <Input v-model="search" type="search" placeholder="Cari nama, email, no. anggota, jawatan..."
                class="w-full pl-9" aria-label="Search users" />
            </div>
            <Button v-if="hasPermission('daftar pengguna baru')" type="button" variant="primary" look="outline"
              @click="goToCreateUser">
              Daftar Pengguna
            </Button>
          </div>
          <div class="flex flex-wrap items-center gap-2">
            <span class="text-sm opacity-70">Status:</span>
            <Badge v-for="chip in STATUS_FILTER_CHIPS" :key="chip.value || 'all'" :variant="chip.variant"
              :look="isStatusFilterActive(chip.value) ? 'filled' : 'outline'" class="capitalize" role="button"
              tabindex="0" :aria-pressed="isStatusFilterActive(chip.value)" @click="setStatusFilter(chip.value)"
              @keydown.enter="setStatusFilter(chip.value)">
              {{ chip.label }}
            </Badge>
          </div>
          <div class="flex flex-wrap items-center gap-2">
            <span class="text-sm opacity-70">Unit:</span>
            <Badge v-for="chip in UNIT_FILTER_CHIPS" :key="chip.value || 'all-units'" variant="ghost"
              :look="isUnitFilterActive(chip.value) ? 'filled' : 'outline'" role="button" tabindex="0"
              :title="chip.value || 'Semua unit'" :aria-pressed="isUnitFilterActive(chip.value)"
              @click="setUnitFilter(chip.value)" @keydown.enter="setUnitFilter(chip.value)">
              {{ chip.label }}
            </Badge>
          </div>
        </div>
      </template>

      <template #item.name="{ item }">
        <div class="flex items-center gap-2">
          <!-- profile image -->
          <img v-if="item.image_url" :src="item.image_url" alt="Profile Image" class="size-10 rounded-full" />
          <div v-else class="size-10 rounded-full bg-gray-200 flex items-center justify-center">
            <span class="text-gray-500">{{ item.name.charAt(0) }}</span>
          </div>

          <!-- name -->
          <span class="font-medium">{{ item.name }}</span>
        </div>
      </template>

      <template #item.email="{ item }">
        <span class="lowercase">{{ item.email }}</span>
      </template>

      <template #item.member_type="{ item }">
        <span class="capitalize">{{ item.member_type }}</span>
      </template>

      <template #item.company_name="{ item }">
        <span>{{ getUserCompanyName(item) }}</span>
      </template>

      <template #item.roles="{ item }">
        {{ formatUserRoles(item.roles) }}
      </template>

      <template #item.member_number="{ item }">
        <span class="text-center">{{ item.member_number }}</span>
      </template>

      <template #item.join_date="{ item }">
        {{ formatUserDate(item.join_date) }}
      </template>

      <template #item.leave_date="{ item }">
        {{ formatUserDate(item.leave_date) }}
      </template>

      <!-- centre align status -->
      <template #item.status="{ item }">
        <Badge :variant="statusBadgeVariant(item.status)" class="capitalize text-center">
          {{ item.status }}
        </Badge>
      </template>

      <template #item.actions="{ item }">
        <div class="flex items-center">
          <Button v-if="hasPermission('lihat peranan')" type="button" variant="ghost" size="sm"
            class="bg-purple-600 text-white disabled:opacity-50" :disabled="savingRoles"
            :title="savingRoles ? 'Menyimpan perubahan...' : 'Tetapkan peranan'"
            @click="openAssignRolesDialog(item as UserListItem)"> Urus Peranan
            <Shield class="size-4" aria-hidden="true" />
          </Button>
          <Button v-if="hasPermission('lihat pengguna')" type="button" variant="ghost" size="sm"
            class="bg-green-600 text-white disabled:opacity-50" :disabled="savingRoles"
            :title="savingRoles ? 'Menyimpan perubahan...' : 'Lihat profil'" @click="goToViewUser(item.id)">
            <Eye class="size-4" aria-hidden="true" />
          </Button>
          <Button v-if="hasPermission('kemaskini pengguna')" type="button" variant="ghost" size="sm"
            class="bg-yellow-600 text-white disabled:opacity-50" :disabled="savingRoles"
            :title="savingRoles ? 'Menyimpan perubahan...' : 'Kemaskini pengguna'" @click="goToEditUser(item.id)">
            <SquarePen class="size-4" aria-hidden="true" />
          </Button>
          <Button v-if="hasPermission('padam akaun pengguna')" type="button" variant="ghost" size="sm"
            class="bg-red-600 text-white disabled:opacity-50" :disabled="deleting"
            @click="openDeleteConfirmation(item as UserListItem)">
            <Trash2 class="size-4" aria-hidden="true" />
          </Button>
          <Button v-if="showImpersonateButton(item as UserListItem)" type="button" variant="ghost" size="sm"
            class="bg-orange-600 text-white disabled:opacity-50"
            :disabled="!canImpersonateUser(item as UserListItem) || impersonateLoading || impersonating"
            :title="impersonateButtonTitle(item as UserListItem)" @click="impersonateUser(item as UserListItem)">
            <HatGlasses class="size-4" aria-hidden="true" />
          </Button>

        </div>
      </template>
    </DataTable>

    <!-- Start of deleted users table -->
    <div class="space-y-4 border-t border-foreground/10 pt-8">
      <div>
        <h3 class="text-lg font-medium">Pengguna Dipadam</h3>
        <p class="mt-1 text-sm opacity-70">Pengguna yang telah dipadam dan boleh dipulihkan.</p>
      </div>

      <AlertRoot v-if="deletedError" variant="danger">
        <AlertTitle>Error</AlertTitle>
        <AlertDescription>{{ deletedError }}</AlertDescription>
      </AlertRoot>

      <DataTable :headers="deletedHeaders" :items="deletedUsers" :loading="deletedLoading"
        :pagination="deletedPagination" :current-sort="deletedSortBy" show-pagination exportable
        export-file-name="deleted-users" v-model:page="deletedPage" v-model:items-per-page="deletedItemsPerPage"
        @update:sort-by="handleDeletedSortUpdate">
        <template #item.name="{ item }">
          <div class="flex items-center gap-2">
            <img v-if="item.image_url" :src="item.image_url" alt="Profile Image" class="size-10 rounded-full" />
            <div v-else class="flex size-10 items-center justify-center rounded-full bg-gray-200">
              <span class="text-gray-500">{{ item.name.charAt(0) }}</span>
            </div>
            <span class="font-medium">{{ item.name }}</span>
          </div>
        </template>

        <template #item.email="{ item }">
          <span class="lowercase">{{ item.email }}</span>
        </template>

        <template #item.member_type="{ item }">
          <span class="uppercase">{{ item.member_type }}</span>
        </template>

        <template #item.company_name="{ item }">
          <span>{{ getUserCompanyName(item) }}</span>
        </template>

        <template #item.roles="{ item }">
          {{ formatUserRoles(item.roles) }}
        </template>

        <template #item.member_number="{ item }">
          <span class="text-center">{{ item.member_number ?? '-' }}</span>
        </template>

        <template #item.status="{ item }">
          <Badge :variant="statusBadgeVariant(item.status)" class="capitalize text-center">
            {{ item.status }}
          </Badge>
        </template>

        <template #item.deleted_at="{ item }">
          {{ formatDeletedAt(item.deleted_at) }}
        </template>

        <template #item.actions="{ item }">
          <div class="flex items-center">
            <Button v-if="hasPermission('padam akaun pengguna')" type="button" variant="ghost" size="sm"
              class="bg-blue-600 text-white disabled:opacity-50" :disabled="restoring" title="Pulihkan pengguna"
              @click="openRestoreConfirmation(item as UserListItem)">
              <RotateCcw class="size-4" aria-hidden="true" />
              Pulihkan
            </Button>
          </div>
        </template>
      </DataTable>
    </div>

    <!-- Assign roles dialog -->
    <DialogRoot :open="assignRolesOpen" @openChange="(details) => (assignRolesOpen = details.open)">
      <DialogContent>
        <div class="p-5">
          <div class="text-center text-2xl font-medium">Tetapkan Peranan</div>
          <div v-if="userToAssignRoles" class="mt-2 text-center opacity-70">
            Pilih peranan untuk
            <span class="font-medium">{{ userToAssignRoles.name }}</span>
          </div>

          <div v-if="assignRolesError" class="mt-4 text-center text-sm text-danger">
            {{ assignRolesError }}
          </div>

          <div class="mt-5 max-h-80 overflow-auto rounded-lg border border-foreground/10 p-3">
            <div v-if="loadingRoles" class="py-6 text-center opacity-70">
              Memuatkan peranan...
            </div>
            <div v-else-if="!availableRoles.length" class="py-6 text-center opacity-70">
              Tiada peranan ditemui
            </div>
            <div v-else class="grid grid-cols-1 gap-2">
              <CheckboxRoot v-for="role in availableRoles" :key="role.id" :checked="selectedRoleIds.has(role.id)"
                :disabled="savingRoles" @checked-change="({ checked }) => setRoleChecked(role.id, checked === true)">
                <CheckboxControl />
                <CheckboxLabel>
                  <span class="font-medium">{{ role.name }}</span>
                  <span v-if="role.fullname" class="ml-2 opacity-70">({{ role.fullname }})</span>
                </CheckboxLabel>
              </CheckboxRoot>
            </div>
          </div>
        </div>
        <div class="px-5 pb-8 text-center">
          <DialogCloseTrigger class="mr-2 w-24" :disabled="savingRoles">
            Batal
          </DialogCloseTrigger>
          <Button class="w-24" type="button" variant="primary" look="outline" :disabled="savingRoles || loadingRoles"
            @click="confirmAssignRoles">
            {{ savingRoles ? 'Menyimpan...' : 'Simpan' }}
          </Button>
        </div>
      </DialogContent>
    </DialogRoot>

    <!-- Delete confirmation dialog -->
    <DialogRoot :open="deleteConfirmationOpen" @openChange="(details) => (deleteConfirmationOpen = details.open)">
      <DialogContent>
        <div class="p-5 text-center">
          <Lucide class="text-danger mx-auto mt-3 size-16 stroke-1" icon="CircleX" />
          <div class="mt-5 text-2xl font-medium">Adakah anda yakin?</div>
          <div class="mt-2 opacity-70">
            Adakah anda benar-benar mahu menghapus
            <span v-if="userToDelete" class="font-medium">{{ userToDelete.name }}</span>?
            <br />
            Proses ini tidak boleh dibatalkan.
          </div>
          <div v-if="deleteError" class="mt-4 text-sm text-danger">
            {{ deleteError }}
          </div>
        </div>
        <div class="px-5 pb-8 text-center">
          <DialogCloseTrigger class="mr-2 w-24" :disabled="deleting">
            Batal
          </DialogCloseTrigger>
          <Button class="w-24" type="button" variant="danger" look="outline" :disabled="deleting"
            @click="confirmDelete">
            {{ deleting ? 'Menghapus...' : 'Hapus' }}
          </Button>
        </div>
      </DialogContent>
    </DialogRoot>

    <!-- Restore confirmation dialog -->
    <DialogRoot :open="restoreConfirmationOpen" @openChange="(details) => (restoreConfirmationOpen = details.open)">
      <DialogContent>
        <div class="p-5 text-center">
          <Lucide class="mx-auto mt-3 size-16 stroke-1 text-primary" icon="RotateCcw" />
          <div class="mt-5 text-2xl font-medium">Pulihkan pengguna?</div>
          <div class="mt-2 opacity-70">
            Adakah anda mahu memulihkan
            <span v-if="userToRestore" class="font-medium">{{ userToRestore.name }}</span>?
          </div>
          <div v-if="restoreError" class="mt-4 text-sm text-danger">
            {{ restoreError }}
          </div>
        </div>
        <div class="px-5 pb-8 text-center">
          <DialogCloseTrigger class="mr-2 w-24" :disabled="restoring">
            Batal
          </DialogCloseTrigger>
          <Button class="w-24" type="button" variant="primary" look="outline" :disabled="restoring"
            @click="confirmRestore">
            {{ restoring ? 'Memulihkan...' : 'Pulihkan' }}
          </Button>
        </div>
      </DialogContent>
    </DialogRoot>
  </div>
</template>
