"use client";

import Link from "next/link";
import { useEffect, useMemo, useState } from "react";
import {
  Activity,
  AlertTriangle,
  BadgePercent,
  BadgeCheck,
  Banknote,
  BarChart3,
  Bitcoin,
  CalendarClock,
  CircleDollarSign,
  Clock3,
  Dice5,
  Gauge,
  Landmark,
  ListChecks,
  Loader2,
  LockKeyhole,
  MessageCircle,
  Radio,
  Search,
  ShieldAlert,
  ShieldCheck,
  SlidersHorizontal,
  TicketCheck,
  TrendingUp,
  UserCog,
  UsersRound,
  WalletCards,
  XCircle
} from "lucide-react";
import { cn } from "@/lib/utils";
import { AdminKycDashboard } from "@/components/admin-kyc-dashboard";
import { AdminSupportDashboard } from "@/components/admin-support-dashboard";

type AdminSummary = {
  generatedAt: string;
  users: {
    total: number;
    active: number;
    newToday: number;
    suspended: number;
    selfExcluded: number;
  };
  kyc: {
    pending: number;
    approved: number;
    rejected: number;
  };
  sportsbook: {
    openBets: number;
    openStake: string;
    openLiability: string;
    ticketsToday: number;
    stakeToday: string;
    payoutToday: string;
    ggrToday: string;
    liveEvents: number;
    scheduledEvents: number;
    openMarkets: number;
    suspendedMarkets: number;
  };
  casino: {
    roundsToday: number;
    stakeToday: string;
    payoutToday: string;
    ggrToday: string;
    activeRounds: number;
    wonToday: number;
    lostToday: number;
    voidToday: number;
  };
  revenue: {
    ggrToday: string;
  };
  payments: {
    pendingWithdrawals: number;
    pendingWithdrawalAmount: string;
    withdrawalsToday: number;
    withdrawalsTodayAmount: string;
    pendingDeposits: number;
    pendingDepositAmount: string;
    depositsToday: number;
    depositsTodayAmount: string;
  };
  balances: {
    available: string;
    bonus: string;
  };
  promotions: {
    active: number;
    activeUserBonuses: number;
  };
  risk: {
    open: number;
    high: number;
    critical: number;
  };
  platform: {
    ledgerEntries: number;
    auditLogs24h: number;
    providerFailures24h: number;
    avgProviderLatencyMs: number;
  };
};

type AdminUser = {
  id: string;
  email: string;
  username: string;
  status: string;
  roles: string[];
  country?: string;
  currency: string;
  createdAt: string;
  lastLoginAt?: string | null;
  kycStatus: string;
  vipTier?: string;
  availableBalance: string;
  bonusBalance: string;
  tickets: number;
  withdrawals: number;
  riskEvents: number;
  notes: number;
};

type CryptoOperations = {
  deposits: Array<{
    id: string;
    userEmail: string;
    asset: string;
    network: string;
    txHash: string;
    cryptoAmount: string;
    eurAmount: string | null;
    confirmations: number;
    requiredConfirmations: number;
    status: string;
    createdAt: string;
  }>;
  withdrawals: Array<{
    id: string;
    userEmail: string;
    asset: string;
    network: string;
    destinationAddress: string;
    eurAmount: string;
    feeEur: string;
    totalDebitEur: string;
    cryptoAmount: string;
    eurRate: string;
    status: string;
    txHash?: string | null;
    createdAt: string;
  }>;
};

type AdminPromotion = {
  code: string;
  name: string;
  status: string;
  currency: string;
  matchPercent: number;
  maxBonusAmount: string;
  wageringMultiplier: string;
  terms: string;
};

type AdminBoostedOdd = {
  id: string;
  title: string;
  category: AdminBoostedOddCategory;
  sportSlug: string;
  sportName: string;
  competitionName: string;
  competitionCountry: string;
  teamA: string;
  teamB: string;
  startsAt: string;
  betLabel: string;
  originalOdds: string;
  boostedOdds: string;
  maxStake: string;
  allowCombinations: boolean;
  terms: string;
  status: string;
  sortOrder: number;
  selectionId: string;
  oddsVersion: number;
  openTickets: number;
};

type AdminBoostedOddCategory = {
  id: string;
  name: string;
  slug: string;
  status: string;
  sortOrder: number;
};

type AdminSportsPagePromotion = {
  id: string;
  title: string;
  subtitle: string | null;
  badge: string | null;
  imageUrl: string;
  href: string;
  status: string;
  sortOrder: number;
  startsAt: string;
  endsAt: string | null;
  createdAt: string;
  updatedAt: string;
};

const statuses = ["ALL", "ACTIVE", "PENDING_EMAIL", "SUSPENDED", "SELF_EXCLUDED", "CLOSED"] as const;
const mutableStatuses = ["ACTIVE", "SUSPENDED", "CLOSED", "SELF_EXCLUDED"] as const;

export type AdminSection = "overview" | "players" | "kyc" | "support" | "trading" | "sport-promos" | "bonus" | "finance";

export const adminSections: AdminSection[] = ["overview", "players", "kyc", "support", "trading", "sport-promos", "bonus", "finance"];

const adminNavigation: Array<{ section: AdminSection; href: string; label: string; icon: typeof ShieldCheck }> = [
  { section: "overview", href: "/admin", label: "Vue d'ensemble", icon: BarChart3 },
  { section: "players", href: "/admin/players", label: "Joueurs", icon: UsersRound },
  { section: "kyc", href: "/admin/kyc", label: "KYC", icon: BadgeCheck },
  { section: "support", href: "/admin/support", label: "Support", icon: MessageCircle },
  { section: "trading", href: "/admin/trading", label: "Trading & boosts", icon: BadgePercent },
  { section: "sport-promos", href: "/admin/sport-promos", label: "Promos sport", icon: TicketCheck },
  { section: "bonus", href: "/admin/bonus", label: "Bonus", icon: CircleDollarSign },
  { section: "finance", href: "/admin/finance", label: "Finance crypto", icon: Bitcoin }
];

