// Đặt phòng họp (Meeting Calendar) — Phase 10.2 G-O2 (S36 2026-05-28).
// Custom HTML 7-day week grid (8h–20h, 1h slot) — KHÔNG cài FullCalendar dep
// để giữ bundle size minimal (Investigator verdict pre-flight S36).
// Booking blocks render absolute positioning theo startAt/endAt.
// File này MIRROR SHA256 identical với fe-user counterpart.
// Pattern 16-bis 4-place mirror foundation (7× cumulative).
import { useMemo, useState, type FormEvent } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, Clock, MapPin, Plus, Trash2, Users as UsersIcon, X } from 'lucide-react'
import { toast } from 'sonner'
import { PageHeader } from '@/components/PageHeader'
import { Button } from '@/components/ui/Button'
import { Input } from '@/components/ui/Input'
import { Label } from '@/components/ui/Label'
import { Textarea } from '@/components/ui/Textarea'
import { Select } from '@/components/ui/Select'
import { Dialog } from '@/components/ui/Dialog'
import { useAuth } from '@/contexts/AuthContext'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import { cn } from '@/lib/cn'
import type { Paged } from '@/types/master'
import {
  MeetingBookingStatus,
  type AttendeeInput,
  type MeetingBookingCreateInput,
  type MeetingBookingDto,
  type MeetingRoomDto,
} from '@/types/meeting'

// Calendar constants — 12 slot 1h, 8h–20h.
const HOUR_START = 8
const HOUR_END = 20
const SLOT_COUNT = HOUR_END - HOUR_START
const SLOT_PX = 56 // height of each 1h row
const DAYS_OF_WEEK = ['T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN'] as const

// ===== Date helpers =====

function startOfWeek(d: Date): Date {
  const x = new Date(d)
  x.setHours(0, 0, 0, 0)
  const day = x.getDay() // 0=Sun, 1=Mon...
  const diff = day === 0 ? -6 : 1 - day // shift to Monday
  x.setDate(x.getDate() + diff)
  return x
}

function addDays(d: Date, days: number): Date {
  const x = new Date(d)
  x.setDate(x.getDate() + days)
  return x
}

function formatDateRange(weekStart: Date): string {
  const end = addDays(weekStart, 6)
  const sameMonth = weekStart.getMonth() === end.getMonth()
  if (sameMonth) {
    return `${weekStart.getDate()}–${end.getDate()}/${weekStart.getMonth() + 1}/${weekStart.getFullYear()}`
  }
  return `${weekStart.getDate()}/${weekStart.getMonth() + 1}–${end.getDate()}/${end.getMonth() + 1}/${weekStart.getFullYear()}`
}

function formatTime(iso: string): string {
  const d = new Date(iso)
  return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
}

// Trả về datetime-local string 'YYYY-MM-DDTHH:mm' từ Date (giữ local tz).
function toLocalDateTimeString(d: Date): string {
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}

// Booking nằm trong day d nếu (startAt < endOfDay) && (endAt > startOfDay).
function bookingOverlapsDay(b: MeetingBookingDto, day: Date): boolean {
  const startOfDay = new Date(day)
  startOfDay.setHours(0, 0, 0, 0)
  const endOfDay = new Date(day)
  endOfDay.setHours(23, 59, 59, 999)
  const bStart = new Date(b.startAt)
  const bEnd = new Date(b.endAt)
  return bStart < endOfDay && bEnd > startOfDay
}

// Compute top + height (px) cho 1 booking trong day cụ thể.
function computeBlockStyle(b: MeetingBookingDto, day: Date): { top: number; height: number } {
  const bStart = new Date(b.startAt)
  const bEnd = new Date(b.endAt)
  const dayStart = new Date(day)
  dayStart.setHours(HOUR_START, 0, 0, 0)
  const dayEnd = new Date(day)
  dayEnd.setHours(HOUR_END, 0, 0, 0)
  const clampedStart = bStart < dayStart ? dayStart : bStart
  const clampedEnd = bEnd > dayEnd ? dayEnd : bEnd
  const topHours = (clampedStart.getTime() - dayStart.getTime()) / (1000 * 60 * 60)
  const durationHours = (clampedEnd.getTime() - clampedStart.getTime()) / (1000 * 60 * 60)
  return {
    top: Math.max(0, topHours * SLOT_PX),
    height: Math.max(20, durationHours * SLOT_PX),
  }
}

