"use client"

import { useEffect, useMemo, useState } from "react"
import { MoreHorizontal, UserPlus, UsersRound } from "lucide-react"
import { SettingsSectionHeader } from "@/components/gmail/settings/settings-section-header"
import { SettingsSyncBanner } from "@/components/gmail/settings/settings-sync-banner"
import { AdminListControls, type AdminListSortOption } from "@/components/admin/settings/admin-list-controls"
import { UsersBulkToolbar } from "@/components/admin/settings/sections/users-bulk-toolbar"
import { UsersGroupsDialog } from "@/components/admin/settings/sections/users-groups-dialog"
import { useAdminUser, useAdminUserGroups, useAdminUsers } from "@/lib/api/hooks/use-admin-queries"
import {
  useDeleteAdminUser,
  useDisableAdminUser,
  useInviteAdminUser,
  useReactivateAdminUser,
  useSetAdminUserQuota,
  useSetAdminUserRole,
  useUpdateAdminUser,
} from "@/lib/api/hooks/use-admin-mutations"
import { useUpdateUserAICostPolicy } from "@/lib/api/hooks/use-admin-ai-usage"
import type { AdminUser, AdminUserRole } from "@/lib/api/admin-types"
import { bytesToGib, formatBytes, gibToBytes } from "@/lib/admin/format-bytes"
import {
  resolveUserRole,
  USER_ROLE_DESCRIPTIONS,
  USER_ROLE_FILTER_ALL_ICON,
  USER_ROLE_ICONS,
  USER_ROLE_LABELS,
} from "@/lib/admin/user-role"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Badge } from "@/components/ui/badge"
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

const ROLE_OPTIONS: AdminUserRole[] = ["admin", "user", "guest", "suspended"]

const USER_SORT_OPTIONS: AdminListSortOption[] = [
  { value: "-created_at", label: "Création (récent)" },
  { value: "created_at", label: "Création (ancien)" },
  { value: "name", label: "Nom (A→Z)" },
  { value: "-name", label: "Nom (Z→A)" },
  { value: "email", label: "E-mail (A→Z)" },
  { value: "-email", label: "E-mail (Z→A)" },
  { value: "-updated_at", label: "Mise à jour (récent)" },
  { value: "updated_at", label: "Mise à jour (ancien)" },
]