export function AdminDashboard({ section = "overview" }: { section?: AdminSection }) {
  const activeSection = adminSections.includes(section) ? section : "overview";
  const activeNavigation = adminNavigation.find((item) => item.section === activeSection) ?? adminNavigation[0];
  const [summary, setSummary] = useState<AdminSummary | null>(null);
  const [users, setUsers] = useState<AdminUser[]>([]);
  const [cryptoOps, setCryptoOps] = useState<CryptoOperations | null>(null);
  const [promotions, setPromotions] = useState<AdminPromotion[]>([]);
  const [boostedOdds, setBoostedOdds] = useState<AdminBoostedOdd[]>([]);
  const [boostCategories, setBoostCategories] = useState<AdminBoostedOddCategory[]>([]);
  const [sportsPromos, setSportsPromos] = useState<AdminSportsPagePromotion[]>([]);
  const [message, setMessage] = useState("");
  const [loading, setLoading] = useState(true);
  const [query, setQuery] = useState("");
  const [status, setStatus] = useState<(typeof statuses)[number]>("ALL");
  const [savingUserId, setSavingUserId] = useState<string | null>(null);
  const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
  const [actionLoading, setActionLoading] = useState<"deposit" | "bonus" | "kyc" | null>(null);
  const [cryptoActionId, setCryptoActionId] = useState<string | null>(null);
  const [broadcastHashes, setBroadcastHashes] = useState<Record<string, string>>({});
  const [feedback, setFeedback] = useState("");
  const [depositAmount, setDepositAmount] = useState("100");
  const [depositReason, setDepositReason] = useState("Depot manuel admin");
  const [bonusAmount, setBonusAmount] = useState("300");
  const [bonusTitle, setBonusTitle] = useState("Bonus manuel");
  const [bonusWager, setBonusWager] = useState("1");
  const [bonusTerms, setBonusTerms] = useState("Bonus offert par le support. Conditions de mise indiquees avant acceptation.");
  const [promoActionLoading, setPromoActionLoading] = useState<"sport" | "code" | "delete" | null>(null);
  const [sportMatchPercent, setSportMatchPercent] = useState("300");
  const [sportMaxBonus, setSportMaxBonus] = useState("1000");
  const [sportWager, setSportWager] = useState("1");
  const [sportTerms, setSportTerms] = useState("Bonus sport crédité automatiquement sur le premier dépôt éligible.");
  const [promoCode, setPromoCode] = useState("AZIA");
  const [promoName, setPromoName] = useState("Code promo AZIA");
  const [promoMatchPercent, setPromoMatchPercent] = useState("500");
  const [promoMaxBonus, setPromoMaxBonus] = useState("2500");
  const [promoWager, setPromoWager] = useState("1");
  const [promoTerms, setPromoTerms] = useState("Code promotionnel crédité automatiquement sur le premier dépôt éligible.");
  const [boostActionLoading, setBoostActionLoading] = useState<string | null>(null);
  const [boostEditingId, setBoostEditingId] = useState<string | null>(null);
  const [boostCategoryId, setBoostCategoryId] = useState("");
  const [categoryEditingId, setCategoryEditingId] = useState<string | null>(null);
  const [categoryName, setCategoryName] = useState("World Cup Boosts!");
  const [categoryStatus, setCategoryStatus] = useState("ACTIVE");
  const [categorySortOrder, setCategorySortOrder] = useState("10");
  const [boostSportSlug, setBoostSportSlug] = useState("football");
  const [boostSportName, setBoostSportName] = useState("Football");
  const [boostCompetitionName, setBoostCompetitionName] = useState("World Cup Boosts");
  const [boostCompetitionCountry, setBoostCompetitionCountry] = useState("International");
  const [boostTeamA, setBoostTeamA] = useState("Argentine");
  const [boostTeamB, setBoostTeamB] = useState("Egypte");
  const [boostStartsAt, setBoostStartsAt] = useState(defaultDateTimeLocal());
  const [boostBetLabel, setBoostBetLabel] = useState("Mohamed Salah 3+ tirs");
  const [boostOriginalOdds, setBoostOriginalOdds] = useState("2.32");
  const [boostedOddsValue, setBoostedOddsValue] = useState("2.80");
  const [boostMaxStake, setBoostMaxStake] = useState("100");
  const [boostAllowCombinations, setBoostAllowCombinations] = useState(false);
  const [boostTerms, setBoostTerms] = useState("Temps réglementaire uniquement");
  const [boostStatus, setBoostStatus] = useState("ACTIVE");
  const [boostSortOrder, setBoostSortOrder] = useState("10");
  const [sportsPromoActionLoading, setSportsPromoActionLoading] = useState<string | null>(null);
  const [sportsPromoEditingId, setSportsPromoEditingId] = useState<string | null>(null);
  const [sportsPromoTitle, setSportsPromoTitle] = useState("Cotes boostées du jour");
  const [sportsPromoSubtitle, setSportsPromoSubtitle] = useState("Sélection sport mise en avant par ZiraBet.");
  const [sportsPromoBadge, setSportsPromoBadge] = useState("Sport");
  const [sportsPromoImageUrl, setSportsPromoImageUrl] = useState("/images/home/promo-sport-boosts.png");
  const [sportsPromoHref, setSportsPromoHref] = useState("/sports#cote-boostee");
  const [sportsPromoStatus, setSportsPromoStatus] = useState("ACTIVE");
  const [sportsPromoSortOrder, setSportsPromoSortOrder] = useState("10");
  const [sportsPromoStartsAt, setSportsPromoStartsAt] = useState(defaultDateTimeLocal());
  const [sportsPromoEndsAt, setSportsPromoEndsAt] = useState("");

  useEffect(() => {
    void loadDashboard();
  }, []);

  useEffect(() => {
    if (!selectedUserId && users.length) {
      setSelectedUserId(users[0].id);
    }
  }, [selectedUserId, users]);

  async function loadDashboard() {
    setLoading(true);
    setMessage("");
    setFeedback("");
    if (activeSection === "kyc" || activeSection === "support") {
      setLoading(false);
      return;
    }
    const [summaryResponse, usersResponse, cryptoResponse, promotionsResponse, boostedResponse, sportsPromosResponse] = await Promise.all([
      fetch("/api/admin/summary"),
      fetch("/api/admin/users"),
      fetch("/api/admin/crypto"),
      fetch("/api/admin/promotions"),
      fetch("/api/admin/boosted-odds"),
      fetch("/api/admin/sports-promotions")
    ]);
    const [summaryPayload, usersPayload, cryptoPayload, promotionsPayload, boostedPayload, sportsPromosPayload] = await Promise.all([
      summaryResponse.json(),
      usersResponse.json(),
      cryptoResponse.json(),
      promotionsResponse.json(),
      boostedResponse.json(),
      sportsPromosResponse.json()
    ]);

    if (summaryPayload.ok) {
      setSummary(summaryPayload.data);
    } else {
      setMessage(summaryPayload.error?.message ?? "Accès admin requis");
    }

    if (usersPayload.ok) {
      setUsers(usersPayload.data.users);
    } else if (!message) {
      setMessage(usersPayload.error?.message ?? "Accès gestion joueurs requis");
    }

    if (cryptoPayload.ok) {
      setCryptoOps(cryptoPayload.data);
    }

    if (promotionsPayload.ok) {
      const nextPromotions = promotionsPayload.data.promotions as AdminPromotion[];
      setPromotions(nextPromotions);
      const sportPromotion = nextPromotions.find((promotion) => promotion.code === "WELCOME_SPORT");
      if (sportPromotion) {
        setSportMatchPercent(String(sportPromotion.matchPercent));
        setSportMaxBonus(sportPromotion.maxBonusAmount);
        setSportWager(sportPromotion.wageringMultiplier);
        setSportTerms(sportPromotion.terms);
      }
    }

    if (boostedPayload.ok) {
      setBoostedOdds(boostedPayload.data.boostedOdds as AdminBoostedOdd[]);
      const categories = boostedPayload.data.categories as AdminBoostedOddCategory[];
      setBoostCategories(categories);
      if (!boostCategoryId && categories.length) {
        setBoostCategoryId(categories[0].id);
      }
    }

    if (sportsPromosPayload.ok) {
      setSportsPromos(sportsPromosPayload.data.promotions as AdminSportsPagePromotion[]);
    }

    setLoading(false);
  }

  async function updateUserStatus(userId: string, nextStatus: string) {
    setSavingUserId(userId);
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/users", {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ userId, status: nextStatus })
    });
    const payload = await response.json();

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Modification impossible");
      setSavingUserId(null);
      return;
    }

    await loadDashboard();
    setFeedback("Statut joueur mis à jour.");
    setSavingUserId(null);
  }

  const filteredUsers = useMemo(() => {
    const normalizedQuery = query.trim().toLowerCase();
    return users.filter((user) => {
      const matchesStatus = status === "ALL" || user.status === status;
      const matchesQuery =
        !normalizedQuery ||
        [user.email, user.username, user.country, user.kycStatus, user.vipTier].some((value) => value?.toLowerCase().includes(normalizedQuery));
      return matchesStatus && matchesQuery;
    });
  }, [query, status, users]);

  const selectedUser = users.find((user) => user.id === selectedUserId) ?? filteredUsers[0] ?? users[0];

  async function creditManualDeposit() {
    if (!selectedUser) return;
    setActionLoading("deposit");
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/wallet-adjustments", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        userId: selectedUser.id,
        currency: selectedUser.currency,
        accountType: "AVAILABLE",
        direction: "CREDIT",
        amount: depositAmount,
        reason: depositReason
      })
    });
    const payload = await response.json();
    setActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Dépôt manuel impossible");
      return;
    }

    await loadDashboard();
    setFeedback(`Dépôt manuel de ${money(depositAmount)} crédité à ${selectedUser.email}.`);
  }

  async function grantBonusOffer() {
    if (!selectedUser) return;
    setActionLoading("bonus");
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/bonuses/grant", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        userId: selectedUser.id,
        currency: selectedUser.currency,
        amount: bonusAmount,
        title: bonusTitle,
        wagerMultiplier: bonusWager,
        terms: bonusTerms
      })
    });
    const payload = await response.json();
    setActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Attribution bonus impossible");
      return;
    }

    await loadDashboard();
    setFeedback(`Bonus de ${money(bonusAmount)} proposé à ${selectedUser.email}.`);
  }

  async function requestKycVerification() {
    if (!selectedUser) return;
    setActionLoading("kyc");
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/kyc/request", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        userId: selectedUser.id,
        reason: "Vérification requise par le support."
      })
    });
    const payload = await response.json();
    setActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Demande de vérification impossible");
      return;
    }

    await loadDashboard();
    setFeedback(`Vérification demandée à ${selectedUser.email}.`);
  }

  async function reviewCryptoWithdrawal(withdrawalId: string, action: "approve" | "reject" | "mark_broadcasted") {
    setCryptoActionId(withdrawalId);
    setMessage("");
    setFeedback("");

    const response = await fetch(`/api/admin/crypto/withdrawals/${withdrawalId}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        action,
        reason: action === "reject" ? "Retrait refusé par la finance" : "Validation finance",
        txHash: action === "mark_broadcasted" ? broadcastHashes[withdrawalId] : undefined
      })
    });
    const payload = await response.json();
    setCryptoActionId(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Action crypto impossible");
      return;
    }

    await loadDashboard();
    setFeedback("Retrait crypto mis à jour.");
  }

  async function saveWelcomeSport() {
    setPromoActionLoading("sport");
    setMessage("");
    setFeedback("");
    const response = await fetch("/api/admin/promotions", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        code: "WELCOME_SPORT",
        name: "Sport Bonus de premier dépôt",
        status: "ACTIVE",
        matchPercent: sportMatchPercent,
        maxBonusAmount: sportMaxBonus,
        wageringMultiplier: sportWager,
        terms: sportTerms
      })
    });
    const payload = await response.json();
    setPromoActionLoading(null);
    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Configuration bonus sport impossible");
      return;
    }
    await loadDashboard();
    setFeedback("Offre Sport mise à jour.");
  }

  async function savePromoCode() {
    setPromoActionLoading("code");
    setMessage("");
    setFeedback("");
    const response = await fetch("/api/admin/promotions", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        code: promoCode,
        name: promoName,
        status: "ACTIVE",
        matchPercent: promoMatchPercent,
        maxBonusAmount: promoMaxBonus,
        wageringMultiplier: promoWager,
        terms: promoTerms
      })
    });
    const payload = await response.json();
    setPromoActionLoading(null);
    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Création du code promo impossible");
      return;
    }
    await loadDashboard();
    setFeedback(`Code promo ${promoCode.toUpperCase()} enregistré.`);
  }

  function editPromoCode(promotion: AdminPromotion) {
    setPromoCode(promotion.code);
    setPromoName(promotion.name);
    setPromoMatchPercent(String(promotion.matchPercent));
    setPromoMaxBonus(promotion.maxBonusAmount);
    setPromoWager(promotion.wageringMultiplier);
    setPromoTerms(promotion.terms);
    setFeedback(`Modification du code ${promotion.code}.`);
  }

  function resetPromoForm() {
    setPromoCode("");
    setPromoName("");
    setPromoMatchPercent("100");
    setPromoMaxBonus("500");
    setPromoWager("1");
    setPromoTerms("Code promotionnel crédité automatiquement sur le premier dépôt éligible.");
  }

  async function deletePromoCode(code: string) {
    setPromoActionLoading("delete");
    setMessage("");
    setFeedback("");
    const response = await fetch(`/api/admin/promotions?code=${encodeURIComponent(code)}`, { method: "DELETE" });
    const payload = await response.json();
    setPromoActionLoading(null);
    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Suppression du code promo impossible");
      return;
    }
    await loadDashboard();
    if (promoCode.toUpperCase() === code) {
      resetPromoForm();
    }
    setFeedback(`Code promo ${code} supprimé.`);
  }

  async function saveBoostedOdd() {
    setBoostActionLoading("save");
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/boosted-odds", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        id: boostEditingId ?? undefined,
        categoryId: boostCategoryId || undefined,
        sportSlug: boostSportSlug,
        sportName: boostSportName,
        competitionName: boostCompetitionName,
        competitionCountry: boostCompetitionCountry,
        teamA: boostTeamA,
        teamB: boostTeamB,
        startsAt: boostStartsAt,
        betLabel: boostBetLabel,
        originalOdds: boostOriginalOdds,
        boostedOdds: boostedOddsValue,
        maxStake: boostMaxStake,
        allowCombinations: boostAllowCombinations,
        terms: boostTerms,
        status: boostStatus,
        sortOrder: boostSortOrder
      })
    });
    const payload = await response.json();
    setBoostActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Enregistrement de la cote boostée impossible");
      return;
    }

    await loadDashboard();
    setFeedback(boostEditingId ? "Cote boostée mise à jour." : "Cote boostée créée.");
    setBoostEditingId(payload.data.boostedOdd.id);
  }

  function editBoostedOdd(boostedOdd: AdminBoostedOdd) {
    setBoostEditingId(boostedOdd.id);
    setBoostCategoryId(boostedOdd.category.id);
    setBoostSportSlug(boostedOdd.sportSlug);
    setBoostSportName(boostedOdd.sportName);
    setBoostCompetitionName(boostedOdd.competitionName);
    setBoostCompetitionCountry(boostedOdd.competitionCountry);
    setBoostTeamA(boostedOdd.teamA);
    setBoostTeamB(boostedOdd.teamB);
    setBoostStartsAt(toDateTimeLocal(boostedOdd.startsAt));
    setBoostBetLabel(boostedOdd.betLabel);
    setBoostOriginalOdds(boostedOdd.originalOdds);
    setBoostedOddsValue(boostedOdd.boostedOdds);
    setBoostMaxStake(boostedOdd.maxStake);
    setBoostAllowCombinations(boostedOdd.allowCombinations);
    setBoostTerms(boostedOdd.terms);
    setBoostStatus(boostedOdd.status);
    setBoostSortOrder(String(boostedOdd.sortOrder));
    setFeedback(`Modification de ${boostedOdd.betLabel}.`);
  }

  function resetBoostedOddForm() {
    setBoostEditingId(null);
    setBoostCategoryId(boostCategories[0]?.id ?? "");
    setBoostSportSlug("football");
    setBoostSportName("Football");
    setBoostCompetitionName("World Cup Boosts");
    setBoostCompetitionCountry("International");
    setBoostTeamA("");
    setBoostTeamB("");
    setBoostStartsAt(defaultDateTimeLocal());
    setBoostBetLabel("");
    setBoostOriginalOdds("2.00");
    setBoostedOddsValue("2.50");
    setBoostMaxStake("100");
    setBoostAllowCombinations(false);
    setBoostTerms("Temps réglementaire uniquement");
    setBoostStatus("ACTIVE");
    setBoostSortOrder("10");
  }

  async function deleteBoostedOdd(id: string) {
    setBoostActionLoading("delete");
    setMessage("");
    setFeedback("");

    const response = await fetch(`/api/admin/boosted-odds?id=${encodeURIComponent(id)}`, { method: "DELETE" });
    const payload = await response.json();
    setBoostActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Suppression de la cote boostée impossible");
      return;
    }

    await loadDashboard();
    if (boostEditingId === id) {
      resetBoostedOddForm();
    }
    setFeedback("Cote boostée supprimée.");
  }

  async function settleBoostedOddAdmin(id: string, outcome: "won" | "lost" | "void") {
    setBoostActionLoading(`settle:${id}:${outcome}`);
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/boosted-odds", {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ id, outcome })
    });
    const payload = await response.json();
    setBoostActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Règlement de la cote boostée impossible");
      return;
    }

    await loadDashboard();
    const settled = payload.data.settlement;
    setFeedback(
      `Cote boostée réglée : ${settlementLabel(outcome)} · ${settled.ticketsSettled} ticket(s) traité(s) · ${money(settled.creditedAmount)} crédité.`
    );
  }

  async function saveBoostedOddCategory() {
    setBoostActionLoading("category");
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/boosted-odds/categories", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        id: categoryEditingId ?? undefined,
        name: categoryName,
        status: categoryStatus,
        sortOrder: categorySortOrder
      })
    });
    const payload = await response.json();
    setBoostActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Enregistrement de la catégorie impossible");
      return;
    }

    await loadDashboard();
    setBoostCategoryId(payload.data.category.id);
    setCategoryEditingId(null);
    setCategoryName("");
    setCategorySortOrder("100");
    setCategoryStatus("ACTIVE");
    setFeedback("Catégorie de cotes boostées enregistrée.");
  }

  function editBoostedOddCategory(category: AdminBoostedOddCategory) {
    setCategoryEditingId(category.id);
    setCategoryName(category.name);
    setCategoryStatus(category.status);
    setCategorySortOrder(String(category.sortOrder));
  }

  function resetBoostedOddCategoryForm() {
    setCategoryEditingId(null);
    setCategoryName("");
    setCategoryStatus("ACTIVE");
    setCategorySortOrder("100");
  }

  async function deleteBoostedOddCategory(id: string) {
    setBoostActionLoading("category");
    setMessage("");
    setFeedback("");

    const response = await fetch(`/api/admin/boosted-odds/categories?id=${encodeURIComponent(id)}`, { method: "DELETE" });
    const payload = await response.json();
    setBoostActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Suppression de la catégorie impossible");
      return;
    }

    await loadDashboard();
    if (boostCategoryId === id) {
      setBoostCategoryId("");
    }
    setFeedback("Catégorie supprimée.");
  }

  async function saveSportsPagePromotion() {
    setSportsPromoActionLoading("save");
    setMessage("");
    setFeedback("");

    const response = await fetch("/api/admin/sports-promotions", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        id: sportsPromoEditingId ?? undefined,
        title: sportsPromoTitle,
        subtitle: sportsPromoSubtitle || null,
        badge: sportsPromoBadge || null,
        imageUrl: sportsPromoImageUrl,
        href: sportsPromoHref,
        status: sportsPromoStatus,
        sortOrder: sportsPromoSortOrder,
        startsAt: sportsPromoStartsAt || undefined,
        endsAt: sportsPromoEndsAt || null
      })
    });
    const payload = await response.json();
    setSportsPromoActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Enregistrement de la promotion sport impossible");
      return;
    }

    await loadDashboard();
    setSportsPromoEditingId(payload.data.promotion.id);
    setFeedback(sportsPromoEditingId ? "Promotion sport mise à jour." : "Promotion sport créée.");
  }

  function editSportsPagePromotion(promotion: AdminSportsPagePromotion) {
    setSportsPromoEditingId(promotion.id);
    setSportsPromoTitle(promotion.title);
    setSportsPromoSubtitle(promotion.subtitle ?? "");
    setSportsPromoBadge(promotion.badge ?? "");
    setSportsPromoImageUrl(promotion.imageUrl);
    setSportsPromoHref(promotion.href);
    setSportsPromoStatus(promotion.status);
    setSportsPromoSortOrder(String(promotion.sortOrder));
    setSportsPromoStartsAt(toDateTimeLocal(promotion.startsAt));
    setSportsPromoEndsAt(promotion.endsAt ? toDateTimeLocal(promotion.endsAt) : "");
    setFeedback(`Modification de ${promotion.title}.`);
  }

  function resetSportsPagePromotionForm() {
    setSportsPromoEditingId(null);
    setSportsPromoTitle("");
    setSportsPromoSubtitle("");
    setSportsPromoBadge("Sport");
    setSportsPromoImageUrl("/images/home/promo-sport-boosts.png");
    setSportsPromoHref("/sports#cote-boostee");
    setSportsPromoStatus("ACTIVE");
    setSportsPromoSortOrder("10");
    setSportsPromoStartsAt(defaultDateTimeLocal());
    setSportsPromoEndsAt("");
  }

  async function deleteSportsPagePromotion(id: string) {
    setSportsPromoActionLoading("delete");
    setMessage("");
    setFeedback("");

    const response = await fetch(`/api/admin/sports-promotions?id=${encodeURIComponent(id)}`, { method: "DELETE" });
    const payload = await response.json();
    setSportsPromoActionLoading(null);

    if (!payload.ok) {
      setMessage(payload.error?.message ?? "Suppression de la promotion sport impossible");
      return;
    }

    await loadDashboard();
    if (sportsPromoEditingId === id) {
      resetSportsPagePromotionForm();
    }
    setFeedback("Promotion sport archivée.");
  }

  const primaryKpis = summary
    ? [
        { label: "Joueurs actifs", value: number(summary.users.active), meta: `${number(summary.users.total)} comptes`, icon: UsersRound, tone: "felt" },
        { label: "GGR aujourd'hui", value: money(summary.revenue.ggrToday), meta: `Sport + casino`, icon: TrendingUp, tone: "gold" },
        { label: "Exposition open bets", value: money(summary.sportsbook.openLiability), meta: `${summary.sportsbook.openBets} tickets ouverts`, icon: TicketCheck, tone: "ember" },
        { label: "Retraits à valider", value: money(summary.payments.pendingWithdrawalAmount), meta: `${summary.payments.pendingWithdrawals} demandes`, icon: Banknote, tone: "sky" }
      ]
    : [];

  const queues = summary
    ? [
        { label: "KYC en attente", value: summary.kyc.pending, icon: BadgeCheck, tone: summary.kyc.pending ? "gold" : "felt", href: "KYC / AML" },
        { label: "Risque critique", value: summary.risk.critical, icon: ShieldAlert, tone: summary.risk.critical ? "ember" : "felt", href: "Risk queue" },
        { label: "Retraits pending", value: summary.payments.pendingWithdrawals, icon: Landmark, tone: summary.payments.pendingWithdrawals ? "gold" : "felt", href: "Paiements" },
        { label: "Marchés suspendus", value: summary.sportsbook.suspendedMarkets, icon: LockKeyhole, tone: summary.sportsbook.suspendedMarkets ? "ember" : "felt", href: "Trading" },
        { label: "Provider failures 24h", value: summary.platform.providerFailures24h, icon: XCircle, tone: summary.platform.providerFailures24h ? "ember" : "felt", href: "Providers" },
        { label: "Logs audit 24h", value: summary.platform.auditLogs24h, icon: ListChecks, tone: "sky", href: "Audit" }
      ]
    : [];

  const modules = summary
    ? [
        {
          title: "Gestion joueurs",
          body: "Profils, statuts, rôles, notes internes, limites, self-exclusion et historique compte.",
          metric: `${filteredUsers.length}/${users.length} affichés`,
          icon: UserCog,
          status: "Opérationnel"
        },
        {
          title: "Trading & cotes",
          body: "Monitoring pré-match, marchés ouverts/suspendus, exposition par événement et contrôles de settlement.",
          metric: `${summary.sportsbook.openMarkets} marchés ouverts`,
          icon: Radio,
          status: summary.sportsbook.suspendedMarkets ? "À surveiller" : "Stable"
        },
        {
          title: "Paiements & ledger",
          body: "Dépôts, retraits, rapprochement PSP, ledger atomique et ajustements finance auditables.",
          metric: `${money(summary.balances.available)} disponibles`,
          icon: WalletCards,
          status: summary.payments.pendingWithdrawals ? "Revue requise" : "Fluide"
        },
        {
          title: "Risk, KYC & conformité",
          body: "Files KYC, événements risque, AML, PEP/sanctions, limites et audit réglementaire.",
          metric: `${summary.risk.open} risques ouverts`,
          icon: ShieldCheck,
          status: summary.risk.critical ? "Critique" : "Sous contrôle"
        },
        {
          title: "Bonus, VIP & CRM",
          body: "Promotions actives, bonus utilisateurs, cashback hebdomadaire, segmentation et wagering.",
          metric: `${summary.promotions.active} promos · ${summary.promotions.activeUserBonuses} bonus`,
          icon: CircleDollarSign,
          status: "Configuré"
        },
        {
          title: "Observabilité providers",
          body: "Latence moyenne, erreurs providers, webhooks, mapping externe et santé opérationnelle.",
          metric: `${summary.platform.avgProviderLatencyMs} ms moyen`,
          icon: Gauge,
          status: summary.platform.providerFailures24h ? "Dégradé" : "Nominal"
        }
      ]
    : [];

  return (
    <div className="space-y-4">
      <section className="surface overflow-hidden rounded-lg p-4 sm:p-5">
        <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
          <div className="min-w-0">
            <div className="flex items-center gap-2 text-xs font-black uppercase text-felt">
              <ShieldCheck className="h-4 w-4" />
              Back-office bookmaker
            </div>
            <h1 className="mt-2 text-2xl font-black text-white sm:text-3xl">{activeNavigation.label}</h1>
            <p className="mt-2 max-w-3xl text-sm leading-6 text-slate-400">
              Pilotage joueurs, trading, paiements, KYC/AML, risque, bonus et observabilité provider depuis des données transactionnelles réelles.
            </p>
          </div>
          <button
            onClick={() => void loadDashboard()}
            className="inline-flex h-10 shrink-0 items-center justify-center gap-2 rounded-lg bg-felt px-4 text-sm font-black text-ink-950 transition hover:bg-emerald-300"
          >
            {loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Activity className="h-4 w-4" />}
            Actualiser
          </button>
        </div>

        {summary ? (
          <div className="mt-4 flex flex-wrap gap-2 text-xs font-bold text-slate-300">
            <Pill icon={Clock3} label={`Généré ${formatDateTime(summary.generatedAt)}`} />
            <Pill icon={CalendarClock} label={`${summary.users.newToday} inscription(s) aujourd'hui`} />
            <Pill icon={SlidersHorizontal} label={`${summary.platform.ledgerEntries} écritures ledger`} />
          </div>
        ) : null}

        {message ? (
          <div className="mt-4 rounded-lg border border-ember/30 bg-ember/10 p-3 text-sm font-semibold text-ember">
            {message}
          </div>
        ) : null}
        {feedback ? (
          <div className="mt-4 rounded-lg border border-felt/30 bg-felt/10 p-3 text-sm font-semibold text-felt">
            {feedback}
          </div>
        ) : null}

        <nav className="mt-4 flex gap-2 overflow-x-auto pb-1 scrollbar-thin" aria-label="Navigation admin">
          {adminNavigation.map((item) => (
            <Link
              key={item.section}
              href={item.href}
              className={cn(
                "inline-flex h-9 shrink-0 items-center gap-2 rounded-lg border px-3 text-xs font-black transition",
                activeSection === item.section
                  ? "border-felt bg-felt text-ink-950"
                  : "border-white/10 bg-white/[0.04] text-slate-300 hover:bg-white/[0.07] hover:text-white"
              )}
            >
              <item.icon className="h-4 w-4" />
              {item.label}
            </Link>
          ))}
        </nav>
      </section>

      {activeSection === "overview" ? (
      <section className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
        {primaryKpis.map((item) => (
          <KpiCard key={item.label} {...item} />
        ))}
        {!summary && !message
          ? Array.from({ length: 4 }).map((_, index) => <div key={index} className="h-32 animate-pulse rounded-lg bg-white/[0.04]" />)
          : null}
      </section>
      ) : null}

      {summary ? (
        <>
          {activeSection === "overview" ? (
          <>
          <section className="grid gap-3 xl:grid-cols-3">
            <div className="surface rounded-lg p-4">
              <SectionTitle icon={AlertTriangle} title="Files prioritaires" />
              <div className="mt-4 grid gap-2 sm:grid-cols-2">
                {queues.map((item) => (
                  <div key={item.label} className="rounded-lg border border-white/10 bg-white/[0.035] p-3">
                    <div className="flex items-center justify-between gap-3">
                      <span className={cn("grid h-9 w-9 shrink-0 place-items-center rounded-lg", toneClass(item.tone, "soft"))}>
                        <item.icon className="h-4 w-4" />
                      </span>
                      <span className={cn("rounded-md px-2 py-1 text-xs font-black", toneClass(item.tone, "badge"))}>{item.href}</span>
                    </div>
                    <div className="mt-3 text-2xl font-black text-white">{number(item.value)}</div>
                    <div className="mt-1 text-sm font-semibold text-slate-400">{item.label}</div>
                  </div>
                ))}
              </div>
            </div>

            <div className="surface rounded-lg p-4">
              <SectionTitle icon={BarChart3} title="Santé sportsbook" />
              <div className="mt-4 grid gap-3">
                <MetricLine label="Mises aujourd'hui" value={money(summary.sportsbook.stakeToday)} helper={`${summary.sportsbook.ticketsToday} tickets`} />
                <MetricLine label="Payout aujourd'hui" value={money(summary.sportsbook.payoutToday)} helper="Écritures BET_WIN" />
                <MetricLine label="Stake ouvert" value={money(summary.sportsbook.openStake)} helper={`${summary.sportsbook.openBets} tickets ouverts`} />
                <MetricLine label="Événements pré-match" value={number(summary.sportsbook.scheduledEvents)} helper={`${summary.sportsbook.openMarkets} marchés ouverts`} />
                <MetricLine label="Bonus actifs" value={number(summary.promotions.activeUserBonuses)} helper={`${summary.promotions.active} campagnes`} />
              </div>
            </div>

            <div className="surface rounded-lg p-4">
              <SectionTitle icon={Dice5} title="Santé casino" />
              <div className="mt-4 grid gap-3">
                <MetricLine label="Mises casino aujourd'hui" value={money(summary.casino.stakeToday)} helper={`${summary.casino.roundsToday} rounds`} />
                <MetricLine label="Payout casino aujourd'hui" value={money(summary.casino.payoutToday)} helper="Gains casino crédités" />
                <MetricLine label="GGR casino aujourd'hui" value={money(summary.casino.ggrToday)} helper={`${summary.casino.wonToday} gagnés · ${summary.casino.lostToday} perdus`} />
                <MetricLine label="Rounds actifs" value={number(summary.casino.activeRounds)} helper={`${summary.casino.voidToday} annulé(s) aujourd'hui`} />
                <MetricLine label="GGR total aujourd'hui" value={money(summary.revenue.ggrToday)} helper="Sportsbook + casino" />
              </div>
            </div>
          </section>

          <section className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
            {modules.map((module) => (
              <article key={module.title} className="surface rounded-lg p-4">
                <div className="flex items-start justify-between gap-3">
                  <span className="grid h-10 w-10 shrink-0 place-items-center rounded-lg bg-felt/10 text-felt">
                    <module.icon className="h-5 w-5" />
                  </span>
                  <span className="rounded-md border border-white/10 bg-white/[0.04] px-2 py-1 text-[11px] font-black uppercase text-slate-300">
                    {module.status}
                  </span>
                </div>
                <h2 className="mt-4 text-base font-black text-white">{module.title}</h2>
                <p className="mt-2 text-sm leading-6 text-slate-400">{module.body}</p>
                <div className="mt-4 rounded-lg bg-white/[0.04] px-3 py-2 text-sm font-black text-felt">{module.metric}</div>
              </article>
            ))}
          </section>
          </>
          ) : null}

          {activeSection === "bonus" ? (
          <section className="surface rounded-lg p-4">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <SectionTitle icon={CircleDollarSign} title="Bonus de bienvenue" />
              <span className="rounded-lg border border-felt/25 bg-felt/10 px-3 py-2 text-xs font-black uppercase text-felt">
                Premier dépôt automatique
              </span>
            </div>

            <div className="mt-4 grid gap-3 xl:grid-cols-2">
              <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
                <h3 className="text-sm font-black text-white">Offre Sport</h3>
                <p className="mt-1 text-xs leading-5 text-slate-500">Affichée par défaut à l'inscription et créditée au premier dépôt.</p>
                <div className="mt-3 grid grid-cols-3 gap-2">
                  <AdminInput label="% bonus" value={sportMatchPercent} onChange={setSportMatchPercent} />
                  <AdminInput label="Max EUR" value={sportMaxBonus} onChange={setSportMaxBonus} />
                  <AdminInput label="Wager x" value={sportWager} onChange={setSportWager} />
                </div>
                <textarea
                  value={sportTerms}
                  onChange={(event) => setSportTerms(event.target.value)}
                  className="mt-2 min-h-16 w-full rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Conditions de l'offre"
                />
                <button
                  onClick={() => void saveWelcomeSport()}
                  disabled={promoActionLoading === "sport"}
                  className="mt-3 flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-felt text-sm font-black text-ink-950 disabled:opacity-60"
                >
                  {promoActionLoading === "sport" ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                  Enregistrer l'offre Sport
                </button>
              </article>

              <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
                <div className="flex items-center justify-between gap-3">
                  <h3 className="text-sm font-black text-white">Code promotionnel</h3>
                  <button onClick={resetPromoForm} className="rounded-lg border border-white/10 bg-white/[0.04] px-2.5 py-1.5 text-[11px] font-bold text-slate-200">
                    Nouveau
                  </button>
                </div>
                <p className="mt-1 text-xs leading-5 text-slate-500">Exemple : AZIA = 500% jusqu'à 2 500€. Le joueur le saisit à l'inscription.</p>
                <div className="mt-3 grid gap-2 sm:grid-cols-[0.6fr_1fr]">
                  <AdminInput label="Code" value={promoCode} onChange={(value) => setPromoCode(value.toUpperCase())} />
                  <AdminInput label="Nom" value={promoName} onChange={setPromoName} />
                </div>
                <div className="mt-2 grid grid-cols-3 gap-2">
                  <AdminInput label="% bonus" value={promoMatchPercent} onChange={setPromoMatchPercent} />
                  <AdminInput label="Max EUR" value={promoMaxBonus} onChange={setPromoMaxBonus} />
                  <AdminInput label="Wager x" value={promoWager} onChange={setPromoWager} />
                </div>
                <textarea
                  value={promoTerms}
                  onChange={(event) => setPromoTerms(event.target.value)}
                  className="mt-2 min-h-16 w-full rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Conditions du code"
                />
                <button
                  onClick={() => void savePromoCode()}
                  disabled={promoActionLoading === "code"}
                  className="mt-3 flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-gold text-sm font-black text-ink-950 disabled:opacity-60"
                >
                  {promoActionLoading === "code" ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                  Enregistrer le code
                </button>
              </article>
            </div>

            <div className="mt-3 grid gap-2 md:grid-cols-2 xl:grid-cols-3">
              {promotions.filter((promotion) => promotion.code !== "WELCOME_SPORT").map((promotion) => (
                <div key={promotion.code} className="rounded-lg border border-white/10 bg-white/[0.035] p-3">
                  <div className="flex items-center justify-between gap-2">
                    <div className="truncate text-sm font-black text-white">{promotion.code}</div>
                    <StatusBadge status={promotion.status} compact />
                  </div>
                  <div className="mt-1 truncate text-xs text-slate-400">{promotion.name}</div>
                  <div className="mt-2 text-xs font-black text-felt">
                    {promotion.matchPercent}% jusqu'à {money(promotion.maxBonusAmount)}
                  </div>
                  <div className="mt-3 grid grid-cols-2 gap-2">
                    <button onClick={() => editPromoCode(promotion)} className="h-8 rounded-lg border border-white/10 bg-white/[0.05] text-xs font-bold text-slate-100">
                      Éditer
                    </button>
                    <button
                      onClick={() => void deletePromoCode(promotion.code)}
                      disabled={promoActionLoading === "delete"}
                      className="flex h-8 items-center justify-center gap-1 rounded-lg border border-ember/25 bg-ember/10 text-xs font-bold text-ember disabled:opacity-60"
                    >
                      {promoActionLoading === "delete" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : null}
                      Supprimer
                    </button>
                  </div>
                </div>
              ))}
              {promotions.filter((promotion) => promotion.code !== "WELCOME_SPORT").length === 0 ? (
                <div className="rounded-lg border border-dashed border-white/10 bg-white/[0.025] p-3 text-xs font-semibold text-slate-500">
                  Aucun code promotionnel créé.
                </div>
              ) : null}
            </div>
          </section>
          ) : null}

          {activeSection === "trading" ? (
          <section className="surface rounded-lg p-4">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <SectionTitle icon={BadgePercent} title="Cotes boostées" />
              <span className="rounded-lg border border-felt/25 bg-felt/10 px-3 py-2 text-xs font-black uppercase text-felt">
                Pari personnalisé · coupon sécurisé
              </span>
            </div>

            <div className="mt-4 rounded-lg border border-white/10 bg-white/[0.03] p-3">
              <div className="flex flex-col gap-3 lg:flex-row lg:items-end">
                <div className="grid flex-1 gap-2 sm:grid-cols-[1fr_0.35fr_0.35fr]">
                  <AdminInput label="Nom catégorie" value={categoryName} onChange={setCategoryName} />
                  <AdminInput label="Ordre" value={categorySortOrder} onChange={setCategorySortOrder} />
                  <label className="block text-[11px] font-black uppercase text-slate-500">
                    Statut
                    <select value={categoryStatus} onChange={(event) => setCategoryStatus(event.target.value)} className="mt-1 h-10 w-full rounded-lg border-white/10 bg-ink-900 text-sm font-bold text-white">
                      <option value="ACTIVE">ACTIVE</option>
                      <option value="PAUSED">PAUSED</option>
                      <option value="DRAFT">DRAFT</option>
                      <option value="EXPIRED">EXPIRED</option>
                    </select>
                  </label>
                </div>
                <div className="grid grid-cols-2 gap-2 lg:w-[260px]">
                  <button onClick={resetBoostedOddCategoryForm} className="h-10 rounded-lg border border-white/10 bg-white/[0.04] text-xs font-bold text-slate-200">
                    Nouvelle
                  </button>
                  <button
                    onClick={() => void saveBoostedOddCategory()}
                    disabled={boostActionLoading === "category" || !categoryName.trim()}
                    className="flex h-10 items-center justify-center gap-2 rounded-lg bg-felt text-xs font-black text-ink-950 disabled:opacity-60"
                  >
                    {boostActionLoading === "category" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : null}
                    Enregistrer
                  </button>
                </div>
              </div>
              <div className="mt-3 flex flex-wrap gap-2">
                {boostCategories.map((category) => (
                  <div key={category.id} className="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-2 py-1.5">
                    <button onClick={() => editBoostedOddCategory(category)} className="text-xs font-black text-white">
                      {category.name}
                    </button>
                    <StatusBadge status={category.status} compact />
                    <button onClick={() => void deleteBoostedOddCategory(category.id)} disabled={boostActionLoading === "category"} className="text-xs font-black text-ember disabled:opacity-50">
                      ×
                    </button>
                  </div>
                ))}
                {!boostCategories.length ? <span className="text-xs font-semibold text-slate-500">Aucune catégorie créée.</span> : null}
              </div>
            </div>

            <div className="mt-4 grid gap-3 xl:grid-cols-[1.1fr_0.9fr]">
              <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h3 className="text-sm font-black text-white">{boostEditingId ? "Modifier une cote boostée" : "Créer une cote boostée"}</h3>
                    <p className="mt-1 text-xs leading-5 text-slate-500">La cote est publiée dans la section Cote boostée et respecte la mise max dans le coupon.</p>
                  </div>
                  <button onClick={resetBoostedOddForm} className="rounded-lg border border-white/10 bg-white/[0.04] px-2.5 py-1.5 text-[11px] font-bold text-slate-200">
                    Nouveau
                  </button>
                </div>

                <div className="mt-3 grid gap-2 sm:grid-cols-2">
                  <label className="block text-[11px] font-black uppercase text-slate-500">
                    Catégorie
                    <select value={boostCategoryId} onChange={(event) => setBoostCategoryId(event.target.value)} className="mt-1 h-10 w-full rounded-lg border-white/10 bg-ink-900 text-sm font-bold text-white">
                      <option value="">Créer automatiquement</option>
                      {boostCategories.filter((category) => category.status === "ACTIVE").map((category) => (
                        <option key={category.id} value={category.id}>
                          {category.name}
                        </option>
                      ))}
                    </select>
                  </label>
                  <AdminInput label="Date / heure" value={boostStartsAt} onChange={setBoostStartsAt} type="datetime-local" />
                  <AdminInput label="Sport slug" value={boostSportSlug} onChange={setBoostSportSlug} />
                  <AdminInput label="Nom sport" value={boostSportName} onChange={setBoostSportName} />
                  <AdminInput label="Compétition" value={boostCompetitionName} onChange={setBoostCompetitionName} />
                  <AdminInput label="Pays / zone" value={boostCompetitionCountry} onChange={setBoostCompetitionCountry} />
                  <AdminInput label="Équipe A" value={boostTeamA} onChange={setBoostTeamA} />
                  <AdminInput label="Équipe B" value={boostTeamB} onChange={setBoostTeamB} />
                  <AdminInput label="Pari exact" value={boostBetLabel} onChange={setBoostBetLabel} />
                  <AdminInput label="Cote origine" value={boostOriginalOdds} onChange={setBoostOriginalOdds} />
                  <AdminInput label="Cote boostée" value={boostedOddsValue} onChange={setBoostedOddsValue} />
                  <AdminInput label="Mise max EUR" value={boostMaxStake} onChange={setBoostMaxStake} />
                  <AdminInput label="Ordre" value={boostSortOrder} onChange={setBoostSortOrder} />
                  <label className="block text-[11px] font-black uppercase text-slate-500">
                    Statut
                    <select value={boostStatus} onChange={(event) => setBoostStatus(event.target.value)} className="mt-1 h-10 w-full rounded-lg border-white/10 bg-ink-900 text-sm font-bold text-white">
                      <option value="ACTIVE">ACTIVE</option>
                      <option value="PAUSED">PAUSED</option>
                      <option value="DRAFT">DRAFT</option>
                      <option value="EXPIRED">EXPIRED</option>
                    </select>
                  </label>
                </div>

                <label className="mt-3 flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.03] px-3 py-2 text-xs font-bold text-slate-200">
                  <input
                    type="checkbox"
                    checked={boostAllowCombinations}
                    onChange={(event) => setBoostAllowCombinations(event.target.checked)}
                    className="rounded border-white/20 bg-ink-900 text-felt focus:ring-felt"
                  />
                  Autoriser cette cote boostée en combiné
                </label>

                <textarea
                  value={boostTerms}
                  onChange={(event) => setBoostTerms(event.target.value)}
                  className="mt-2 min-h-16 w-full rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Conditions affichées sous la cote"
                />

                <button
                  onClick={() => void saveBoostedOdd()}
                  disabled={boostActionLoading === "save"}
                  className="mt-3 flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-felt text-sm font-black text-ink-950 disabled:opacity-60"
                >
                  {boostActionLoading === "save" ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                  Enregistrer la cote boostée
                </button>
              </article>

              <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
                <h3 className="text-sm font-black text-white">Boosts actifs et planifiés</h3>
                <div className="mt-3 space-y-2">
                  {boostedOdds.length ? (
                    boostedOdds.map((boostedOdd) => (
                      <div key={boostedOdd.id} className="rounded-lg border border-white/10 bg-white/[0.035] p-3">
                        <div className="flex items-start justify-between gap-3">
                          <div className="min-w-0">
                            <div className="truncate text-sm font-black text-white">{boostedOdd.betLabel}</div>
                            <div className="mt-1 truncate text-xs text-slate-400">
                              {boostedOdd.category.name} · {boostedOdd.teamA} vs {boostedOdd.teamB} · {formatDateTime(boostedOdd.startsAt)}
                            </div>
                          </div>
                          <StatusBadge status={boostedOdd.status} compact />
                        </div>
                        <div className="mt-2 grid grid-cols-4 gap-2 text-xs">
                          <div className="rounded-md bg-white/[0.04] p-2">
                            <div className="text-slate-500">Origine</div>
                            <div className="font-black text-white">{boostedOdd.originalOdds}</div>
                          </div>
                          <div className="rounded-md bg-felt/10 p-2">
                            <div className="text-felt/80">Boost</div>
                            <div className="font-black text-felt">{boostedOdd.boostedOdds}</div>
                          </div>
                          <div className="rounded-md bg-white/[0.04] p-2">
                            <div className="text-slate-500">Mise max</div>
                            <div className="font-black text-white">{money(boostedOdd.maxStake)}</div>
                          </div>
                          <div className="rounded-md bg-white/[0.04] p-2">
                            <div className="text-slate-500">Tickets</div>
                            <div className="font-black text-white">{number(boostedOdd.openTickets)}</div>
                          </div>
                        </div>
                        <div className="mt-3 grid grid-cols-2 gap-2">
                          <button onClick={() => editBoostedOdd(boostedOdd)} className="h-8 rounded-lg border border-white/10 bg-white/[0.05] text-xs font-bold text-slate-100">
                            Éditer
                          </button>
                          <button
                            onClick={() => void deleteBoostedOdd(boostedOdd.id)}
                            disabled={boostActionLoading === "delete"}
                            className="flex h-8 items-center justify-center gap-1 rounded-lg border border-ember/25 bg-ember/10 text-xs font-bold text-ember disabled:opacity-60"
                          >
                            {boostActionLoading === "delete" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : null}
                            Supprimer
                          </button>
                        </div>
                        <div className="mt-2 grid grid-cols-3 gap-2">
                          <SettlementButton
                            label="Gagné"
                            tone="felt"
                            loading={boostActionLoading === `settle:${boostedOdd.id}:won`}
                            disabled={boostedOdd.status === "EXPIRED"}
                            onClick={() => void settleBoostedOddAdmin(boostedOdd.id, "won")}
                          />
                          <SettlementButton
                            label="Perdu"
                            tone="ember"
                            loading={boostActionLoading === `settle:${boostedOdd.id}:lost`}
                            disabled={boostedOdd.status === "EXPIRED"}
                            onClick={() => void settleBoostedOddAdmin(boostedOdd.id, "lost")}
                          />
                          <SettlementButton
                            label="Remboursé"
                            tone="gold"
                            loading={boostActionLoading === `settle:${boostedOdd.id}:void`}
                            disabled={boostedOdd.status === "EXPIRED"}
                            onClick={() => void settleBoostedOddAdmin(boostedOdd.id, "void")}
                          />
                        </div>
                      </div>
                    ))
                  ) : (
                    <div className="rounded-lg border border-dashed border-white/10 bg-white/[0.025] p-4 text-xs font-semibold text-slate-500">
                      Aucune cote boostée créée.
                    </div>
                  )}
                </div>
              </article>
            </div>
          </section>
          ) : null}

          {activeSection === "sport-promos" ? (
          <section className="surface rounded-lg p-4">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <SectionTitle icon={TicketCheck} title="Promotions sport" />
              <span className="rounded-lg border border-felt/25 bg-felt/10 px-3 py-2 text-xs font-black uppercase text-felt">
                Affichage haut de page Sports
              </span>
            </div>

            <div className="mt-4 grid gap-3 xl:grid-cols-[0.92fr_1.08fr]">
              <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h3 className="text-sm font-black text-white">{sportsPromoEditingId ? "Modifier une promotion" : "Créer une promotion"}</h3>
                    <p className="mt-1 text-xs leading-5 text-slate-500">Image, lien et texte affichés uniquement sur la page Sports.</p>
                  </div>
                  <button onClick={resetSportsPagePromotionForm} className="rounded-lg border border-white/10 bg-white/[0.04] px-2.5 py-1.5 text-[11px] font-bold text-slate-200">
                    Nouveau
                  </button>
                </div>

                <div className="mt-3 grid gap-2">
                  <AdminInput label="Titre" value={sportsPromoTitle} onChange={setSportsPromoTitle} />
                  <AdminInput label="Sous-titre" value={sportsPromoSubtitle} onChange={setSportsPromoSubtitle} />
                  <div className="grid gap-2 sm:grid-cols-[0.7fr_1fr]">
                    <AdminInput label="Badge" value={sportsPromoBadge} onChange={setSportsPromoBadge} />
                    <AdminInput label="Lien de redirection" value={sportsPromoHref} onChange={setSportsPromoHref} />
                  </div>
                  <AdminInput label="Image promo" value={sportsPromoImageUrl} onChange={setSportsPromoImageUrl} />
                  <div className="grid gap-2 sm:grid-cols-2">
                    <AdminInput label="Début" value={sportsPromoStartsAt} onChange={setSportsPromoStartsAt} type="datetime-local" />
                    <AdminInput label="Fin optionnelle" value={sportsPromoEndsAt} onChange={setSportsPromoEndsAt} type="datetime-local" />
                  </div>
                  <div className="grid gap-2 sm:grid-cols-[0.45fr_0.55fr]">
                    <AdminInput label="Ordre" value={sportsPromoSortOrder} onChange={setSportsPromoSortOrder} />
                    <label className="block text-[11px] font-black uppercase text-slate-500">
                      Statut
                      <select value={sportsPromoStatus} onChange={(event) => setSportsPromoStatus(event.target.value)} className="mt-1 h-10 w-full rounded-lg border-white/10 bg-ink-900 text-sm font-bold text-white">
                        <option value="ACTIVE">ACTIVE</option>
                        <option value="PAUSED">PAUSED</option>
                        <option value="DRAFT">DRAFT</option>
                      </select>
                    </label>
                  </div>
                </div>

                <button
                  onClick={() => void saveSportsPagePromotion()}
                  disabled={sportsPromoActionLoading === "save" || !sportsPromoTitle.trim() || !sportsPromoImageUrl.trim() || !sportsPromoHref.trim()}
                  className="mt-3 flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-felt text-sm font-black text-ink-950 disabled:opacity-60"
                >
                  {sportsPromoActionLoading === "save" ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                  Enregistrer la promotion sport
                </button>
              </article>

              <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
                <h3 className="text-sm font-black text-white">Promotions créées</h3>
                <div className="mt-3 grid gap-2">
                  {sportsPromos.length ? (
                    sportsPromos.map((promotion) => (
                        <div key={promotion.id} className="grid gap-3 rounded-lg border border-white/10 bg-white/[0.035] p-3 sm:grid-cols-[140px_1fr]">
                        <div
                          className="relative h-24 overflow-hidden rounded-lg border border-white/10 bg-ink-900 bg-cover bg-center"
                          style={{ backgroundImage: `url(${promotion.imageUrl})` }}
                        >
                          {promotion.badge ? (
                            <span className="absolute left-2 top-2 rounded-md bg-felt px-1.5 py-1 text-[9px] font-black uppercase text-ink-950">{promotion.badge}</span>
                          ) : null}
                        </div>
                        <div className="min-w-0">
                          <div className="flex items-start justify-between gap-3">
                            <div className="min-w-0">
                              <div className="truncate text-sm font-black text-white">{promotion.title}</div>
                              {promotion.subtitle ? <div className="mt-1 line-clamp-2 text-xs leading-5 text-slate-400">{promotion.subtitle}</div> : null}
                            </div>
                            <StatusBadge status={promotion.status} compact />
                          </div>
                          <div className="mt-2 grid gap-1 text-[11px] font-semibold text-slate-500">
                            <span className="truncate">Lien: {promotion.href}</span>
                            <span>
                              Ordre {promotion.sortOrder} · début {formatDateTime(promotion.startsAt)}
                              {promotion.endsAt ? ` · fin ${formatDateTime(promotion.endsAt)}` : ""}
                            </span>
                          </div>
                          <div className="mt-3 grid grid-cols-2 gap-2">
                            <button onClick={() => editSportsPagePromotion(promotion)} className="h-8 rounded-lg border border-white/10 bg-white/[0.05] text-xs font-bold text-slate-100">
                              Éditer
                            </button>
                            <button
                              onClick={() => void deleteSportsPagePromotion(promotion.id)}
                              disabled={sportsPromoActionLoading === "delete"}
                              className="flex h-8 items-center justify-center gap-1 rounded-lg border border-ember/25 bg-ember/10 text-xs font-bold text-ember disabled:opacity-60"
                            >
                              {sportsPromoActionLoading === "delete" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : null}
                              Archiver
                            </button>
                          </div>
                        </div>
                      </div>
                    ))
                  ) : (
                    <div className="rounded-lg border border-dashed border-white/10 bg-white/[0.025] p-4 text-xs font-semibold text-slate-500">
                      Aucune promotion sport créée.
                    </div>
                  )}
                </div>
              </article>
            </div>
          </section>
          ) : null}

          {activeSection === "finance" ? (
          <section className="surface min-w-0 overflow-hidden rounded-lg p-4">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <SectionTitle icon={Bitcoin} title="Crypto finance" />
              <span className="rounded-lg border border-felt/25 bg-felt/10 px-3 py-2 text-xs font-black uppercase text-felt">
                Dépôts auto · retraits validés admin
              </span>
            </div>

            <div className="mt-4 grid gap-3 xl:grid-cols-[1.05fr_0.95fr]">
              <article className="min-w-0 rounded-lg border border-white/10 bg-white/[0.025] p-3">
                <h3 className="font-black text-white">Retraits à traiter</h3>
                <div className="mt-3 space-y-2">
                  {cryptoOps?.withdrawals.filter((item) => item.status === "REQUESTED" || item.status === "APPROVED").length ? (
                    cryptoOps.withdrawals
                      .filter((item) => item.status === "REQUESTED" || item.status === "APPROVED")
                      .slice(0, 8)
                      .map((withdrawal) => (
                        <div key={withdrawal.id} className="min-w-0 rounded-lg bg-white/[0.04] p-3">
                          <div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
                            <div className="min-w-0">
                              <div className="truncate text-sm font-black text-white">{withdrawal.userEmail}</div>
                              <div className="mt-1 text-xs text-slate-500">
                                {withdrawal.asset} · {money(withdrawal.eurAmount)} demandé · débit {money(withdrawal.totalDebitEur)}
                              </div>
                              <div className="mt-1 break-all font-mono text-[11px] text-slate-400">{withdrawal.destinationAddress}</div>
                            </div>
                            <StatusBadge status={withdrawal.status} compact />
                          </div>

                          {withdrawal.status === "REQUESTED" ? (
                            <div className="mt-3 grid gap-2 sm:grid-cols-2">
                              <button
                                onClick={() => void reviewCryptoWithdrawal(withdrawal.id, "approve")}
                                disabled={cryptoActionId === withdrawal.id}
                                className="h-10 rounded-lg bg-felt text-sm font-black text-ink-950 disabled:opacity-60"
                              >
                                Approuver
                              </button>
                              <button
                                onClick={() => void reviewCryptoWithdrawal(withdrawal.id, "reject")}
                                disabled={cryptoActionId === withdrawal.id}
                                className="h-10 rounded-lg border border-ember/30 bg-ember/10 text-sm font-black text-ember disabled:opacity-60"
                              >
                                Refuser
                              </button>
                            </div>
                          ) : (
                            <div className="mt-3 grid gap-2 sm:grid-cols-[1fr_auto]">
                              <input
                                value={broadcastHashes[withdrawal.id] ?? ""}
                                onChange={(event) => setBroadcastHashes((current) => ({ ...current, [withdrawal.id]: event.target.value }))}
                                className="h-10 rounded-lg border-white/10 bg-ink-900 text-sm"
                                placeholder="Hash transaction envoyé"
                              />
                              <button
                                onClick={() => void reviewCryptoWithdrawal(withdrawal.id, "mark_broadcasted")}
                                disabled={cryptoActionId === withdrawal.id || !broadcastHashes[withdrawal.id]}
                                className="h-10 rounded-lg bg-gold px-3 text-sm font-black text-ink-950 disabled:opacity-60"
                              >
                                Marquer envoyé
                              </button>
                            </div>
                          )}
                        </div>
                      ))
                  ) : (
                    <div className="rounded-lg bg-white/[0.04] p-4 text-sm font-semibold text-slate-400">Aucun retrait crypto à traiter.</div>
                  )}
                </div>
              </article>

              <article className="min-w-0 rounded-lg border border-white/10 bg-white/[0.025] p-3">
                <h3 className="font-black text-white">Dépôts récents</h3>
                <div className="mt-3 space-y-2">
                  {cryptoOps?.deposits.length ? (
                    cryptoOps.deposits.slice(0, 10).map((deposit) => (
                      <div key={deposit.id} className="flex min-w-0 items-center justify-between gap-3 rounded-lg bg-white/[0.04] p-3">
                        <div className="min-w-0">
                          <div className="truncate text-sm font-black text-white">{deposit.userEmail}</div>
                          <div className="mt-1 truncate text-xs text-slate-500">
                            {deposit.asset} · {shortHash(deposit.txHash)} · {deposit.confirmations}/{deposit.requiredConfirmations} confirmations
                          </div>
                        </div>
                        <div className="shrink-0 text-right">
                          <div className="text-sm font-black text-white">{money(deposit.eurAmount ?? "0")}</div>
                          <StatusBadge status={deposit.status} compact />
                        </div>
                      </div>
                    ))
                  ) : (
                    <div className="rounded-lg bg-white/[0.04] p-4 text-sm font-semibold text-slate-400">Aucun dépôt crypto détecté.</div>
                  )}
                </div>
              </article>
            </div>
          </section>
          ) : null}
        </>
      ) : null}

      {activeSection === "kyc" ? <AdminKycDashboard /> : null}
      {activeSection === "support" ? <AdminSupportDashboard /> : null}

      {activeSection === "players" ? (
      <section className="surface rounded-lg p-4">
        <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
          <SectionTitle icon={UsersRound} title="Gestion joueurs" />
          <div className="flex flex-col gap-2 sm:flex-row">
            <label className="flex h-10 items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-3 text-slate-400">
              <Search className="h-4 w-4" />
              <input
                value={query}
                onChange={(event) => setQuery(event.target.value)}
                placeholder="Email, pseudo, pays, KYC..."
                className="h-full min-w-0 border-0 bg-transparent p-0 text-sm text-white placeholder:text-slate-500 focus:ring-0"
              />
            </label>
            <select
              value={status}
              onChange={(event) => setStatus(event.target.value as (typeof statuses)[number])}
              className="h-10 rounded-lg border border-white/10 bg-[#101521] px-3 text-sm font-bold text-white"
            >
              {statuses.map((item) => (
                <option key={item} value={item}>
                  {item === "ALL" ? "Tous statuts" : item}
                </option>
              ))}
            </select>
          </div>
        </div>

        {selectedUser ? (
          <div className="mt-4 grid gap-3 xl:grid-cols-[0.85fr_1fr_1fr]">
            <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
              <div className="text-xs font-black uppercase text-slate-500">Joueur sélectionné</div>
              <h3 className="mt-2 truncate text-lg font-black text-white">{selectedUser.email}</h3>
              <div className="mt-2 flex flex-wrap gap-2">
                <StatusBadge status={selectedUser.status} />
                <StatusBadge status={selectedUser.kycStatus} compact />
              </div>
              <div className="mt-4 grid grid-cols-2 gap-2 text-sm">
                <div className="rounded-lg bg-white/[0.04] p-3">
                  <div className="text-xs font-bold text-slate-500">Disponible</div>
                  <div className="mt-1 font-black text-white">{money(selectedUser.availableBalance)}</div>
                </div>
                <div className="rounded-lg bg-white/[0.04] p-3">
                  <div className="text-xs font-bold text-slate-500">Bonus</div>
                  <div className="mt-1 font-black text-white">{money(selectedUser.bonusBalance)}</div>
                </div>
              </div>
              <button
                onClick={() => void updateUserStatus(selectedUser.id, "SUSPENDED")}
                disabled={savingUserId === selectedUser.id || selectedUser.status === "SUSPENDED"}
                className="mt-3 h-10 w-full rounded-lg border border-ember/30 bg-ember/10 text-sm font-black text-ember disabled:opacity-50"
              >
                Bloquer le joueur
              </button>
              <button
                onClick={() => void requestKycVerification()}
                disabled={actionLoading === "kyc" || selectedUser.kycStatus === "PENDING"}
                className="mt-2 flex h-10 w-full items-center justify-center gap-2 rounded-lg border border-felt/25 bg-felt/10 text-sm font-black text-felt disabled:cursor-not-allowed disabled:opacity-50"
              >
                {actionLoading === "kyc" ? <Loader2 className="h-4 w-4 animate-spin" /> : <ShieldAlert className="h-4 w-4" />}
                {selectedUser.kycStatus === "PENDING" ? "Vérification déjà demandée" : "Vérification requise"}
              </button>
            </article>

            <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
              <div className="flex items-center gap-2">
                <Banknote className="h-5 w-5 text-felt" />
                <h3 className="font-black text-white">Dépôt manuel</h3>
              </div>
              <div className="mt-3 grid gap-2 sm:grid-cols-[0.45fr_1fr]">
                <input
                  value={depositAmount}
                  onChange={(event) => setDepositAmount(event.target.value)}
                  inputMode="decimal"
                  className="h-10 rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Montant"
                />
                <input
                  value={depositReason}
                  onChange={(event) => setDepositReason(event.target.value)}
                  className="h-10 rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Motif audit"
                />
              </div>
              <p className="mt-2 text-xs leading-5 text-slate-500">Crédite le wallet disponible avec une écriture ledger auditée.</p>
              <button
                onClick={() => void creditManualDeposit()}
                disabled={actionLoading === "deposit"}
                className="mt-3 flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-felt text-sm font-black text-ink-950 disabled:opacity-60"
              >
                {actionLoading === "deposit" ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                Créditer le dépôt
              </button>
            </article>

            <article className="rounded-lg border border-white/10 bg-white/[0.035] p-4">
              <div className="flex items-center gap-2">
                <CircleDollarSign className="h-5 w-5 text-gold" />
                <h3 className="font-black text-white">Offre bonus</h3>
              </div>
              <div className="mt-3 grid gap-2 sm:grid-cols-3">
                <input
                  value={bonusAmount}
                  onChange={(event) => setBonusAmount(event.target.value)}
                  inputMode="decimal"
                  className="h-10 rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Montant"
                />
                <input
                  value={bonusWager}
                  onChange={(event) => setBonusWager(event.target.value)}
                  inputMode="decimal"
                  className="h-10 rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Wager x"
                />
                <input
                  value={bonusTitle}
                  onChange={(event) => setBonusTitle(event.target.value)}
                  className="h-10 rounded-lg border-white/10 bg-ink-900 text-sm"
                  placeholder="Nom bonus"
                />
              </div>
              <textarea
                value={bonusTerms}
                onChange={(event) => setBonusTerms(event.target.value)}
                className="mt-2 min-h-20 w-full rounded-lg border-white/10 bg-ink-900 text-sm"
                placeholder="Conditions visibles par le joueur"
              />
              <button
                onClick={() => void grantBonusOffer()}
                disabled={actionLoading === "bonus"}
                className="mt-3 flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-gold text-sm font-black text-ink-950 disabled:opacity-60"
              >
                {actionLoading === "bonus" ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                Proposer le bonus
              </button>
            </article>
          </div>
        ) : null}

        <div className="mt-4 overflow-hidden rounded-lg border border-white/10">
          <div className="hidden grid-cols-[1.2fr_0.75fr_0.7fr_0.85fr_0.8fr_0.9fr] gap-3 border-b border-white/10 bg-white/[0.035] px-3 py-2 text-xs font-black uppercase text-slate-500 lg:grid">
            <span>Joueur</span>
            <span>Statut</span>
            <span>KYC</span>
            <span>Wallet</span>
            <span>Activité</span>
            <span>Action</span>
          </div>

          <div className="divide-y divide-white/10">
            {filteredUsers.map((user) => (
              <div key={user.id} className="grid gap-3 px-3 py-3 text-sm lg:grid-cols-[1.2fr_0.75fr_0.7fr_0.85fr_0.8fr_0.9fr] lg:items-center">
                <div className="min-w-0">
                  <div className="truncate font-black text-white">{user.email}</div>
                  <div className="mt-1 flex flex-wrap gap-1.5 text-xs text-slate-500">
                    <span>@{user.username}</span>
                    <span>{user.country ?? "Pays n/d"}</span>
                    <span>{formatDate(user.createdAt)}</span>
                  </div>
                </div>
                <StatusBadge status={user.status} />
                <StatusBadge status={user.kycStatus} compact />
                <div>
                  <div className="font-black text-white">
                    {money(user.availableBalance)} {user.currency}
                  </div>
                  <div className="text-xs text-slate-500">Bonus {money(user.bonusBalance)}</div>
                </div>
                <div className="flex flex-wrap gap-1.5 text-xs font-bold text-slate-300">
                  <span className="rounded bg-white/[0.05] px-2 py-1">{user.tickets} paris</span>
                  <span className="rounded bg-white/[0.05] px-2 py-1">{user.withdrawals} retraits</span>
                  {user.riskEvents ? <span className="rounded bg-ember/15 px-2 py-1 text-ember">{user.riskEvents} risques</span> : null}
                </div>
                <div className="flex items-center gap-2">
                  <button
                    onClick={() => setSelectedUserId(user.id)}
                    className={cn(
                      "h-9 rounded-lg px-2 text-xs font-black",
                      selectedUser?.id === user.id ? "bg-felt text-ink-950" : "bg-white/[0.06] text-slate-200"
                    )}
                  >
                    Gérer
                  </button>
                  <select
                    value={mutableStatuses.includes(user.status as (typeof mutableStatuses)[number]) ? user.status : "ACTIVE"}
                    disabled={savingUserId === user.id}
                    onChange={(event) => void updateUserStatus(user.id, event.target.value)}
                    className="h-9 min-w-0 flex-1 rounded-lg border border-white/10 bg-[#101521] px-2 text-xs font-bold text-white disabled:opacity-60"
                  >
                    {mutableStatuses.map((item) => (
                      <option key={item} value={item}>
                        {item}
                      </option>
                    ))}
                  </select>
                  {savingUserId === user.id ? <Loader2 className="h-4 w-4 animate-spin text-felt" /> : null}
                </div>
              </div>
            ))}
          </div>
        </div>

        {!filteredUsers.length ? (
          <div className="mt-4 rounded-lg border border-white/10 bg-white/[0.035] p-6 text-center text-sm font-semibold text-slate-400">
            Aucun joueur ne correspond aux filtres.
          </div>
        ) : null}
      </section>
      ) : null}
    </div>
  );
}

function KpiCard({
  label,
  value,
  meta,
  icon: Icon,
  tone
}: {
  label: string;
  value: string;
  meta: string;
  icon: typeof UsersRound;
  tone: string;
}) {
  return (
    <article className="surface rounded-lg p-4">
      <div className="flex items-center justify-between gap-3">
        <span className={cn("grid h-10 w-10 place-items-center rounded-lg", toneClass(tone, "soft"))}>
          <Icon className="h-5 w-5" />
        </span>
        <span className={cn("rounded-md px-2 py-1 text-[11px] font-black uppercase", toneClass(tone, "badge"))}>KPI</span>
      </div>
      <div className="mt-4 text-[26px] font-black leading-none text-white">{value}</div>
      <div className="mt-2 text-sm font-black text-slate-300">{label}</div>
      <div className="mt-1 text-xs font-semibold text-slate-500">{meta}</div>
    </article>
  );
}

function SectionTitle({ icon: Icon, title }: { icon: typeof ShieldCheck; title: string }) {
  return (
    <div className="flex items-center gap-2">
      <Icon className="h-5 w-5 text-felt" />
      <h2 className="text-lg font-black text-white">{title}</h2>
    </div>
  );
}

function Pill({ icon: Icon, label }: { icon: typeof Clock3; label: string }) {
  return (
    <span className="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-3 py-2">
      <Icon className="h-3.5 w-3.5 text-felt" />
      {label}
    </span>
  );
}

function MetricLine({ label, value, helper }: { label: string; value: string; helper: string }) {
  return (
    <div className="flex items-center justify-between gap-4 rounded-lg bg-white/[0.035] px-3 py-2">
      <div className="min-w-0">
        <div className="text-sm font-black text-white">{label}</div>
        <div className="mt-0.5 truncate text-xs text-slate-500">{helper}</div>
      </div>
      <div className="shrink-0 text-right text-base font-black text-felt">{value}</div>
    </div>
  );
}

function SettlementButton({
  label,
  tone,
  loading,
  disabled,
  onClick
}: {
  label: string;
  tone: "felt" | "ember" | "gold";
  loading: boolean;
  disabled: boolean;
  onClick: () => void;
}) {
  return (
    <button
      onClick={onClick}
      disabled={disabled || loading}
      className={cn("flex h-8 items-center justify-center gap-1 rounded-lg text-[11px] font-black disabled:cursor-not-allowed disabled:opacity-45", toneClass(tone, "badge"))}
    >
      {loading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : null}
      {label}
    </button>
  );
}

function AdminInput({ label, value, onChange, type = "text" }: { label: string; value: string; onChange: (value: string) => void; type?: string }) {
  return (
    <label className="block text-[11px] font-black uppercase text-slate-500">
      {label}
      <input
        type={type}
        value={value}
        onChange={(event) => onChange(event.target.value)}
        className="mt-1 h-10 w-full rounded-lg border-white/10 bg-ink-900 text-sm font-bold text-white"
      />
    </label>
  );
}

function StatusBadge({ status, compact = false }: { status: string; compact?: boolean }) {
  const tone = status.includes("APPROVED") || status === "ACTIVE" ? "felt" : status.includes("PENDING") ? "gold" : status.includes("SUSPENDED") || status.includes("REJECTED") || status.includes("SELF") ? "ember" : "sky";
  return <span className={cn("w-fit rounded-md px-2 py-1 text-xs font-black uppercase", compact ? "text-[10px]" : "", toneClass(tone, "badge"))}>{status}</span>;
}

function toneClass(tone: string, variant: "soft" | "badge") {
  const palette: Record<string, Record<"soft" | "badge", string>> = {
    felt: {
      soft: "bg-felt/10 text-felt",
      badge: "bg-felt/10 text-felt"
    },
    gold: {
      soft: "bg-gold/10 text-gold",
      badge: "bg-gold/10 text-gold"
    },
    ember: {
      soft: "bg-ember/10 text-ember",
      badge: "bg-ember/10 text-ember"
    },
    sky: {
      soft: "bg-sky-400/10 text-sky-300",
      badge: "bg-sky-400/10 text-sky-300"
    }
  };

  return palette[tone]?.[variant] ?? palette.felt[variant];
}

function number(value: number) {
  return new Intl.NumberFormat("fr-FR").format(value);
}

function money(value: string) {
  return new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" }).format(Number(value));
}

function settlementLabel(outcome: "won" | "lost" | "void") {
  if (outcome === "won") return "Gagné";
  if (outcome === "lost") return "Perdu";
  return "Remboursé";
}

function defaultDateTimeLocal() {
  return toDateTimeLocal(new Date(Date.now() + 4 * 60 * 60 * 1000).toISOString());
}

function toDateTimeLocal(value: string) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "";
  const local = new Date(date.getTime() - date.getTimezoneOffset() * 60_000);
  return local.toISOString().slice(0, 16);
}

function shortHash(value: string) {
  if (value.length <= 14) return value;
  return `${value.slice(0, 7)}…${value.slice(-5)}`;
}

function formatDate(value: string) {
  return new Intl.DateTimeFormat("fr-FR", { day: "2-digit", month: "short" }).format(new Date(value));
}

function formatDateTime(value: string) {
  return new Intl.DateTimeFormat("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(value));
}