// Status badge color
function statusBadgeClass(status: number): string {
  if (status === MeetingBookingStatus.Cancelled) return 'bg-slate-100 text-slate-500 line-through'
  if (status === MeetingBookingStatus.Completed) return 'bg-emerald-100 text-emerald-700'
  return 'bg-brand-100 text-brand-700' // Confirmed
}

function statusLabel(status: number): string {
  if (status === MeetingBookingStatus.Cancelled) return 'Đã hủy'
  if (status === MeetingBookingStatus.Completed) return 'Đã hoàn tất'
  return 'Xác nhận'
}

// ===== Page =====

type UserOption = { id: string; fullName: string; email: string }

export function MeetingCalendarPage() {
  const auth = useAuth()
  const qc = useQueryClient()

  const [weekStart, setWeekStart] = useState<Date>(() => startOfWeek(new Date()))
  const [roomId, setRoomId] = useState<string>('')

  const [createOpen, setCreateOpen] = useState(false)
  const [createForm, setCreateForm] = useState<Partial<MeetingBookingCreateInput>>({})
  const [createAttendees, setCreateAttendees] = useState<AttendeeInput[]>([])

  const [detailId, setDetailId] = useState<string | null>(null)

  const rooms = useQuery({
    queryKey: ['meeting-rooms', 'active'],
    queryFn: async () =>
      (await api.get<MeetingRoomDto[]>('/meeting-rooms', { params: { isActiveOnly: true } })).data,
  })

  const weekEnd = useMemo(() => addDays(weekStart, 7), [weekStart])

  const bookings = useQuery({
    queryKey: ['meeting-bookings', { roomId, weekStart: weekStart.toISOString() }],
    queryFn: async () =>
      (await api.get<MeetingBookingDto[]>('/meeting-bookings', {
        params: {
          roomId: roomId || undefined,
          startDate: weekStart.toISOString(),
          endDate: weekEnd.toISOString(),
        },
      })).data,
  })

  const users = useQuery({
    queryKey: ['users-meeting-attendees'],
    queryFn: async () =>
      (await api.get<Paged<UserOption>>('/users', { params: { page: 1, pageSize: 200 } })).data.items,
    enabled: createOpen || detailId !== null,
  })

  const createBooking = useMutation({
    mutationFn: async (payload: MeetingBookingCreateInput) => {
      await api.post('/meeting-bookings', payload)
    },
    onSuccess: () => {
      toast.success('Đã tạo booking')
      qc.invalidateQueries({ queryKey: ['meeting-bookings'] })
      setCreateOpen(false)
      setCreateForm({})
      setCreateAttendees([])
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  const cancelBooking = useMutation({
    mutationFn: async (id: string) => {
      await api.delete(`/meeting-bookings/${id}`)
    },
    onSuccess: () => {
      toast.success('Đã hủy booking')
      qc.invalidateQueries({ queryKey: ['meeting-bookings'] })
      setDetailId(null)
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  function openCreateForSlot(day: Date, hour: number) {
    const start = new Date(day)
    start.setHours(hour, 0, 0, 0)
    const end = new Date(day)
    end.setHours(hour + 1, 0, 0, 0)
    setCreateForm({
      roomId: roomId || rooms.data?.[0]?.id || '',
      startAt: toLocalDateTimeString(start),
      endAt: toLocalDateTimeString(end),
      title: '',
      description: '',
      note: '',
    })
    setCreateAttendees([])
    setCreateOpen(true)
  }

  function openCreateBlank() {
    const now = new Date()
    const next = new Date(now)
    next.setHours(now.getHours() + 1, 0, 0, 0)
    const end = new Date(next)
    end.setHours(end.getHours() + 1)
    setCreateForm({
      roomId: roomId || rooms.data?.[0]?.id || '',
      startAt: toLocalDateTimeString(next),
      endAt: toLocalDateTimeString(end),
      title: '',
      description: '',
      note: '',
    })
    setCreateAttendees([])
    setCreateOpen(true)
  }

  function submitCreate(e: FormEvent) {
    e.preventDefault()
    if (!createForm.roomId || !createForm.startAt || !createForm.endAt || !createForm.title?.trim()) {
      toast.error('Vui lòng nhập đầy đủ thông tin')
      return
    }
    // datetime-local strings không có tz suffix → convert sang ISO UTC
    const payload: MeetingBookingCreateInput = {
      roomId: createForm.roomId,
      startAt: new Date(createForm.startAt).toISOString(),
      endAt: new Date(createForm.endAt).toISOString(),
      title: createForm.title.trim(),
      description: createForm.description?.trim() || null,
      note: createForm.note?.trim() || null,
      attendees: createAttendees,
    }
    createBooking.mutate(payload)
  }

  const detailBooking = useMemo(
    () => bookings.data?.find(b => b.id === detailId) ?? null,
    [bookings.data, detailId],
  )

  // Filter bookings cho từng day column
  const bookingsByDay = useMemo(() => {
    const map = new Map<number, MeetingBookingDto[]>()
    for (let i = 0; i < 7; i++) {
      const day = addDays(weekStart, i)
      const dayBookings = (bookings.data ?? []).filter(b => bookingOverlapsDay(b, day))
      map.set(i, dayBookings)
    }
    return map
  }, [bookings.data, weekStart])

  const totalThisWeek = bookings.data?.length ?? 0

  return (
    <div className="p-6">
      <PageHeader
        title={
          <span className="flex items-center gap-2">
            <CalendarIcon className="h-5 w-5" />
            Đặt phòng họp
          </span>
        }
        description={bookings.isLoading ? 'Đang tải…' : `${totalThisWeek} booking tuần này`}
        actions={
          <Button onClick={openCreateBlank}>
            <Plus className="h-4 w-4" />
            Tạo Booking
          </Button>
        }
      />

      {/* Filter bar */}
      <div className="mb-4 flex flex-col gap-2 rounded-lg border border-slate-200 bg-white p-3 shadow-sm sm:flex-row sm:items-center">
        <div className="flex items-center gap-2">
          <Button variant="outline" size="sm" onClick={() => setWeekStart(startOfWeek(addDays(weekStart, -7)))}>
            <ChevronLeft className="h-4 w-4" />
          </Button>
          <Button variant="outline" size="sm" onClick={() => setWeekStart(startOfWeek(new Date()))}>
            Hôm nay
          </Button>
          <Button variant="outline" size="sm" onClick={() => setWeekStart(startOfWeek(addDays(weekStart, 7)))}>
            <ChevronRight className="h-4 w-4" />
          </Button>
          <span className="ml-2 text-sm font-medium text-slate-700">{formatDateRange(weekStart)}</span>
        </div>
        <div className="flex-1" />
        <Select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
          className="sm:w-64"
        >
          <option value="">Tất cả phòng họp</option>
          {(rooms.data ?? []).map(r => (
            <option key={r.id} value={r.id}>
              {r.code} — {r.name} ({r.capacity} chỗ)
            </option>
          ))}
        </Select>
      </div>

      {/* Calendar grid */}
      <div className="overflow-x-auto rounded-lg border border-slate-200 bg-white shadow-sm">
        <div className="min-w-[900px]">
          {/* Header row: 7 days */}
          <div className="sticky top-0 z-10 grid grid-cols-[60px_repeat(7,minmax(0,1fr))] border-b border-slate-200 bg-slate-50">
            <div className="border-r border-slate-200 px-2 py-2 text-[11px] uppercase tracking-wider text-slate-500"></div>
            {DAYS_OF_WEEK.map((d, i) => {
              const day = addDays(weekStart, i)
              const isToday = day.toDateString() === new Date().toDateString()
              return (
                <div
                  key={d}
                  className={cn(
                    'border-r border-slate-200 px-2 py-2 text-center last:border-r-0',
                    isToday && 'bg-brand-50',
                  )}
                >
                  <div className="text-[11px] uppercase tracking-wider text-slate-500">{d}</div>
                  <div className={cn('text-sm font-semibold', isToday ? 'text-brand-700' : 'text-slate-900')}>
                    {day.getDate()}/{day.getMonth() + 1}
                  </div>
                </div>
              )
            })}
          </div>

          {/* Time slots column + day columns (relative parent for absolute booking blocks) */}
          <div className="grid grid-cols-[60px_repeat(7,minmax(0,1fr))]">
            {/* Time labels column */}
            <div className="border-r border-slate-200 bg-slate-50/50">
              {Array.from({ length: SLOT_COUNT }).map((_, i) => (
                <div
                  key={i}
                  className="flex items-start justify-end border-b border-slate-100 px-2 py-1 text-[10px] text-slate-400"
                  style={{ height: `${SLOT_PX}px` }}
                >
                  {String(HOUR_START + i).padStart(2, '0')}:00
                </div>
              ))}
            </div>

            {/* 7 day columns */}
            {Array.from({ length: 7 }).map((_, dayIdx) => {
              const day = addDays(weekStart, dayIdx)
              const dayBookings = bookingsByDay.get(dayIdx) ?? []
              return (
                <div
                  key={dayIdx}
                  className="relative border-r border-slate-200 last:border-r-0"
                  style={{ height: `${SLOT_COUNT * SLOT_PX}px` }}
                >
                  {/* Hour slot click targets */}
                  {Array.from({ length: SLOT_COUNT }).map((_, hourIdx) => (
                    <button
                      key={hourIdx}
                      onClick={() => openCreateForSlot(day, HOUR_START + hourIdx)}
                      className="block w-full border-b border-slate-100 transition hover:bg-brand-50/40"
                      style={{ height: `${SLOT_PX}px` }}
                      title={`Tạo booking lúc ${String(HOUR_START + hourIdx).padStart(2, '0')}:00`}
                    />
                  ))}

                  {/* Absolute booking blocks */}
                  {dayBookings.map(b => {
                    const { top, height } = computeBlockStyle(b, day)
                    const isOwn = b.bookedByUserId === auth.user?.id
                    return (
                      <button
                        key={b.id}
                        onClick={() => setDetailId(b.id)}
                        className={cn(
                          'absolute left-1 right-1 overflow-hidden rounded-md border px-2 py-1 text-left text-[11px] shadow-sm transition hover:shadow',
                          statusBadgeClass(b.status),
                          isOwn ? 'border-brand-400 ring-1 ring-brand-200' : 'border-slate-200',
                        )}
                        style={{ top: `${top}px`, height: `${height}px` }}
                      >
                        <div className="truncate font-semibold leading-tight">{b.title}</div>
                        <div className="truncate text-[10px] opacity-80">
                          {formatTime(b.startAt)}–{formatTime(b.endAt)} · {b.roomCode}
                        </div>
                        {height >= 56 && (
                          <div className="truncate text-[10px] opacity-70">{b.bookedByFullName}</div>
                        )}
                      </button>
                    )
                  })}
                </div>
              )
            })}
          </div>
        </div>
      </div>

      {/* Legend */}
      <div className="mt-3 flex flex-wrap gap-3 text-[11px] text-slate-500">
        <span className="flex items-center gap-1"><span className="h-3 w-3 rounded bg-brand-100" /> Xác nhận</span>
        <span className="flex items-center gap-1"><span className="h-3 w-3 rounded bg-emerald-100" /> Hoàn tất</span>
        <span className="flex items-center gap-1"><span className="h-3 w-3 rounded bg-slate-100" /> Đã hủy</span>
        <span className="flex items-center gap-1"><span className="h-3 w-3 rounded border border-brand-400" /> Booking của tôi</span>
      </div>

      {/* Create Dialog */}
      <Dialog
        open={createOpen}
        onClose={() => setCreateOpen(false)}
        title="Tạo Booking mới"
        size="lg"
        footer={
          <>
            <Button variant="outline" onClick={() => setCreateOpen(false)}>Hủy</Button>
            <Button onClick={(e: FormEvent) => submitCreate(e)} disabled={createBooking.isPending}>
              {createBooking.isPending ? 'Đang tạo…' : 'Tạo'}
            </Button>
          </>
        }
      >
        <form onSubmit={submitCreate} className="space-y-3">
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
            <div className="space-y-1">
              <Label>Phòng họp *</Label>
              <Select
                value={createForm.roomId ?? ''}
                onChange={e => setCreateForm(s => ({ ...s, roomId: e.target.value }))}
                required
              >
                <option value="">— Chọn phòng —</option>
                {(rooms.data ?? []).map(r => (
                  <option key={r.id} value={r.id}>
                    {r.code} — {r.name} ({r.capacity} chỗ)
                  </option>
                ))}
              </Select>
            </div>
            <div className="space-y-1">
              <Label>Tiêu đề *</Label>
              <Input
                value={createForm.title ?? ''}
                onChange={e => setCreateForm(s => ({ ...s, title: e.target.value }))}
                placeholder="VD: Họp planning Q3 2026"
                required
              />
            </div>
            <div className="space-y-1">
              <Label>Bắt đầu *</Label>
              <Input
                type="datetime-local"
                value={createForm.startAt ?? ''}
                onChange={e => setCreateForm(s => ({ ...s, startAt: e.target.value }))}
                required
              />
            </div>
            <div className="space-y-1">
              <Label>Kết thúc *</Label>
              <Input
                type="datetime-local"
                value={createForm.endAt ?? ''}
                onChange={e => setCreateForm(s => ({ ...s, endAt: e.target.value }))}
                required
              />
            </div>
          </div>

          <div className="space-y-1">
            <Label>Mô tả</Label>
            <Textarea
              rows={2}
              value={createForm.description ?? ''}
              onChange={e => setCreateForm(s => ({ ...s, description: e.target.value }))}
              placeholder="Nội dung họp, agenda..."
            />
          </div>

          <div className="space-y-1">
            <Label>Ghi chú</Label>
            <Input
              value={createForm.note ?? ''}
              onChange={e => setCreateForm(s => ({ ...s, note: e.target.value }))}
              placeholder="Ghi chú nội bộ"
            />
          </div>

          <div className="space-y-1">
            <Label>Người tham dự ({createAttendees.length})</Label>
            <AttendeePicker
              users={users.data ?? []}
              selected={createAttendees}
              onChange={setCreateAttendees}
            />
          </div>
        </form>
      </Dialog>

      {/* Detail Dialog */}
      <Dialog
        open={detailBooking !== null}
        onClose={() => setDetailId(null)}
        title="Chi tiết Booking"
        size="lg"
        footer={
          detailBooking && detailBooking.bookedByUserId === auth.user?.id
            && detailBooking.status === MeetingBookingStatus.Confirmed
            ? (
              <>
                <Button variant="outline" onClick={() => setDetailId(null)}>Đóng</Button>
                <Button
                  variant="danger"
                  onClick={() => {
                    if (confirm('Hủy booking này?')) cancelBooking.mutate(detailBooking.id)
                  }}
                  disabled={cancelBooking.isPending}
                >
                  <Trash2 className="h-4 w-4" />
                  Hủy booking
                </Button>
              </>
            ) : (
              <Button variant="outline" onClick={() => setDetailId(null)}>Đóng</Button>
            )
        }
      >
        {detailBooking && (
          <div className="space-y-3 text-sm">
            <div>
              <h3 className="text-base font-semibold text-slate-900">{detailBooking.title}</h3>
              <div className="mt-1 flex flex-wrap items-center gap-2 text-xs">
                <span className={cn('rounded-full px-2 py-0.5', statusBadgeClass(detailBooking.status))}>
                  {statusLabel(detailBooking.status)}
                </span>
                <span className="text-slate-500">
                  Người tạo: <span className="font-medium text-slate-700">{detailBooking.bookedByFullName}</span>
                </span>
              </div>
            </div>

            <div className="grid grid-cols-1 gap-2 rounded-md bg-slate-50 p-3 sm:grid-cols-2">
              <div className="flex items-center gap-2 text-slate-700">
                <MapPin className="h-4 w-4 text-slate-400" />
                <span>{detailBooking.roomCode} — {detailBooking.roomName}</span>
              </div>
              <div className="flex items-center gap-2 text-slate-700">
                <Clock className="h-4 w-4 text-slate-400" />
                <span>
                  {new Date(detailBooking.startAt).toLocaleString('vi-VN', { dateStyle: 'short', timeStyle: 'short' })}
                  {' – '}
                  {new Date(detailBooking.endAt).toLocaleString('vi-VN', { dateStyle: 'short', timeStyle: 'short' })}
                </span>
              </div>
            </div>

            {detailBooking.description && (
              <div>
                <Label className="text-xs text-slate-500">Mô tả</Label>
                <p className="mt-1 whitespace-pre-wrap text-sm text-slate-700">{detailBooking.description}</p>
              </div>
            )}

            {detailBooking.note && (
              <div>
                <Label className="text-xs text-slate-500">Ghi chú</Label>
                <p className="mt-1 text-sm text-slate-700">{detailBooking.note}</p>
              </div>
            )}

            <div>
              <Label className="flex items-center gap-1 text-xs text-slate-500">
                <UsersIcon className="h-3.5 w-3.5" />
                Người tham dự ({detailBooking.attendees.length})
              </Label>
              {detailBooking.attendees.length === 0 ? (
                <p className="mt-1 text-xs text-slate-400">— Không có người tham dự —</p>
              ) : (
                <ul className="mt-1 divide-y divide-slate-100 rounded-md border border-slate-200">
                  {detailBooking.attendees.map(a => (
                    <li key={a.userId} className="flex items-start gap-2 px-3 py-2 text-xs">
                      <UsersIcon className="mt-0.5 h-3.5 w-3.5 text-slate-400" />
                      <div className="flex-1">
                        <div className="font-medium text-slate-700">{a.fullName}</div>
                        {a.email && <div className="text-[11px] text-slate-500">{a.email}</div>}
                        {a.notes && <div className="mt-0.5 text-[11px] italic text-slate-500">{a.notes}</div>}
                      </div>
                    </li>
                  ))}
                </ul>
              )}
            </div>
          </div>
        )}
      </Dialog>
    </div>
  )
}

// ===== AttendeePicker subcomponent =====

function AttendeePicker({
  users,
  selected,
  onChange,
}: {
  users: UserOption[]
  selected: AttendeeInput[]
  onChange: (next: AttendeeInput[]) => void
}) {
  const [search, setSearch] = useState('')
  const selectedIds = useMemo(() => new Set(selected.map(a => a.userId)), [selected])

  const filtered = useMemo(() => {
    if (!search.trim()) return users.slice(0, 50)
    const s = search.toLowerCase()
    return users
      .filter(u => u.fullName.toLowerCase().includes(s) || u.email.toLowerCase().includes(s))
      .slice(0, 50)
  }, [users, search])

  function toggle(u: UserOption) {
    if (selectedIds.has(u.id)) {
      onChange(selected.filter(a => a.userId !== u.id))
    } else {
      onChange([...selected, { userId: u.id, notes: null }])
    }
  }

  function removeAt(id: string) {
    onChange(selected.filter(a => a.userId !== id))
  }

  return (
    <div className="rounded-md border border-slate-200">
      {/* Selected chips */}
      {selected.length > 0 && (
        <div className="flex flex-wrap gap-1 border-b border-slate-200 bg-slate-50 p-2">
          {selected.map(a => {
            const u = users.find(x => x.id === a.userId)
            return (
              <span
                key={a.userId}
                className="inline-flex items-center gap-1 rounded-full bg-brand-100 px-2 py-0.5 text-[11px] text-brand-700"
              >
                {u?.fullName ?? a.userId}
                <button
                  type="button"
                  onClick={() => removeAt(a.userId)}
                  className="rounded-full text-brand-600 hover:bg-brand-200"
                >
                  <X className="h-3 w-3" />
                </button>
              </span>
            )
          })}
        </div>
      )}

      {/* Search + list */}
      <div className="p-2">
        <Input
          value={search}
          onChange={e => setSearch(e.target.value)}
          placeholder="Tìm theo tên / email…"
          className="mb-2 h-8 text-xs"
        />
        <div className="max-h-40 overflow-y-auto rounded border border-slate-100">
          {filtered.length === 0 ? (
            <div className="p-3 text-center text-[11px] text-slate-400">Không có user khớp.</div>
          ) : (
            filtered.map(u => {
              const isSel = selectedIds.has(u.id)
              return (
                <button
                  key={u.id}
                  type="button"
                  onClick={() => toggle(u)}
                  className={cn(
                    'block w-full px-2 py-1.5 text-left text-xs transition',
                    isSel ? 'bg-brand-50 text-brand-700' : 'hover:bg-slate-50',
                  )}
                >
                  <div className="font-medium">{u.fullName}</div>
                  <div className="text-[10px] text-slate-500">{u.email}</div>
                </button>
              )
            })
          )}
        </div>
      </div>
    </div>
  )
}