export function UsersSection() {
  const [q, setQ] = useState("")
  const [role, setRole] = useState<string>("all")
  const [groupId, setGroupId] = useState<string>("all")
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(25)
  const [sort, setSort] = useState("-created_at")
  const [inviteOpen, setInviteOpen] = useState(false)
  const [groupsOpen, setGroupsOpen] = useState(false)
  const [selectedId, setSelectedId] = useState<string | null>(null)
  const [selectedIds, setSelectedIds] = useState<string[]>([])

  const queryParams = useMemo(
    () => ({
      page,
      page_size: pageSize,
      sort,
      q: q.trim() || undefined,
      role: role === "all" ? undefined : role,
      group_id: groupId === "all" ? undefined : groupId,
    }),
    [page, pageSize, sort, q, role, groupId]
  )

  const { data: groupsData } = useAdminUserGroups({ page: 1, page_size: 200 })
  const groups = groupsData?.groups ?? []

  const { data, isFetching, isError, refetch } = useAdminUsers(queryParams)
  const users = data?.users
  const total = data?.pagination.total ?? 0
  const resolvedPageSize = data?.pagination.page_size ?? pageSize
  const totalPages = Math.max(1, Math.ceil(total / resolvedPageSize))

  const pageUserIds = useMemo(() => (users ?? []).map((user) => user.id), [users])
  const pageUserIdsKey = pageUserIds.join(",")
  const allPageSelected =
    pageUserIds.length > 0 && pageUserIds.every((id) => selectedIds.includes(id))
  const somePageSelected =
    pageUserIds.some((id) => selectedIds.includes(id)) && !allPageSelected

  useEffect(() => {
    const ids = pageUserIdsKey.length > 0 ? pageUserIdsKey.split(",") : []
    setSelectedIds((prev) => {
      const next = prev.filter((id) => ids.includes(id))
      if (next.length === prev.length && next.every((id, index) => id === prev[index])) {
        return prev
      }
      return next
    })
  }, [pageUserIdsKey])

  function toggleUser(id: string, checked: boolean) {
    setSelectedIds((prev) =>
      checked ? Array.from(new Set([...prev, id])) : prev.filter((value) => value !== id)
    )
  }

  function togglePage(checked: boolean) {
    if (checked) {
      setSelectedIds((prev) => Array.from(new Set([...prev, ...pageUserIds])))
      return
    }
    setSelectedIds((prev) => prev.filter((id) => !pageUserIds.includes(id)))
  }

  return (
    <>
      <SettingsSectionHeader
        title="Utilisateurs"
        description="Comptes, groupes, types d'utilisateur, invitations et quotas."
      />
      <SettingsSyncBanner isFetching={isFetching} isError={isError} onRetry={() => refetch()} />

      <div className="mb-4 flex flex-wrap items-end gap-3">
        <div className="min-w-[200px] flex-1">
          <Label className="text-xs">Recherche</Label>
          <Input
            className="mt-1 h-9"
            value={q}
            onChange={(e) => {
              setQ(e.target.value)
              setPage(1)
            }}
            placeholder="E-mail, nom ou ID externe"
          />
        </div>
        <div className="w-52">
          <Label className="text-xs">Type d&apos;utilisateur</Label>
          <Select
            value={role}
            onValueChange={(v) => {
              setRole(v)
              setPage(1)
            }}
          >
            <SelectTrigger className="mt-1 h-9">
              <SelectValue placeholder="Type d'utilisateur" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">
                <UserRoleLabel role="all" />
              </SelectItem>
              {ROLE_OPTIONS.map((option) => (
                <SelectItem key={option} value={option}>
                  <UserRoleLabel role={option} />
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div className="w-52">
          <Label className="text-xs">Groupe</Label>
          <Select
            value={groupId}
            onValueChange={(v) => {
              setGroupId(v)
              setPage(1)
            }}
          >
            <SelectTrigger className="mt-1 h-9">
              <SelectValue placeholder="Groupe" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">
                <span className="flex items-center gap-2">
                  <UsersRound className="size-4 opacity-80" />
                  Tous les groupes
                </span>
              </SelectItem>
              {groups.map((group) => (
                <SelectItem key={group.id} value={group.id}>
                  {group.name}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <Button variant="outline" className="h-9" onClick={() => setGroupsOpen(true)}>
          <UsersRound className="mr-2 size-4" />
          Groupes
        </Button>
        <Button className="h-9" onClick={() => setInviteOpen(true)}>
          <UserPlus className="mr-2 size-4" />
          Inviter
        </Button>
      </div>

      <UsersBulkToolbar
        selectedIds={selectedIds}
        groups={groups}
        onClear={() => setSelectedIds([])}
      />

      <AdminListControls
        page={page}
        pageSize={resolvedPageSize}
        total={total}
        totalPages={totalPages}
        sort={sort}
        sortOptions={USER_SORT_OPTIONS}
        onPageChange={setPage}
        onPageSizeChange={(next) => {
          setPageSize(next)
          setPage(1)
        }}
        onSortChange={(next) => {
          setSort(next)
          setPage(1)
        }}
        itemLabel="utilisateur(s)"
      />

      <div className="overflow-x-auto rounded-lg border">
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead className="w-10">
                <Checkbox
                  checked={allPageSelected ? true : somePageSelected ? "indeterminate" : false}
                  onCheckedChange={(checked) => togglePage(checked === true)}
                  aria-label="Sélectionner la page"
                />
              </TableHead>
              <TableHead>Utilisateur</TableHead>
              <TableHead>Type</TableHead>
              <TableHead className="hidden xl:table-cell">Groupes</TableHead>
              <TableHead className="hidden lg:table-cell">Mail</TableHead>
              <TableHead className="hidden lg:table-cell">Drive</TableHead>
              <TableHead className="hidden md:table-cell">ID externe</TableHead>
              <TableHead className="w-12" />
            </TableRow>
          </TableHeader>
          <TableBody>
            {(users ?? []).length === 0 ? (
              <TableRow>
                <TableCell colSpan={8} className="text-center text-muted-foreground">
                  Aucun utilisateur trouvé.
                </TableCell>
              </TableRow>
            ) : (
              (users ?? []).map((user) => (
                <UserRow
                  key={user.id}
                  user={user}
                  selected={selectedIds.includes(user.id)}
                  onToggleSelect={(checked) => toggleUser(user.id, checked)}
                  onOpen={() => setSelectedId(user.id)}
                />
              ))
            )}
          </TableBody>
        </Table>
      </div>

      <InviteUserDialog open={inviteOpen} onOpenChange={setInviteOpen} />
      <UsersGroupsDialog open={groupsOpen} onOpenChange={setGroupsOpen} />
      <UserDetailSheet userId={selectedId} onClose={() => setSelectedId(null)} />
    </>
  )
}

function UserRow({
  user,
  selected,
  onToggleSelect,
  onOpen,
}: {
  user: AdminUser
  selected: boolean
  onToggleSelect: (checked: boolean) => void
  onOpen: () => void
}) {
  const disableUser = useDisableAdminUser()
  const reactivateUser = useReactivateAdminUser()
  const deleteUser = useDeleteAdminUser()

  return (
    <TableRow className="cursor-pointer">
      <TableCell onClick={(e) => e.stopPropagation()}>
        <Checkbox
          checked={selected}
          onCheckedChange={(checked) => onToggleSelect(checked === true)}
          aria-label={`Sélectionner ${user.email}`}
        />
      </TableCell>
      <TableCell onClick={onOpen}>
        <div className="font-medium">{user.name || "—"}</div>
        <div className="text-xs text-muted-foreground">{user.email}</div>
      </TableCell>
      <TableCell onClick={onOpen}>
        <RoleBadge role={resolveUserRole(user)} />
      </TableCell>
      <TableCell className="hidden xl:table-cell" onClick={onOpen}>
        <UserGroupsBadges groups={user.groups ?? []} />
      </TableCell>
      <TableCell className="hidden text-xs text-muted-foreground lg:table-cell" onClick={onOpen}>
        {formatBytes(user.storage?.mail_used_bytes ?? 0)}
      </TableCell>
      <TableCell className="hidden text-xs text-muted-foreground lg:table-cell" onClick={onOpen}>
        {formatBytes(user.storage?.drive_used_bytes ?? 0)}
      </TableCell>
      <TableCell
        className="hidden max-w-[200px] truncate font-mono text-xs md:table-cell"
        onClick={onOpen}
      >
        {user.external_id}
      </TableCell>
      <TableCell onClick={(e) => e.stopPropagation()}>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="ghost" size="icon" className="size-8">
              <MoreHorizontal className="size-4" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuItem onClick={onOpen}>Détails et quotas</DropdownMenuItem>
            {resolveUserRole(user) !== "suspended" ? (
              <DropdownMenuItem
                onClick={() => void disableUser.mutateAsync(user.id)}
              >
                Suspendre
              </DropdownMenuItem>
            ) : (
              <DropdownMenuItem
                onClick={() => void reactivateUser.mutateAsync(user.id)}
              >
                Réactiver
              </DropdownMenuItem>
            )}
            <DropdownMenuSeparator />
            <DropdownMenuItem
              className="text-destructive"
              onClick={() => {
                if (confirm(`Supprimer définitivement ${user.email} ?`)) {
                  void deleteUser.mutateAsync(user.id)
                }
              }}
            >
              Supprimer
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </TableCell>
    </TableRow>
  )
}

function UserGroupsBadges({ groups }: { groups: AdminUser["groups"] }) {
  if (!groups?.length) {
    return <span className="text-xs text-muted-foreground">—</span>
  }
  const visible = groups.slice(0, 2)
  const extra = groups.length - visible.length
  return (
    <div className="flex flex-wrap gap-1">
      {visible.map((group) => (
        <Badge key={group.id} variant="outline" className="text-xs font-normal">
          {group.name}
        </Badge>
      ))}
      {extra > 0 ? (
        <Badge variant="secondary" className="text-xs font-normal">
          +{extra}
        </Badge>
      ) : null}
    </div>
  )
}

function UserRoleLabel({
  role,
  className,
}: {
  role: AdminUserRole | "all"
  className?: string
}) {
  const Icon =
    role === "all" ? USER_ROLE_FILTER_ALL_ICON : USER_ROLE_ICONS[role]
  const label = role === "all" ? "Tous les types" : USER_ROLE_LABELS[role]

  return (
    <span className={cn("flex items-center gap-2", className)}>
      <Icon className="size-4 shrink-0 opacity-80" aria-hidden />
      <span>{label}</span>
    </span>
  )
}

function RoleBadge({ role }: { role: AdminUserRole }) {
  const variant =
    role === "admin"
      ? "default"
      : role === "user"
        ? "secondary"
        : role === "guest"
          ? "outline"
          : "destructive"
  const Icon = USER_ROLE_ICONS[role]
  return (
    <Badge variant={variant} className="gap-1.5 pr-2.5">
      <Icon className="size-3.5" aria-hidden />
      {USER_ROLE_LABELS[role] ?? role}
    </Badge>
  )
}

function InviteUserDialog({
  open,
  onOpenChange,
}: {
  open: boolean
  onOpenChange: (open: boolean) => void
}) {
  const invite = useInviteAdminUser()
  const [email, setEmail] = useState("")
  const [name, setName] = useState("")

  async function submit() {
    await invite.mutateAsync({ email, name: name || undefined })
    setEmail("")
    setName("")
    onOpenChange(false)
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Inviter un utilisateur</DialogTitle>
        </DialogHeader>
        <div className="space-y-3">
          <div>
            <Label>E-mail</Label>
            <Input
              className="mt-1"
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
            />
          </div>
          <div>
            <Label>Nom (optionnel)</Label>
            <Input
              className="mt-1"
              value={name}
              onChange={(e) => setName(e.target.value)}
            />
          </div>
        </div>
        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Annuler
          </Button>
          <Button disabled={!email || invite.isPending} onClick={() => void submit()}>
            Envoyer l&apos;invitation
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

function UserDetailSheet({
  userId,
  onClose,
}: {
  userId: string | null
  onClose: () => void
}) {
  const { data: user, isFetching } = useAdminUser(userId)
  const updateUser = useUpdateAdminUser(userId ?? "")
  const setRole = useSetAdminUserRole(userId ?? "")
  const setQuota = useSetAdminUserQuota(userId ?? "")
  const setAiPolicy = useUpdateUserAICostPolicy(userId ?? "")
  const [name, setName] = useState("")
  const [email, setEmail] = useState("")
  const [selectedRole, setSelectedRole] = useState<AdminUserRole>("user")
  const [mailGib, setMailGib] = useState("5")
  const [driveGib, setDriveGib] = useState("5")
  const [photosGib, setPhotosGib] = useState("5")
  const [aiDailyEur, setAiDailyEur] = useState("")
  const [aiMonthlyEur, setAiMonthlyEur] = useState("")

  const open = Boolean(userId)

  useEffect(() => {
    if (!user) return
    setName(user.name ?? "")
    setEmail(user.email ?? "")
    setSelectedRole(resolveUserRole(user))
    if (user.quota) {
      setMailGib(String(bytesToGib(user.quota.mail.max_storage_bytes).toFixed(1)))
      setDriveGib(String(bytesToGib(user.quota.drive.max_storage_bytes).toFixed(1)))
      setPhotosGib(String(bytesToGib(user.quota.photos.max_storage_bytes).toFixed(1)))
    }
  }, [user])

  async function saveProfile() {
    if (!userId) return
    await updateUser.mutateAsync({ name, email })
  }

  async function saveRole() {
    if (!userId || !user || selectedRole === resolveUserRole(user)) return
    await setRole.mutateAsync({ role: selectedRole })
  }

  async function saveQuotas() {
    if (!userId) return
    await setQuota.mutateAsync({
      mail_max_storage_bytes: gibToBytes(Number(mailGib)),
      drive_max_storage_bytes: gibToBytes(Number(driveGib)),
      photos_max_storage_bytes: gibToBytes(Number(photosGib)),
    })
  }

  async function saveAiPolicy() {
    if (!userId) return
    await setAiPolicy.mutateAsync({
      daily_limit_eur: aiDailyEur.trim() === "" ? null : Number(aiDailyEur),
      monthly_limit_eur: aiMonthlyEur.trim() === "" ? null : Number(aiMonthlyEur),
    })
  }

  return (
    <Sheet open={open} onOpenChange={(v) => !v && onClose()}>
      <SheetContent className="flex flex-col gap-0 overflow-y-auto p-0 sm:max-w-lg">
        <SheetHeader className="border-b px-6 py-5">
          <SheetTitle>Détails utilisateur</SheetTitle>
        </SheetHeader>

        {isFetching || !user ? (
          <p className="px-6 py-5 text-sm text-muted-foreground">Chargement…</p>
        ) : (
          <div className="space-y-8 px-6 py-6">
            <div className="space-y-4">
              <RoleBadge role={resolveUserRole(user)} />
              {user.groups?.length ? (
                <div className="space-y-2">
                  <Label>Groupes</Label>
                  <UserGroupsBadges groups={user.groups} />
                </div>
              ) : null}
              <div className="space-y-2">
                <Label>Type d&apos;utilisateur</Label>
                <Select
                  value={selectedRole}
                  onValueChange={(v) => setSelectedRole(v as AdminUserRole)}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Type d'utilisateur" />
                  </SelectTrigger>
                  <SelectContent>
                    {ROLE_OPTIONS.map((option) => (
                      <SelectItem key={option} value={option}>
                        <UserRoleLabel role={option} />
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <p className="text-xs text-muted-foreground">
                  {USER_ROLE_DESCRIPTIONS[selectedRole]}
                </p>
                <Button
                  size="sm"
                  variant="secondary"
                  onClick={() => void saveRole()}
                  disabled={setRole.isPending || selectedRole === resolveUserRole(user)}
                >
                  Enregistrer le type
                </Button>
              </div>
              <div className="space-y-2">
                <Label>Nom</Label>
                <Input value={name} onChange={(e) => setName(e.target.value)} />
              </div>
              <div className="space-y-2">
                <Label>E-mail</Label>
                <Input value={email} onChange={(e) => setEmail(e.target.value)} />
              </div>
              <Button size="sm" onClick={() => void saveProfile()} disabled={updateUser.isPending}>
                Mettre à jour le profil
              </Button>
            </div>

            {user.quota ? (
              <div className="space-y-5 rounded-lg border bg-muted/20 p-5">
                <h3 className="text-sm font-medium">Quotas stockage</h3>
                <QuotaField
                  label="Mail"
                  used={coerceBytes(user.quota.mail.used_storage_bytes)}
                  max={coerceBytes(user.quota.mail.max_storage_bytes)}
                  gib={mailGib}
                  onGibChange={setMailGib}
                  count={user.quota.mail.count}
                />
                <QuotaField
                  label="Drive"
                  used={coerceBytes(user.quota.drive.used_storage_bytes)}
                  max={coerceBytes(user.quota.drive.max_storage_bytes)}
                  gib={driveGib}
                  onGibChange={setDriveGib}
                />
                <QuotaField
                  label="Photos"
                  used={coerceBytes(user.quota.photos.used_storage_bytes)}
                  max={coerceBytes(user.quota.photos.max_storage_bytes)}
                  gib={photosGib}
                  onGibChange={setPhotosGib}
                />
                <Button size="sm" onClick={() => void saveQuotas()} disabled={setQuota.isPending}>
                  Enregistrer les quotas
                </Button>
              </div>
            ) : null}

            <div className="space-y-4 rounded-lg border bg-muted/20 p-5">
              <h3 className="text-sm font-medium">Plafond IA (clé org)</h3>
              <p className="text-xs text-muted-foreground">
                Override utilisateur. Laissez vide pour hériter des plafonds org/groupe.
              </p>
              <div className="grid gap-3 sm:grid-cols-2">
                <div className="space-y-2">
                  <Label>Journalier (€)</Label>
                  <Input
                    type="number"
                    min={0}
                    step={0.5}
                    placeholder="Hérité"
                    value={aiDailyEur}
                    onChange={(e) => setAiDailyEur(e.target.value)}
                  />
                </div>
                <div className="space-y-2">
                  <Label>Mensuel (€)</Label>
                  <Input
                    type="number"
                    min={0}
                    step={1}
                    placeholder="Hérité"
                    value={aiMonthlyEur}
                    onChange={(e) => setAiMonthlyEur(e.target.value)}
                  />
                </div>
              </div>
              <Button size="sm" variant="secondary" onClick={() => void saveAiPolicy()} disabled={setAiPolicy.isPending}>
                Enregistrer le plafond IA
              </Button>
            </div>

            <p className="font-mono text-xs text-muted-foreground">ID : {user.id}</p>
          </div>
        )}
      </SheetContent>
    </Sheet>
  )
}

function coerceBytes(value: unknown): number {
  const n = typeof value === "number" ? value : Number(value)
  return Number.isFinite(n) && n >= 0 ? n : 0
}

function QuotaField({
  label,
  used,
  max,
  gib,
  onGibChange,
  count,
}: {
  label: string
  used: number
  max: number
  gib: string
  onGibChange: (v: string) => void
  count?: number
}) {
  const maxBytes = max > 0 ? max : gibToBytes(Number(gib) || 0)
  const pct = maxBytes > 0 ? Math.min(100, Math.round((used / maxBytes) * 100)) : 0

  return (
    <div className="space-y-2">
      <div className="flex items-center justify-between gap-3 text-xs">
        <span className="font-medium text-foreground">{label}</span>
        <span className="text-right text-muted-foreground">
          {formatBytes(used)} / {formatBytes(maxBytes)}
          {count !== undefined ? ` · ${count} messages` : ""}
        </span>
      </div>
      <div className="h-1.5 overflow-hidden rounded-full bg-muted">
        <div
          className="h-full rounded-full bg-primary transition-all"
          style={{ width: `${pct}%` }}
        />
      </div>
      <div className="flex items-center gap-2">
        <Label className="sr-only">Quota {label}</Label>
        <Input
          type="number"
          min={0}
          step={0.5}
          className="h-9"
          value={gib}
          onChange={(e) => onGibChange(e.target.value)}
        />
        <span className="shrink-0 text-sm text-muted-foreground">Go max</span>
      </div>
    </div>
  )
}
