"use client";

import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { ProjectSwitcher } from "@/features/predictions/components/project-switcher";
import { FieldRendererRegistry } from "@/features/predictions/components/fields/field-renderer-registry";
import { WeightDoubleSlider } from "@/features/predictions/components/fields/weight-double-slider";
import predictionStyles from "@/features/predictions/styles/predictions.module.css";
import {
  closePredictionGame,
  finalizePredictionGame,
  getPredictionBoard,
  getPredictionCards,
  getPredictionScoreboard,
  openPredictionGame,
  setPredictionOutcomes,
  suggestPredictionScores,
  validatePredictionScores,
} from "@/lib/predictions-client";
import {
  authenticatedFetch,
  clearSession,
  getCurrentProjectId,
  getApiUrl,
  loadSession,
  logoutSession,
  type AuthUser,
  type UserRole,
} from "@/lib/auth";
import { getMyProjects } from "@/lib/projects-client";
import { ProjectPhotoModal } from "@/features/predictions/components/project-photo-modal";
import type {
  PredictionBoardCard,
  PredictionBoardResponse,
  PredictionCard,
  PredictionDraftValue,
  PredictionScoringEntry,
  PredictionScoreboardItem,
} from "@/types/predictions";
import type { ProjectSummary } from "@/types/projects";
import styles from "./page.module.css";

type UserListItem = {
  id: string;
  username: string;
  displayName: string | null;
  profileImageUrl: string | null;
  workspaceId?: string | null;
  currentProjectId?: string | null;
  role: UserRole;
  createdAt: string;
};

type OutcomeDraftValue = { valueText: string; valueNumber: string; valueDate: string };
type OutcomeDraft = Record<string, Record<string, OutcomeDraftValue>>;
type ScoreDraft = Record<string, Record<string, string>>;
type ScoreDraftByCard = Record<string, ScoreDraft>;
type ScoresByCard = Record<string, PredictionScoringEntry[]>;
type ScoresByBabyCard = ScoresByCard;
type ScoreDraftByBabyCard = ScoreDraftByCard;
function babyCardKey(babyIndex: number, cardId: string) {
  return `${babyIndex}::${cardId}`;
}

type AdminTab = "projects" | "users" | "final";

function formatDate(value: string) {
  return new Date(value).toLocaleDateString("fr-FR");
}

function formatRawValue(
  value: { valueText: string | null; valueNumber: number | null; valueDate: string | null },
  unit?: string | null,
) {
  if (value.valueNumber != null) {
    return `${value.valueNumber}${unit ? ` ${unit}` : ""}`;
  }

  if (value.valueText && value.valueText.trim().length > 0) {
    return value.valueText;
  }

  if (value.valueDate) {
    return value.valueDate.slice(0, 10);
  }

  return "-";
}

function formatLabeledValue(
  label: string,
  value: { valueText: string | null; valueNumber: number | null; valueDate: string | null },
  unit?: string | null,
) {
  return `${label}: ${formatRawValue(value, unit)}`;
}

function buildOutcomeDraftKey(cardId: string, babyIndex: number) {
  return `${cardId}::${babyIndex}`;
}

function initializeOutcomeDraft(
  cards: PredictionCard[],
  board: PredictionBoardResponse | null,
  babyIndex: number,
) {
  const boardByCardId = new Map((board?.cards ?? []).map((card) => [card.id, card]));
  const draft: OutcomeDraft = {};

  for (const card of cards) {
    const key = buildOutcomeDraftKey(card.id, babyIndex);
    const boardCard = boardByCardId.get(card.id);
    const outcomesByField = new Map((boardCard?.outcomes ?? []).map((outcome) => [outcome.fieldId, outcome]));

    draft[key] = {};
    for (const field of card.fields) {
      const outcome = outcomesByField.get(field.id);
      draft[key][field.id] = {
        valueText: outcome?.valueText ?? "",
        valueNumber: outcome?.valueNumber != null ? `${outcome.valueNumber}` : "",
        valueDate: outcome?.valueDate ? outcome.valueDate.slice(0, 10) : "",
      };
    }
  }

  return draft;
}

function getOutcomeDraftValues(
  card: PredictionCard,
  outcomeDraft: OutcomeDraft,
  babyIndex: number,
): PredictionDraftValue[] {
  const cardDraft = outcomeDraft[buildOutcomeDraftKey(card.id, babyIndex)] ?? {};
  return card.fields.map((field) => {
    const draftValue = cardDraft[field.id] ?? { valueText: "", valueNumber: "", valueDate: "" };
    const parsedNumber = Number(draftValue.valueNumber);

    return {
      fieldId: field.id,
      valueText: draftValue.valueText,
      valueNumber:
        draftValue.valueNumber.trim().length === 0 || Number.isNaN(parsedNumber)
          ? null
          : parsedNumber,
      valueDate: draftValue.valueDate,
    };
  });
}

function createScoreDraft(entries: PredictionScoringEntry[]) {
  return entries.reduce<ScoreDraft>((accumulator, entry) => {
    accumulator[entry.id] = entry.scores.reduce<Record<string, string>>((scoreAccumulator, score) => {
      scoreAccumulator[score.fieldId] = `${score.awardedPoints ?? score.suggestedPoints}`;
      return scoreAccumulator;
    }, {});
    return accumulator;
  }, {});
}

function parsePointsInput(rawValue: string | undefined, fallback: number) {
  const parsed = Number(rawValue);
  if (Number.isNaN(parsed) || parsed < 0) {
    return fallback;
  }
  return Math.round(parsed);
}

export default function AdminPage() {
  const router = useRouter();
  const [currentUser, setCurrentUser] = useState<AuthUser | null>(null);
  const [projects, setProjects] = useState<ProjectSummary[]>([]);
  const [activeProjectId, setActiveProjectId] = useState<string | null>(getCurrentProjectId());
  const [activeAdminTab, setActiveAdminTab] = useState<AdminTab>("projects");
  const [photoModalProjectId, setPhotoModalProjectId] = useState<string | null>(null);

  const [users, setUsers] = useState<UserListItem[]>([]);
  const [message, setMessage] = useState("");
  const [loading, setLoading] = useState(false);

  const [newUsername, setNewUsername] = useState("");
  const [newDisplayName, setNewDisplayName] = useState("");
  const [newPassword, setNewPassword] = useState("");
  const [newRole, setNewRole] = useState<UserRole>("FAMILY");
  const [newProjectId, setNewProjectId] = useState("");

  const [editingUserId, setEditingUserId] = useState<string | null>(null);
  const [editUsername, setEditUsername] = useState("");
  const [editDisplayName, setEditDisplayName] = useState("");
  const [editPassword, setEditPassword] = useState("");
  const [editRole, setEditRole] = useState<UserRole>("FAMILY");

  const [predictionCards, setPredictionCards] = useState<PredictionCard[]>([]);
  const [boardsByBaby, setBoardsByBaby] = useState<Record<number, PredictionBoardResponse>>({});
  const [scoreboard, setScoreboard] = useState<PredictionScoreboardItem[]>([]);
  const [outcomeDraft, setOutcomeDraft] = useState<OutcomeDraft>({});
  const [scoresByBabyCard, setScoresByBabyCard] = useState<ScoresByBabyCard>({});
  const [scoreDraftByBabyCard, setScoreDraftByBabyCard] = useState<ScoreDraftByBabyCard>({});
  const [wizardStepIndex, setWizardStepIndex] = useState(0);
  const [predictionMessage, setPredictionMessage] = useState("");

  const apiUrl = getApiUrl();
  const isAdmin = currentUser?.role === "ADMIN";

  const primaryBoard = boardsByBaby[1] ?? null;
  const isGameOpen = primaryBoard?.game?.status === "OPEN";
  const isGameClosed = primaryBoard?.game?.status === "CLOSED";
  const isFinalized = Boolean(primaryBoard?.game?.finalized);

  const totalWorkflowSteps = predictionCards.length + 1;
  const isRecapStep = isGameClosed && !isFinalized && wizardStepIndex >= predictionCards.length;

  const currentStepCard = useMemo(
    () => (!isRecapStep ? predictionCards[wizardStepIndex] ?? null : null),
    [isRecapStep, predictionCards, wizardStepIndex],
  );

  const currentBoardCard = useMemo(() => {
    if (!currentStepCard) {
      return null;
    }

    return primaryBoard?.cards.find((card) => card.id === currentStepCard.id) ?? null;
  }, [currentStepCard, primaryBoard?.cards]);

  const activeProjectBabyCount = useMemo(() => {
    const project = projects.find((item) => item.id === activeProjectId);
    return Math.max(1, project?.babyCount ?? 1);
  }, [activeProjectId, projects]);

  const currentScoringEntriesByBaby = useMemo(() => {
    if (!currentStepCard) {
      return {};
    }

    const result: Record<number, PredictionScoringEntry[]> = {};
    for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
      result[babyIdx] = scoresByBabyCard[babyCardKey(babyIdx, currentStepCard.id)] ?? [];
    }
    return result;
  }, [currentStepCard, scoresByBabyCard, activeProjectBabyCount]);

  const currentScoreDraftByBaby = useMemo(() => {
    if (!currentStepCard) {
      return {};
    }

    const result: Record<number, ScoreDraft> = {};
    for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
      result[babyIdx] = scoreDraftByBabyCard[babyCardKey(babyIdx, currentStepCard.id)] ?? {};
    }
    return result;
  }, [currentStepCard, scoreDraftByBabyCard, activeProjectBabyCount]);

  const totalsByUserId = useMemo(() => {
    return new Map(scoreboard.map((item) => [item.userId, item.totalPoints]));
  }, [scoreboard]);

  const winnerSummary = useMemo(() => {
    if (scoreboard.length === 0) {
      return null;
    }

    const maxPoints = scoreboard[0].totalPoints;
    const winners = scoreboard.filter((item) => item.totalPoints === maxPoints);
    return {
      points: maxPoints,
      winners,
    };
  }, [scoreboard]);

  const remainingEntriesToScore = useMemo(() => {
    let total = 0;
    for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
      const board = boardsByBaby[babyIdx];
      if (!board) continue;
      for (const card of board.cards) {
        total += card.entries.filter((entry) => !entry.isScored).length;
      }
    }
    return total;
  }, [boardsByBaby, activeProjectBabyCount]);

  const canFinalizeContest = isGameClosed && !isFinalized && remainingEntriesToScore === 0 && predictionCards.length > 0;

  const activeProjectName = useMemo(() => {
    return projects.find((project) => project.id === activeProjectId)?.name ?? null;
  }, [activeProjectId, projects]);

  const getBabyLabel = useCallback((idx: number): string => {
    const project = projects.find((p) => p.id === activeProjectId);
    return project?.babies?.find((b) => b.babyIndex === idx)?.label ?? `Bébé ${idx}`;
  }, [activeProjectId, projects]);

  const handleProjectChanged = useCallback((projectId: string) => {
    setActiveProjectId((current) => (current === projectId ? current : projectId));
    setPredictionMessage("");
  }, []);

  useEffect(() => {
    const session = loadSession();

    if (!session) {
      router.replace("/");
      return;
    }

    if (session.user.role !== "ADMIN") {
      router.replace("/predictions");
      return;
    }

    setCurrentUser(session.user);
    setActiveProjectId(session.user.currentProjectId ?? null);
  }, [router]);

  useEffect(() => {
    setWizardStepIndex((current) => Math.min(current, predictionCards.length));
  }, [predictionCards.length]);

  const loadUsers = async () => {
    const response = await authenticatedFetch(apiUrl, "/users");
    const payload = (await response.json()) as UserListItem[] | { message?: string };

    if (!response.ok || !Array.isArray(payload)) {
      throw new Error((payload as { message?: string }).message ?? "Impossible de charger les utilisateurs");
    }

    setUsers(payload);
  };

  const loadProjects = async () => {
    const payload = await getMyProjects();
    setProjects(payload);

    if (payload.length === 0) {
      setNewProjectId("");
      setActiveProjectId(null);
      return null;
    }

    const currentProjectId = getCurrentProjectId();
    const selectedProject = payload.find((project) => project.id === currentProjectId) ?? payload[0];

    if (selectedProject) {
      setActiveProjectId(selectedProject.id);
      setNewProjectId((current) => current || selectedProject.id);
      return selectedProject.id;
    }

    return null;
  };

  const loadPredictionAdminData = async (projectId?: string | null) => {
    const scopedProjectId = projectId ?? getCurrentProjectId();

    if (!scopedProjectId) {
      setPredictionCards([]);
      setBoardsByBaby({});
      setScoreboard([]);
      setOutcomeDraft({});
      setScoresByBabyCard({});
      setScoreDraftByBabyCard({});
      setWizardStepIndex(0);
      return;
    }

    const project = projects.find((p) => p.id === scopedProjectId);
    const babyCount = Math.max(1, project?.babyCount ?? 1);

    const boardPromises = Array.from({ length: babyCount }, (_, i) =>
      getPredictionBoard(scopedProjectId, i + 1),
    );

    const [cards, nextScoreboard, ...boards] = await Promise.all([
      getPredictionCards(scopedProjectId),
      getPredictionScoreboard(scopedProjectId),
      ...boardPromises,
    ]);

    setPredictionCards(cards);
    setScoreboard(nextScoreboard);

    const newBoardsByBaby: Record<number, PredictionBoardResponse> = {};
    const allOutcomeDrafts: OutcomeDraft = {};

    for (let i = 0; i < boards.length; i++) {
      const babyIdx = i + 1;
      newBoardsByBaby[babyIdx] = boards[i];
      const draft = initializeOutcomeDraft(cards, boards[i], babyIdx);
      Object.assign(allOutcomeDrafts, draft);
    }

    setBoardsByBaby(newBoardsByBaby);
    setOutcomeDraft((current) => ({ ...current, ...allOutcomeDrafts }));
  };

  useEffect(() => {
    if (!isAdmin) {
      return;
    }

    Promise.all([loadUsers(), loadProjects()])
      .then(async ([, selectedProjectId]) => {
        await loadPredictionAdminData(selectedProjectId);
      })
      .catch((error: unknown) => {
        if (error instanceof Error && error.message.includes("Session manquante")) {
          clearSession();
          setCurrentUser(null);
          router.replace("/");
        }
        setMessage("Impossible de charger les donnees admin");
      });
  }, [isAdmin, activeProjectId, router]);

  useEffect(() => {
    setScoresByBabyCard({});
    setScoreDraftByBabyCard({});
    setWizardStepIndex(0);
  }, [primaryBoard?.game?.status, primaryBoard?.game?.finalized]);

  useEffect(() => {
    if (!isGameClosed || isFinalized || isRecapStep || !currentStepCard) {
      return;
    }

    const missingBabies: number[] = [];
    for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
      const key = babyCardKey(babyIdx, currentStepCard.id);
      if (!Object.prototype.hasOwnProperty.call(scoresByBabyCard, key)) {
        missingBabies.push(babyIdx);
      }
    }

    if (missingBabies.length === 0) {
      return;
    }

    setLoading(true);
    setPredictionMessage("");

    Promise.all(
      missingBabies.map((babyIdx) =>
        suggestPredictionScores(currentStepCard.id, activeProjectId, babyIdx).then((entries) => ({
          babyIdx,
          entries,
        })),
      ),
    )
      .then((results) => {
        setScoresByBabyCard((current) => {
          const next = { ...current };
          for (const { babyIdx, entries } of results) {
            next[babyCardKey(babyIdx, currentStepCard.id)] = entries;
          }
          return next;
        });
        setScoreDraftByBabyCard((current) => {
          const next = { ...current };
          for (const { babyIdx, entries } of results) {
            next[babyCardKey(babyIdx, currentStepCard.id)] = createScoreDraft(entries);
          }
          return next;
        });
      })
      .catch((error) => {
        setPredictionMessage(error instanceof Error ? error.message : "Erreur de chargement de l'etape");
      })
      .finally(() => {
        setLoading(false);
      });
  }, [
    activeProjectBabyCount,
    activeProjectId,
    currentStepCard,
    isFinalized,
    isGameClosed,
    isRecapStep,
    scoresByBabyCard,
  ]);

  const onCreateUser = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setLoading(true);
    setMessage("");

    try {
      const response = await authenticatedFetch(apiUrl, "/users", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          username: newUsername,
          displayName: newDisplayName || undefined,
          password: newPassword,
          role: newRole,
          projectId: newRole === "FAMILY" ? newProjectId || undefined : undefined,
        }),
      });

      const payload = (await response.json()) as { message?: string };

      if (!response.ok) {
        setMessage(payload.message ?? "Creation impossible");
        return;
      }

      setNewUsername("");
      setNewDisplayName("");
      setNewPassword("");
      setNewRole("FAMILY");
      setNewProjectId((current) => current || projects[0]?.id || "");
      setMessage("Compte cree");
      await loadUsers();
    } catch {
      setMessage("Erreur reseau pendant la creation");
    } finally {
      setLoading(false);
    }
  };

  const startEdit = (user: UserListItem) => {
    setEditingUserId(user.id);
    setEditUsername(user.username);
    setEditDisplayName(user.displayName ?? "");
    setEditPassword("");
    setEditRole(user.role);
  };

  const cancelEdit = () => {
    setEditingUserId(null);
    setEditUsername("");
    setEditDisplayName("");
    setEditPassword("");
    setEditRole("FAMILY");
  };

  const onSaveEdit = async (userId: string) => {
    setLoading(true);
    setMessage("");

    const body: {
      username?: string;
      displayName?: string;
      password?: string;
      role?: UserRole;
    } = {};
    if (editUsername.trim()) body.username = editUsername.trim();
    if (editDisplayName.trim().length >= 2) {
      body.displayName = editDisplayName.trim();
    }
    if (editPassword.trim()) body.password = editPassword;
    body.role = editRole;

    try {
      const response = await authenticatedFetch(apiUrl, `/users/${userId}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });

      const payload = (await response.json()) as { message?: string };

      if (!response.ok) {
        setMessage(payload.message ?? "Mise a jour impossible");
        return;
      }

      setMessage("Compte mis a jour");
      cancelEdit();
      await loadUsers();
    } catch {
      setMessage("Erreur reseau pendant la mise a jour");
    } finally {
      setLoading(false);
    }
  };

  const onDeleteUser = async (userId: string) => {
    setLoading(true);
    setMessage("");

    try {
      const response = await authenticatedFetch(apiUrl, `/users/${userId}`, {
        method: "DELETE",
      });

      const payload = (await response.json()) as { message?: string };

      if (!response.ok) {
        setMessage(payload.message ?? "Suppression impossible");
        return;
      }

      setMessage("Compte supprime");
      await loadUsers();
    } catch {
      setMessage("Erreur reseau pendant la suppression");
    } finally {
      setLoading(false);
    }
  };

  const onAssignUserProject = async (userId: string, projectId: string) => {
    setLoading(true);
    setMessage("");

    try {
      const response = await authenticatedFetch(apiUrl, `/users/${userId}/project`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          projectId: projectId || undefined,
        }),
      });

      const payload = (await response.json()) as { message?: string };

      if (!response.ok) {
        setMessage(payload.message ?? "Affectation de projet impossible");
        return;
      }

      setMessage("Projet utilisateur mis a jour");
      await loadUsers();
    } catch {
      setMessage("Erreur reseau pendant l'affectation projet");
    } finally {
      setLoading(false);
    }
  };

  const patchOutcomeDraft = (
    cardId: string,
    babyIndex: number,
    fieldId: string,
    patch: Partial<OutcomeDraftValue>,
  ) => {
    const key = buildOutcomeDraftKey(cardId, babyIndex);

    setOutcomeDraft((current) => ({
      ...current,
      [key]: {
        ...(current[key] ?? {}),
        [fieldId]: {
          ...(current[key]?.[fieldId] ?? {
            valueText: "",
            valueNumber: "",
            valueDate: "",
          }),
          ...patch,
        },
      },
    }));
  };

  const onToggleGame = async () => {
    if (!primaryBoard?.game) {
      return;
    }

    if (primaryBoard.game.status === "CLOSED" && isFinalized) {
      setPredictionMessage("Concours deja valide: reouverture de La Grande Revelation impossible.");
      return;
    }

    setPredictionMessage("");
    setLoading(true);

    try {
      if (primaryBoard.game.status === "OPEN") {
        await closePredictionGame(activeProjectId);
        setPredictionMessage("La Grande Revelation est cloturee. Passage en mode notation par etapes.");
      } else {
        await openPredictionGame(activeProjectId);
        setPredictionMessage("La Grande Revelation est reouverte. Tu peux encore corriger les valeurs finales.");
      }

      await loadPredictionAdminData();
    } catch (error) {
      setPredictionMessage(error instanceof Error ? error.message : "Erreur de changement d'etat du concours");
    } finally {
      setLoading(false);
    }
  };

  const onSaveOutcomes = async () => {
    if (!isGameOpen) {
      setPredictionMessage("La saisie des valeurs finales est fermee.");
      return;
    }

    if (predictionCards.length === 0) {
      setPredictionMessage("Aucune categorie disponible.");
      return;
    }

    setLoading(true);
    setPredictionMessage("");

    let submittedCards = 0;

    try {
      for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
        for (const card of predictionCards) {
          const cardDraft = outcomeDraft[buildOutcomeDraftKey(card.id, babyIdx)] ?? {};
          const values = card.fields
            .map((field) => {
              const draft = cardDraft[field.id] ?? { valueText: "", valueNumber: "", valueDate: "" };

              if (card.valueType === "NUMBER") {
                const parsed = Number(draft.valueNumber);
                if (Number.isNaN(parsed)) {
                  return null;
                }
                return { fieldId: field.id, valueNumber: parsed };
              }

              if (card.valueType === "DATE") {
                if (!draft.valueDate) {
                  return null;
                }
                return { fieldId: field.id, valueDate: draft.valueDate };
              }

              if (!draft.valueText.trim()) {
                return null;
              }

              return { fieldId: field.id, valueText: draft.valueText.trim() };
            })
            .filter((value): value is NonNullable<typeof value> => value != null);

          if (values.length === 0) {
            continue;
          }

          await setPredictionOutcomes(card.id, { selectedBabyIndex: babyIdx, values }, activeProjectId);
          submittedCards += 1;
        }
      }

      if (submittedCards === 0) {
        setPredictionMessage("Aucune valeur finale detectee a enregistrer.");
      } else {
        setPredictionMessage(`${submittedCards} valeur(s) de resultats enregistree(s) pour ${activeProjectBabyCount} bebe(s).`);
      }

      await loadPredictionAdminData();
    } catch (error) {
      setPredictionMessage(error instanceof Error ? error.message : "Erreur pendant l'enregistrement des resultats");
    } finally {
      setLoading(false);
    }
  };

  const onRefreshStepSuggestions = async () => {
    if (!currentStepCard) {
      return;
    }

    setLoading(true);
    setPredictionMessage("");

    try {
      const results = await Promise.all(
        Array.from({ length: activeProjectBabyCount }, (_, i) => i + 1).map((babyIdx) =>
          suggestPredictionScores(currentStepCard.id, activeProjectId, babyIdx).then((entries) => ({
            babyIdx,
            entries,
          })),
        ),
      );

      setScoresByBabyCard((current) => {
        const next = { ...current };
        for (const { babyIdx, entries } of results) {
          next[babyCardKey(babyIdx, currentStepCard.id)] = entries;
        }
        return next;
      });
      setScoreDraftByBabyCard((current) => {
        const next = { ...current };
        for (const { babyIdx, entries } of results) {
          next[babyCardKey(babyIdx, currentStepCard.id)] = createScoreDraft(entries);
        }
        return next;
      });
      setPredictionMessage(`Suggestions de points recalculees pour ${currentStepCard.title}.`);
    } catch (error) {
      setPredictionMessage(error instanceof Error ? error.message : "Erreur pendant le recalcul des points");
    } finally {
      setLoading(false);
    }
  };

  const onScoreChange = (babyIdx: number, cardId: string, entryId: string, fieldId: string, value: string) => {
    const key = babyCardKey(babyIdx, cardId);
    setScoreDraftByBabyCard((current) => ({
      ...current,
      [key]: {
        ...(current[key] ?? {}),
        [entryId]: {
          ...(current[key]?.[entryId] ?? {}),
          [fieldId]: value,
        },
      },
    }));
  };

  const getStepPointsTotal = (babyIdx: number, entry: PredictionScoringEntry) => {
    if (!currentStepCard) {
      return 0;
    }

    const key = babyCardKey(babyIdx, currentStepCard.id);
    const draft = scoreDraftByBabyCard[key]?.[entry.id] ?? {};

    return entry.scores.reduce((total, score) => {
      return total + parsePointsInput(draft[score.fieldId], score.awardedPoints ?? score.suggestedPoints);
    }, 0);
  };

  const onValidateCurrentStep = async () => {
    if (!currentStepCard) {
      return;
    }

    let hasEntries = false;
    for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
      const entries = scoresByBabyCard[babyCardKey(babyIdx, currentStepCard.id)] ?? [];
      if (entries.length > 0) {
        hasEntries = true;
        break;
      }
    }

    if (!hasEntries) {
      setPredictionMessage("Aucun participant a noter sur cette categorie.");
      setWizardStepIndex((current) => Math.min(current + 1, predictionCards.length));
      return;
    }

    setLoading(true);
    setPredictionMessage("");

    try {
      for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
        const key = babyCardKey(babyIdx, currentStepCard.id);
        const entries = scoresByBabyCard[key] ?? [];

        for (const entry of entries) {
          const draftByField = scoreDraftByBabyCard[key]?.[entry.id] ?? {};
          const scores = entry.scores.map((score) => ({
            fieldId: score.fieldId,
            awardedPoints: parsePointsInput(draftByField[score.fieldId], score.awardedPoints ?? score.suggestedPoints),
          }));

          await validatePredictionScores(entry.id, { scores });
        }
      }

      setScoresByBabyCard((current) => {
        const next = { ...current };
        for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
          delete next[babyCardKey(babyIdx, currentStepCard.id)];
        }
        return next;
      });
      setScoreDraftByBabyCard((current) => {
        const next = { ...current };
        for (let babyIdx = 1; babyIdx <= activeProjectBabyCount; babyIdx++) {
          delete next[babyCardKey(babyIdx, currentStepCard.id)];
        }
        return next;
      });

      await loadPredictionAdminData();
      setPredictionMessage(`Categorie ${currentStepCard.title} validee pour ${activeProjectBabyCount} bebe(s).`);
      setWizardStepIndex((current) => Math.min(current + 1, predictionCards.length));
    } catch (error) {
      setPredictionMessage(error instanceof Error ? error.message : "Erreur pendant la validation des points");
    } finally {
      setLoading(false);
    }
  };

  const onFinalizeContest = async () => {
    setLoading(true);
    setPredictionMessage("");

    try {
      const result = await finalizePredictionGame(activeProjectId);
      const names = result.winners
        .map((winner) => winner.displayName ?? winner.username)
        .join(" / ");
      setPredictionMessage(`Concours valide. Gagnant(s): ${names}.`);
      await loadPredictionAdminData();
    } catch (error) {
      setPredictionMessage(error instanceof Error ? error.message : "Erreur pendant la validation finale du concours");
    } finally {
      setLoading(false);
    }
  };

  const logout = async () => {
    await logoutSession(apiUrl);
    setCurrentUser(null);
    setUsers([]);
    setPredictionCards([]);
    setBoardsByBaby({});
    setScoreboard([]);
    setMessage("Deconnecte");
    window.location.replace("/");
  };

  const renderOutcomeCard = (card: PredictionCard, babyIdx: number, boardCard: PredictionBoardCard | null) => {
    const draftValues = getOutcomeDraftValues(card, outcomeDraft, babyIdx);
    const weightField = card.code === "legacy_weight" ? card.fields[0] : null;
    const weightValue =
      weightField == null
        ? null
        : draftValues.find((value) => value.fieldId === weightField.id)?.valueNumber ?? null;

    return (
      <article
        key={`${card.id}-${babyIdx}`}
        className={`${predictionStyles.tile} ${card.code === "legacy_weight" ? predictionStyles.tileFavorite : ""}`}
      >
        <header className={predictionStyles.tileHeader}>
          <div>
            <h3>{card.title}</h3>
            {card.description ? <p>{card.description}</p> : null}
          </div>
          <span className={predictionStyles.badge}>Resultat final</span>
        </header>

        <div className={predictionStyles.tileBody}>
          {weightField ? (
            <WeightDoubleSlider
              valueKg={weightValue}
              minKg={weightField.minNumber ?? 1}
              maxKg={weightField.maxNumber ?? 6}
              disabled={loading || !isGameOpen}
              onChange={(nextValueKg) => {
                patchOutcomeDraft(card.id, babyIdx, weightField.id, {
                  valueNumber: nextValueKg.toFixed(3),
                });
              }}
            />
          ) : (
            <FieldRendererRegistry
              card={card}
              draftValues={draftValues}
              disabled={loading || !isGameOpen}
              setText={(fieldId, value) => {
                patchOutcomeDraft(card.id, babyIdx, fieldId, { valueText: value });
              }}
              setNumber={(fieldId, value) => {
                patchOutcomeDraft(card.id, babyIdx, fieldId, { valueNumber: value == null ? "" : `${value}` });
              }}
              setDate={(fieldId, value) => {
                patchOutcomeDraft(card.id, babyIdx, fieldId, { valueDate: value });
              }}
            />
          )}
          <p className={styles.helpText}>
            Valeur actuellement enregistree: {boardCard?.outcomes.length
              ? boardCard.outcomes
                .map((outcome) =>
                  formatLabeledValue(outcome.fieldLabel, {
                    valueText: outcome.valueText,
                    valueNumber: outcome.valueNumber,
                    valueDate: outcome.valueDate,
                  }, card.unit),
                )
                .join(" | ")
              : "Aucune valeur encore sauvegardee"}
          </p>
        </div>
      </article>
    );
  };

  return (
    <main className={`app-shell ${styles.page}`}>
      <section className={`panel ${styles.header}`}>
        <div>
          <p className="mono">Le Juste Poids / Admin</p>
          <h1>Gestion des comptes famille</h1>
        </div>
        <div className={styles.actions}>
          <Link className="btn btn-soft" href="/profile">
            Mon profil
          </Link>
          {currentUser ? (
            <button type="button" className="btn btn-soft" onClick={logout}>
              Se deconnecter
            </button>
          ) : null}
        </div>
      </section>

      {!currentUser || !isAdmin ? (
        <section className={`panel ${styles.loginPanel}`}>
          <p>Redirection vers la page de connexion...</p>
        </section>
      ) : (
        <>
          <section className={`panel ${styles.adminTabs}`}>
            <button
              type="button"
              className={`${styles.adminTab} ${activeAdminTab === "projects" ? styles.adminTabActive : ""}`}
              onClick={() => setActiveAdminTab("projects")}
            >
              Gestion des projets
            </button>
            <button
              type="button"
              className={`${styles.adminTab} ${activeAdminTab === "users" ? styles.adminTabActive : ""}`}
              onClick={() => setActiveAdminTab("users")}
            >
              Comptes utilisateurs
            </button>
            <button
              type="button"
              className={`${styles.adminTab} ${activeAdminTab === "final" ? styles.adminTabActive : ""}`}
              onClick={() => setActiveAdminTab("final")}
            >
              La Grande Revelation
            </button>
          </section>

          {activeAdminTab === "projects" ? (
            <section className={`panel ${styles.projectPanel}`}>
              <div className={styles.projectPanelHeader}>
                <div>
                  <h2>Gestion des projets</h2>
                  <p className={styles.helpText}>
                    Cree, clone et selectionne un projet. Ouvre ensuite La Grande Revelation dans l onglet dedie.
                  </p>
                </div>
                <Link className="btn btn-primary" href="/admin/projects/new">
                  Nouveau projet
                </Link>
              </div>
              <ProjectSwitcher onProjectChanged={handleProjectChanged} />
              {projects.length === 0 ? (
                <p className={styles.message}>
                  Aucun projet pour le moment. Commence par creer le premier projet via le wizard.
                </p>
              ) : (
                <div className={styles.projectList}>
                  {projects.map((project) => (
                    <article key={project.id} className={styles.projectItem}>
                      <div>
                        <strong>{project.name}</strong>
                        <p className={styles.helpText}>
                          {project.babyCount} bebe{project.babyCount > 1 ? "s" : ""} • {project.status}
                        </p>
                      </div>
                      <div style={{ display: "flex", gap: "0.5rem", flexWrap: "wrap" }}>
                        <Link
                          className="btn btn-soft"
                          href={`/admin/projects/${project.id}/indices`}
                        >
                          Configurer les indices
                        </Link>
                        <button
                          className="btn btn-soft"
                          onClick={() => setPhotoModalProjectId(project.id)}
                        >
                          Photo du projet
                        </button>
                        <button
                          className="btn btn-soft"
                          onClick={() => {
                            handleProjectChanged(project.id);
                            setActiveAdminTab("final");
                          }}
                        >
                          Ouvrir La Grande Revelation
                        </button>
                      </div>
                    </article>
                  ))}
                </div>
              )}

              {photoModalProjectId ? (() => {
                const modalProject = projects.find((p) => p.id === photoModalProjectId);
                return modalProject ? (
                  <ProjectPhotoModal
                    project={modalProject}
                    onSuccess={(updated) => {
                      setProjects((prev) => prev.map((p) => p.id === updated.id ? updated : p));
                    }}
                    onClose={() => setPhotoModalProjectId(null)}
                  />
                ) : null;
              })() : null}
            </section>
          ) : null}

          {activeAdminTab === "users" ? (
            <>
              <section className={`panel ${styles.createPanel}`}>
                <h2>Creer un compte</h2>
                <form onSubmit={onCreateUser} className={styles.createForm}>
                  <div className="field">
                    <label htmlFor="newUsername">Username</label>
                    <input
                      id="newUsername"
                      value={newUsername}
                      onChange={(event) => setNewUsername(event.target.value)}
                    />
                  </div>
                  <div className="field">
                    <label htmlFor="newDisplayName">Pseudo</label>
                    <input
                      id="newDisplayName"
                      value={newDisplayName}
                      onChange={(event) => setNewDisplayName(event.target.value)}
                    />
                  </div>
                  <div className="field">
                    <label htmlFor="newPassword">Mot de passe</label>
                    <input
                      id="newPassword"
                      type="password"
                      value={newPassword}
                      onChange={(event) => setNewPassword(event.target.value)}
                    />
                  </div>
                  <div className="field">
                    <label htmlFor="newRole">Role</label>
                    <select
                      id="newRole"
                      value={newRole}
                      onChange={(event) => setNewRole(event.target.value as UserRole)}
                    >
                      <option value="FAMILY">FAMILY</option>
                      <option value="ADMIN">ADMIN</option>
                    </select>
                  </div>
                  {newRole === "FAMILY" ? (
                    <div className="field">
                      <label htmlFor="newProjectId">Projet associe</label>
                      <select
                        id="newProjectId"
                        value={newProjectId}
                        onChange={(event) => setNewProjectId(event.target.value)}
                      >
                        <option value="">Sans projet</option>
                        {projects.map((project) => (
                          <option key={project.id} value={project.id}>
                            {project.name}
                          </option>
                        ))}
                      </select>
                    </div>
                  ) : null}
                  <button className="btn btn-primary" disabled={loading}>
                    Creer
                  </button>
                </form>
                {message ? <p className={styles.message}>{message}</p> : null}
              </section>

              <section className={`panel ${styles.tablePanel}`}>
                <h2>Comptes existants</h2>
                <div className={styles.tableWrapper}>
                  <table>
                    <thead>
                      <tr>
                        <th>Username</th>
                        <th>Pseudo</th>
                        <th>Role</th>
                        <th>Projet</th>
                        <th>Cree le</th>
                        <th>Actions</th>
                      </tr>
                    </thead>
                    <tbody>
                      {users.map((user) => (
                        <tr key={user.id}>
                          <td>
                            {editingUserId === user.id ? (
                              <input
                                value={editUsername}
                                onChange={(event) => setEditUsername(event.target.value)}
                              />
                            ) : (
                              user.username
                            )}
                          </td>
                          <td>
                            {editingUserId === user.id ? (
                              <input
                                value={editDisplayName}
                                onChange={(event) => setEditDisplayName(event.target.value)}
                              />
                            ) : (
                              user.displayName ?? "-"
                            )}
                          </td>
                          <td>
                            {editingUserId === user.id ? (
                              <select
                                value={editRole}
                                onChange={(event) => setEditRole(event.target.value as UserRole)}
                              >
                                <option value="FAMILY">FAMILY</option>
                                <option value="ADMIN">ADMIN</option>
                              </select>
                            ) : (
                              user.role
                            )}
                          </td>
                          <td>
                            {user.role === "FAMILY" ? (
                              <select
                                value={user.currentProjectId ?? ""}
                                onChange={(event) => {
                                  void onAssignUserProject(user.id, event.target.value);
                                }}
                                disabled={loading}
                              >
                                <option value="">Sans projet</option>
                                {projects.map((project) => (
                                  <option key={`${user.id}-${project.id}`} value={project.id}>
                                    {project.name}
                                  </option>
                                ))}
                              </select>
                            ) : (
                              <span className={styles.helpText}>Admin scope espace</span>
                            )}
                          </td>
                          <td className="mono">{formatDate(user.createdAt)}</td>
                          <td>
                            <div className={styles.rowActions}>
                              {editingUserId === user.id ? (
                                <>
                                  <input
                                    type="password"
                                    placeholder="Nouveau mot de passe (optionnel)"
                                    value={editPassword}
                                    onChange={(event) => setEditPassword(event.target.value)}
                                  />
                                  <button
                                    className="btn btn-primary"
                                    onClick={() => onSaveEdit(user.id)}
                                    disabled={loading}
                                  >
                                    Sauver
                                  </button>
                                  <button className="btn btn-soft" onClick={cancelEdit}>
                                    Annuler
                                  </button>
                                </>
                              ) : (
                                <>
                                  <button className="btn btn-soft" onClick={() => startEdit(user)}>
                                    Editer
                                  </button>
                                  <button
                                    className="btn btn-soft"
                                    onClick={() => onDeleteUser(user.id)}
                                    disabled={loading}
                                  >
                                    Supprimer
                                  </button>
                                </>
                              )}
                            </div>
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </section>
            </>
          ) : null}

          {activeAdminTab === "final" ? (
            <section className={`panel ${styles.predictionPanel}`}>
              <h2>La Grande Revelation</h2>
              <ProjectSwitcher onProjectChanged={handleProjectChanged} />
              {!activeProjectId ? (
                <p className={styles.helpText}>
                  Selectionne ou cree d abord un projet pour activer La Grande Revelation.
                </p>
              ) : (
                <>
                  <p className={styles.helpText}>
                    Projet actif: {activeProjectName ?? "Projet selectionne"}
                    {activeProjectBabyCount > 1 ? ` — ${activeProjectBabyCount} bebes` : ""}
                  </p>
                  <p className={styles.helpText}>
                    Une fois bebe arrive et ses caracteristiques connues, renseigne ici les resultats finaux.
                    Ensuite, cloture le concours pour lancer la notation et decouvrir qui a gagne.
                  </p>
                </>
              )}

              {!activeProjectId ? null : (
                <>
                  <div className={styles.predictionActions}>
                    <Link className="btn btn-soft" href={`/admin/projects/${activeProjectId}/indices`}>
                      Ouvrir les indices de ce projet
                    </Link>
                  </div>

                  <div className={styles.predictionActions}>
                    <span className={styles.statusPill}>
                      Etat: {isGameOpen ? "OUVERT" : isFinalized ? "CLOTURE ET VALIDE" : "CLOTURE"}
                    </span>
                    <button className="btn btn-primary" onClick={onToggleGame} disabled={loading || !primaryBoard?.game}>
                      {isGameOpen ? "Cloturer La Grande Revelation et lancer la notation" : "Reouvrir La Grande Revelation"}
                    </button>
                  </div>

                  {isGameOpen ? (
                    <>
                      <h3>1. Saisie des valeurs finales</h3>
                      <p className={styles.helpText}>
                        Renseigne les resultats finaux pour {activeProjectBabyCount > 1 ? "chaque bebe" : "le bebe"}.
                      </p>

                      {activeProjectBabyCount > 1 ? (
                        <div className={styles.babyColumnsGrid} style={{ gridTemplateColumns: `repeat(${activeProjectBabyCount}, 1fr)` }}>
                          {Array.from({ length: activeProjectBabyCount }, (_, i) => i + 1).map((babyIdx) => (
                            <div key={babyIdx} className={styles.babyColumn}>
                              <h4 className={styles.babyColumnHeader}>{getBabyLabel(babyIdx)}</h4>
                              {predictionCards.map((card) => renderOutcomeCard(
                                card,
                                babyIdx,
                                boardsByBaby[babyIdx]?.cards.find((c) => c.id === card.id) ?? null,
                              ))}
                            </div>
                          ))}
                        </div>
                      ) : (
                        <div className={predictionStyles.tilesGrid}>
                          {predictionCards.map((card) => renderOutcomeCard(
                            card,
                            1,
                            boardsByBaby[1]?.cards.find((c) => c.id === card.id) ?? null,
                          ))}
                        </div>
                      )}

                      <div className={styles.predictionActions}>
                        <button className="btn btn-primary" onClick={onSaveOutcomes} disabled={loading}>
                          Enregistrer les valeurs finales{activeProjectBabyCount > 1 ? " (tous les bebes)" : ""}
                        </button>
                      </div>
                    </>
                  ) : null}

                  {isGameClosed && !isFinalized ? (
                    <div className={styles.wizardPanel}>
                      <div className={styles.wizardHeader}>
                        <h3>2. Notation par categorie</h3>
                        <span className={styles.stepPill}>
                          Etape {Math.min(wizardStepIndex + 1, totalWorkflowSteps)} / {totalWorkflowSteps}
                        </span>
                      </div>

                      {!isRecapStep && currentStepCard ? (
                        <>
                          <div className={styles.outcomeSummary}>
                            <strong>Categorie: {currentStepCard.title}</strong>
                            {Array.from({ length: activeProjectBabyCount }, (_, i) => i + 1).map((babyIdx) => {
                              const board = boardsByBaby[babyIdx];
                              const boardCard = board?.cards.find((c) => c.id === currentStepCard.id);
                              return (
                                <p key={babyIdx}>
                                  {activeProjectBabyCount > 1 ? `${getBabyLabel(babyIdx)}: ` : "Resultat final: "}
                                  {boardCard?.outcomes.length
                                    ? boardCard.outcomes
                                      .map((outcome) =>
                                        formatLabeledValue(outcome.fieldLabel, {
                                          valueText: outcome.valueText,
                                          valueNumber: outcome.valueNumber,
                                          valueDate: outcome.valueDate,
                                        }, currentStepCard.unit),
                                      )
                                      .join(" | ")
                                    : "Aucun resultat final sauvegarde"}
                                </p>
                              );
                            })}
                          </div>

                          <div className={styles.wizardActions}>
                            <button className="btn btn-soft" onClick={onRefreshStepSuggestions} disabled={loading}>
                              Recalculer les suggestions auto
                            </button>
                          </div>

                          {activeProjectBabyCount > 1 ? (
                            <div className={styles.babyColumnsGrid} style={{ gridTemplateColumns: `repeat(${activeProjectBabyCount}, 1fr)` }}>
                              {Array.from({ length: activeProjectBabyCount }, (_, i) => i + 1).map((babyIdx) => {
                                const entries = currentScoringEntriesByBaby[babyIdx] ?? [];
                                const board = boardsByBaby[babyIdx];
                                const boardCard = board?.cards.find((c) => c.id === currentStepCard.id);
                                const draft = currentScoreDraftByBaby[babyIdx] ?? {};

                                return (
                                  <div key={babyIdx} className={styles.babyColumn}>
                                    <h4 className={styles.babyColumnHeader}>{getBabyLabel(babyIdx)}</h4>
                                    {entries.length === 0 ? (
                                      <p className={predictionStyles.empty}>Aucun participant pour ce bebe.</p>
                                    ) : (
                                      <div className={styles.candidateList}>
                                        {entries.map((entry) => {
                                          const boardEntry = boardCard?.entries.find((item) => item.entryId === entry.id) ?? null;
                                          const participantName = entry.user.displayName ?? entry.user.username;
                                          const currentTotal = totalsByUserId.get(entry.userId) ?? 0;

                                          return (
                                            <article key={entry.id} className={styles.candidateCard}>
                                              <div className={styles.candidateHeader}>
                                                <strong>{participantName}</strong>
                                                <span className={styles.statusPill}>Total: {currentTotal} pts</span>
                                              </div>
                                              <p className={styles.candidateMeta}>
                                                {boardEntry?.values.length
                                                  ? boardEntry.values
                                                    .map((value) =>
                                                      formatLabeledValue(value.fieldLabel, {
                                                        valueText: value.valueText,
                                                        valueNumber: value.valueNumber,
                                                        valueDate: value.valueDate,
                                                      }, currentStepCard.unit),
                                                    )
                                                    .join(" | ")
                                                  : "Aucune reponse"}
                                              </p>
                                              <div className={styles.scoreInputs}>
                                                {entry.scores.map((score) => (
                                                  <label key={`${entry.id}-${score.fieldId}`} className={styles.scoreInputRow}>
                                                    <span>
                                                      {score.field.label} — {score.field.points} pts max
                                                    </span>
                                                    <input
                                                      type="number"
                                                      min={0}
                                                      value={draft[entry.id]?.[score.fieldId] ?? `${score.awardedPoints ?? score.suggestedPoints}`}
                                                      onChange={(event) => {
                                                        onScoreChange(babyIdx, currentStepCard.id, entry.id, score.fieldId, event.target.value);
                                                      }}
                                                    />
                                                  </label>
                                                ))}
                                              </div>
                                              <p className={styles.candidateMeta}>Points: {getStepPointsTotal(babyIdx, entry)}</p>
                                            </article>
                                          );
                                        })}
                                      </div>
                                    )}
                                  </div>
                                );
                              })}
                            </div>
                          ) : (
                            <>
                              {(currentScoringEntriesByBaby[1] ?? []).length === 0 ? (
                                <p className={predictionStyles.empty}>Aucun participant sur cette categorie.</p>
                              ) : (
                                <div className={styles.candidateList}>
                                  {(currentScoringEntriesByBaby[1] ?? []).map((entry) => {
                                    const boardEntry = currentBoardCard?.entries.find((item) => item.entryId === entry.id) ?? null;
                                    const participantName = entry.user.displayName ?? entry.user.username;
                                    const currentTotal = totalsByUserId.get(entry.userId) ?? 0;
                                    const draft = currentScoreDraftByBaby[1] ?? {};

                                    return (
                                      <article key={entry.id} className={styles.candidateCard}>
                                        <div className={styles.candidateHeader}>
                                          <strong>{participantName}</strong>
                                          <span className={styles.statusPill}>Total actuel: {currentTotal} pts</span>
                                        </div>
                                        <p className={styles.candidateMeta}>
                                          Pronostic: {boardEntry?.values.length
                                            ? boardEntry.values
                                              .map((value) =>
                                                formatLabeledValue(value.fieldLabel, {
                                                  valueText: value.valueText,
                                                  valueNumber: value.valueNumber,
                                                  valueDate: value.valueDate,
                                                }, currentStepCard.unit),
                                              )
                                              .join(" | ")
                                            : "Aucune reponse"}
                                        </p>
                                        <div className={styles.scoreInputs}>
                                          {entry.scores.map((score) => (
                                            <label key={`${entry.id}-${score.fieldId}`} className={styles.scoreInputRow}>
                                              <span>
                                                {score.field.label} — {score.field.points} pts max
                                              </span>
                                              <input
                                                type="number"
                                                min={0}
                                                value={draft[entry.id]?.[score.fieldId] ?? `${score.awardedPoints ?? score.suggestedPoints}`}
                                                onChange={(event) => {
                                                  onScoreChange(1, currentStepCard.id, entry.id, score.fieldId, event.target.value);
                                                }}
                                              />
                                            </label>
                                          ))}
                                        </div>
                                        <p className={styles.candidateMeta}>Points sur cette categorie: {getStepPointsTotal(1, entry)}</p>
                                      </article>
                                    );
                                  })}
                                </div>
                              )}
                            </>
                          )}

                          <div className={styles.wizardActions}>
                            <button
                              className="btn btn-soft"
                              onClick={() => setWizardStepIndex((current) => Math.max(current - 1, 0))}
                              disabled={loading || wizardStepIndex === 0}
                            >
                              Etape precedente
                            </button>
                            <button
                              className="btn btn-soft"
                              onClick={() => setWizardStepIndex((current) => Math.min(current + 1, predictionCards.length))}
                              disabled={loading}
                            >
                              Passer au recap
                            </button>
                            <button className="btn btn-primary" onClick={onValidateCurrentStep} disabled={loading}>
                              Valider cette categorie{activeProjectBabyCount > 1 ? " (tous les bebes)" : ""}
                            </button>
                          </div>
                        </>
                      ) : (
                        <>
                          <h4>3. Recap final des points</h4>
                          <p className={styles.helpText}>
                            Les points sont cumules entre les bebes. Si un participant est le plus proche pour les {activeProjectBabyCount} bebes, il gagne les points x{activeProjectBabyCount}.
                          </p>
                          <p className={styles.helpText}>Pronostics restants a noter: {remainingEntriesToScore}</p>

                          {winnerSummary ? (
                            <div className={styles.outcomeSummary}>
                              <strong>
                                Gagnant(s) provisoire(s): {winnerSummary.winners
                                  .map((winner) => winner.displayName ?? winner.username)
                                  .join(" / ")}
                              </strong>
                              <p>Score total: {winnerSummary.points} points (cumul sur {activeProjectBabyCount} bebe{activeProjectBabyCount > 1 ? "s" : ""})</p>
                            </div>
                          ) : (
                            <p className={predictionStyles.empty}>Pas encore de classement disponible.</p>
                          )}

                          <table className={predictionStyles.scoreTable}>
                            <thead>
                              <tr>
                                <th>#</th>
                                <th>Participant</th>
                                <th>Total cumule</th>
                              </tr>
                            </thead>
                            <tbody>
                              {scoreboard.map((item, index) => (
                                <tr key={item.userId}>
                                  <td>{index + 1}</td>
                                  <td>{item.displayName ?? item.username}</td>
                                  <td>{item.totalPoints}</td>
                                </tr>
                              ))}
                            </tbody>
                          </table>

                          <div className={styles.wizardActions}>
                            <button
                              className="btn btn-soft"
                              onClick={() => setWizardStepIndex((current) => Math.max(current - 1, 0))}
                              disabled={loading || predictionCards.length === 0}
                            >
                              Revenir aux categories
                            </button>
                            <button className="btn btn-primary" onClick={onFinalizeContest} disabled={loading || !canFinalizeContest}>
                              Valider definitivement le concours
                            </button>
                          </div>
                          {!canFinalizeContest ? (
                            <p className={styles.helpText}>
                              Valide tous les pronostics de chaque categorie{activeProjectBabyCount > 1 ? " pour chaque bebe" : ""} avant la validation finale.
                            </p>
                          ) : null}
                        </>
                      )}
                    </div>
                  ) : null}

                  {isFinalized ? (
                    <div className={styles.wizardPanel}>
                      <h3>Concours valide</h3>
                      {winnerSummary ? (
                        <div className={styles.outcomeSummary}>
                          <strong>
                            Gagnant(s): {winnerSummary.winners
                              .map((winner) => winner.displayName ?? winner.username)
                              .join(" / ")}
                          </strong>
                          <p>{winnerSummary.points} points (cumul {activeProjectBabyCount} bebe{activeProjectBabyCount > 1 ? "s" : ""})</p>
                        </div>
                      ) : null}
                      <table className={predictionStyles.scoreTable}>
                        <thead>
                          <tr>
                            <th>#</th>
                            <th>Participant</th>
                            <th>Total cumule</th>
                          </tr>
                        </thead>
                        <tbody>
                          {scoreboard.map((item, index) => (
                            <tr key={item.userId}>
                              <td>{index + 1}</td>
                              <td>{item.displayName ?? item.username}</td>
                              <td>{item.totalPoints}</td>
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  ) : null}

                  {predictionMessage ? <p className={styles.message}>{predictionMessage}</p> : null}
                </>
              )}
            </section>
          ) : null}
        </>
      )}
    </main>
  );
}
