"use client";

import {
  DragEvent,
  FormEvent,
  PointerEvent as ReactPointerEvent,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import NextImage from "next/image";
import Link from "next/link";
import { useRouter } from "next/navigation";
import {
  authenticatedFetch,
  clearSession,
  getApiUrl,
  loadSession,
  logoutSession,
} from "@/lib/auth";
import styles from "./page.module.css";
import navStyles from "@/features/predictions/styles/predictions.module.css";

/* ------------------------------------------------------------------ */
/*  Types                                                              */
/* ------------------------------------------------------------------ */

type ProfileResponse = {
  id: string;
  username: string;
  displayName: string | null;
  profileImageUrl: string | null;
  profileBgColor: string | null;
  role: "ADMIN" | "FAMILY";
  createdAt: string;
};

type CropState = { x: number; y: number; scale: number };

/* ------------------------------------------------------------------ */
/*  Constants                                                          */
/* ------------------------------------------------------------------ */

const PASTEL_COLORS = [
  "#F9D5E5", // rose
  "#D5EAF7", // bleu
  "#D5F5E3", // vert
  "#FFF3CD", // jaune
  "#E8D5F5", // lilas
  "#FFE0CC", // peche
];

const CIRCLE_SIZE = 200;
const MIN_SCALE = 0.5;
const MAX_SCALE = 3;

/* ------------------------------------------------------------------ */
/*  Page                                                               */
/* ------------------------------------------------------------------ */

export default function ProfilePage() {
  const router = useRouter();
  const apiUrl = getApiUrl();

  /* profile state */
  const [profile, setProfile] = useState<ProfileResponse | null>(null);
  const [displayName, setDisplayName] = useState("");
  const [message, setMessage] = useState("");
  const [loading, setLoading] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!menuOpen) return;
    function handleClickOutside(e: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        setMenuOpen(false);
      }
    }
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [menuOpen]);

  /* modal state */
  const [modalOpen, setModalOpen] = useState(false);
  const [modalTab, setModalTab] = useState<"upload" | "defaults">("upload");
  const [modalMessage, setModalMessage] = useState("");

  /* upload / crop state */
  const [file, setFile] = useState<File | null>(null);
  const [imageSrc, setImageSrc] = useState<string | null>(null);
  const [imgNaturalSize, setImgNaturalSize] = useState<{ w: number; h: number } | null>(null);
  const [baseScale, setBaseScale] = useState(1);
  const [crop, setCrop] = useState<CropState>({ x: 0, y: 0, scale: 1 });
  const [dragging, setDragging] = useState(false);
  const [bgColor, setBgColor] = useState<string>(PASTEL_COLORS[0]);
  const [showCustomPicker, setShowCustomPicker] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  /* default avatars */
  const [defaultAvatars, setDefaultAvatars] = useState<string[]>([]);
  const [selectedDefault, setSelectedDefault] = useState<string | null>(null);

  /* pointer drag tracking */
  const dragStartRef = useRef<{ px: number; py: number; cx: number; cy: number } | null>(null);
  const cropPreviewRef = useRef<HTMLDivElement>(null);

  /* canvas ref for rendering final crop */
  const canvasRef = useRef<HTMLCanvasElement>(null);

  /* ---------------------------------------------------------------- */
  /*  Data loading                                                     */
  /* ---------------------------------------------------------------- */

  const loadProfile = useCallback(async () => {
    const response = await authenticatedFetch(apiUrl, "/users/me");
    const payload = (await response.json()) as ProfileResponse | { message?: string };
    if (!response.ok || !("id" in payload)) {
      throw new Error((payload as { message?: string }).message ?? "Impossible de charger le profil");
    }
    setProfile(payload);
    setDisplayName(payload.displayName ?? "");
    if (payload.profileBgColor) setBgColor(payload.profileBgColor);
  }, [apiUrl]);

  useEffect(() => {
    const session = loadSession();
    if (!session) { router.push("/"); return; }
    loadProfile().catch(() => { clearSession(); router.push("/"); });
  }, [router, loadProfile]);

  useEffect(() => {
    authenticatedFetch(apiUrl, "/users/default-avatars")
      .then((r) => r.json())
      .then((data) => { if (Array.isArray(data)) setDefaultAvatars(data); })
      .catch(() => {});
  }, [apiUrl]);

  /* ---------------------------------------------------------------- */
  /*  Pseudo                                                           */
  /* ---------------------------------------------------------------- */

  const onSaveDisplayName = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (displayName.trim().length > 0 && displayName.trim().length < 2) {
      setMessage("Le pseudo doit contenir au moins 2 caracteres"); return;
    }
    setLoading(true); setMessage("");
    try {
      const response = await authenticatedFetch(apiUrl, "/users/me", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ displayName: displayName.trim().length >= 2 ? displayName.trim() : undefined }),
      });
      const payload = (await response.json()) as ProfileResponse | { message?: string };
      if (!response.ok || !("id" in payload)) { setMessage((payload as { message?: string }).message ?? "Mise a jour impossible"); return; }
      setProfile(payload);
      setMessage("Pseudo mis a jour ✓");
    } catch { setMessage("Erreur reseau"); }
    finally { setLoading(false); }
  };

  /* ---------------------------------------------------------------- */
  /*  File picking                                                     */
  /* ---------------------------------------------------------------- */

  const pickFile = (picked: File) => {
    setFile(picked);
    const src = URL.createObjectURL(picked);
    setImageSrc(src);
    setCrop({ x: 0, y: 0, scale: 1 });
    setImgNaturalSize(null);
    setBaseScale(1);
    setSelectedDefault(null);
    setModalTab("upload");
  };

  const onDragOver = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); setDragging(true); };
  const onDragLeave = () => setDragging(false);
  const onDrop = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault(); setDragging(false);
    const dropped = e.dataTransfer.files[0];
    if (dropped) pickFile(dropped);
  };
  const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const picked = e.target.files?.[0]; if (picked) pickFile(picked);
  };

  /* ---------------------------------------------------------------- */
  /*  Crop drag                                                        */
  /* ---------------------------------------------------------------- */

  const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {
    if (!imageSrc) return;
    e.preventDefault();
    (e.target as HTMLElement).setPointerCapture(e.pointerId);
    dragStartRef.current = { px: e.clientX, py: e.clientY, cx: crop.x, cy: crop.y };
  };

  const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>) => {
    if (!dragStartRef.current) return;
    const { px, py, cx, cy } = dragStartRef.current;
    setCrop((prev) => ({ ...prev, x: cx + (e.clientX - px), y: cy + (e.clientY - py) }));
  };

  const onPointerUp = () => { dragStartRef.current = null; };

  const onWheel = (e: React.WheelEvent<HTMLDivElement>) => {
    e.stopPropagation();
    setCrop((prev) => {
      const delta = e.deltaY > 0 ? -0.05 : 0.05;
      return { ...prev, scale: Math.min(MAX_SCALE, Math.max(MIN_SCALE, prev.scale + delta)) };
    });
  };

  /* ---------------------------------------------------------------- */
  /*  Modal lifecycle                                                  */
  /* ---------------------------------------------------------------- */

  const openModal = () => {
    setModalOpen(true);
    setModalMessage("");
    setFile(null);
    setImageSrc(null);
    setCrop({ x: 0, y: 0, scale: 1 });
    setSelectedDefault(null);
    setShowCustomPicker(false);
    if (profile?.profileBgColor) setBgColor(profile.profileBgColor);
  };
  const closeModal = () => { setModalOpen(false); setFile(null); setImageSrc(null); setImgNaturalSize(null); setBaseScale(1); setModalMessage(""); };

  /* ---------------------------------------------------------------- */
  /*  Delete current photo                                             */
  /* ---------------------------------------------------------------- */

  const onDeletePhoto = async () => {
    setLoading(true); setModalMessage("");
    try {
      const response = await authenticatedFetch(apiUrl, "/users/me/photo", { method: "DELETE" });
      const payload = (await response.json()) as ProfileResponse | { message?: string };
      if (!response.ok || !("id" in payload)) { setModalMessage((payload as { message?: string }).message ?? "Suppression impossible"); return; }
      setProfile(payload);
      setAvatarVersion(Date.now());
      setMessage("Photo supprimee ✓");
    } catch { setModalMessage("Erreur reseau"); }
    finally { setLoading(false); }
  };

  /* ---------------------------------------------------------------- */
  /*  Render cropped image to blob                                     */
  /* ---------------------------------------------------------------- */

  const renderCroppedBlob = (): Promise<Blob | null> => {
    return new Promise((resolve) => {
      if (!imageSrc || !imgNaturalSize) { resolve(null); return; }
      const img = new window.Image();
      img.onload = () => {
        const canvas = canvasRef.current;
        if (!canvas) { resolve(null); return; }
        const size = 400;
        canvas.width = size;
        canvas.height = size;
        const ctx = canvas.getContext("2d");
        if (!ctx) { resolve(null); return; }

        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, size, size);

        ctx.beginPath();
        ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
        ctx.clip();

        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, size, size);

        // Mirror exactly the preview: baseScale brings image to cover the circle,
        // then crop.scale and crop.x/y are applied on top.
        const ratio = size / CIRCLE_SIZE;
        const scaledW = imgNaturalSize.w * baseScale * crop.scale * ratio;
        const scaledH = imgNaturalSize.h * baseScale * crop.scale * ratio;
        const dx = (size - scaledW) / 2 + crop.x * ratio;
        const dy = (size - scaledH) / 2 + crop.y * ratio;

        ctx.drawImage(img, dx, dy, scaledW, scaledH);

        canvas.toBlob((blob) => resolve(blob), "image/png");
      };
      img.src = imageSrc;
    });
  };

  /* ---------------------------------------------------------------- */
  /*  Upload (custom image)                                            */
  /* ---------------------------------------------------------------- */

  const onUploadPhoto = async () => {
    setLoading(true); setModalMessage("");
    try {
      const blob = await renderCroppedBlob();
      if (!blob) { setModalMessage("Erreur de recadrage."); return; }

      const formData = new FormData();
      formData.append("file", blob, "avatar.png");
      formData.append("bgColor", bgColor);

      const response = await authenticatedFetch(apiUrl, "/users/me/photo", { method: "POST", body: formData });
      const payload = (await response.json()) as ProfileResponse | { message?: string };
      if (!response.ok || !("id" in payload)) { setModalMessage((payload as { message?: string }).message ?? "Upload impossible"); return; }
      setProfile(payload);
      setAvatarVersion(Date.now());
      setMessage("Photo de profil mise a jour ✓");
      closeModal();
    } catch { setModalMessage("Erreur reseau"); }
    finally { setLoading(false); }
  };

  /* ---------------------------------------------------------------- */
  /*  Select default avatar                                            */
  /* ---------------------------------------------------------------- */

  const onSelectDefaultAvatar = async () => {
    if (!selectedDefault) return;
    setLoading(true); setModalMessage("");
    try {
      const response = await authenticatedFetch(apiUrl, "/users/me/avatar", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ avatarUrl: selectedDefault, bgColor }),
      });
      const payload = (await response.json()) as ProfileResponse | { message?: string };
      if (!response.ok || !("id" in payload)) { setModalMessage((payload as { message?: string }).message ?? "Erreur"); return; }
      setProfile(payload);
      setAvatarVersion(Date.now());
      setMessage("Avatar mis a jour ✓");
      closeModal();
    } catch { setModalMessage("Erreur reseau"); }
    finally { setLoading(false); }
  };

  /* ---------------------------------------------------------------- */
  /*  Logout                                                           */
  /* ---------------------------------------------------------------- */

  const logout = async () => { await logoutSession(apiUrl); window.location.replace("/"); };

  /* ---------------------------------------------------------------- */
  /*  Derived                                                          */
  /* ---------------------------------------------------------------- */

  const [avatarVersion, setAvatarVersion] = useState(() => Date.now());
  const profileImageSrc = profile?.profileImageUrl ? `${apiUrl}${profile.profileImageUrl}?v=${avatarVersion}` : null;
  const profileBg = profile?.profileBgColor ?? undefined;
  const hasCurrentPhoto = !!profile?.profileImageUrl;
  const homeHref = profile?.role === "ADMIN" ? "/admin" : "/predictions";
  const homeLabel = profile?.role === "ADMIN" ? "Retour admin" : "Mes pronostics";
  const canSave = modalTab === "upload" ? !!imageSrc : !!selectedDefault;

  /* ---------------------------------------------------------------- */
  /*  Render                                                           */
  /* ---------------------------------------------------------------- */

  const isAdmin = profile?.role === "ADMIN";

  return (
    <main className={`app-shell ${styles.page}`}>
      <header className={navStyles.appHeader}>
        <div className={navStyles.appHeaderLeft}>
          <NextImage src="/images/icons/logo.png" alt="Logo" width={50} height={50} className={navStyles.headerLogo} />
          <span className={navStyles.appTitle}>Le juste poids</span>
        </div>
        {isAdmin ? (
          <div className={navStyles.menuWrapper}>
            <Link className="btn btn-soft" href={homeHref}>{homeLabel}</Link>
            <button type="button" className="btn btn-soft" onClick={logout}>Se déconnecter</button>
          </div>
        ) : (
          <div className={navStyles.menuWrapper} ref={menuRef}>
            <button
              className={navStyles.burgerBtn}
              onClick={() => setMenuOpen(!menuOpen)}
              aria-label="Menu"
              type="button"
            >
              <span className={navStyles.burgerLine} />
              <span className={navStyles.burgerLine} />
              <span className={navStyles.burgerLine} />
            </button>
            {menuOpen && (
              <nav className={navStyles.mobileMenu}>
                <Link className={navStyles.tab} href="/predictions" onClick={() => setMenuOpen(false)}>Pronostics</Link>
                <Link className={navStyles.tab} href="/predictions/history" onClick={() => setMenuOpen(false)}>Historique</Link>
                <Link className={navStyles.tab} href="/predictions/recap" onClick={() => setMenuOpen(false)}>Recap &amp; Moyennes</Link>
                <Link className={`${navStyles.tab} ${navStyles.tabActive}`} href="/profile" onClick={() => setMenuOpen(false)}>Mon profil</Link>
                <div className={navStyles.menuDivider} />
                <button type="button" className={`btn btn-soft ${navStyles.logoutBtn}`} onClick={logout}>Se déconnecter</button>
              </nav>
            )}
          </div>
        )}
      </header>

      <section className={`panel ${styles.content}`}>
        {/* Avatar */}
        <div className={styles.avatarSection}>
          <button type="button" className={styles.avatarBtn} onClick={openModal} title="Modifier la photo de profil"
            style={profileBg ? { background: profileBg } : undefined}>
            {profileImageSrc ? (
              <img src={profileImageSrc} alt="Photo de profil" className={styles.avatar} />
            ) : (
              <div className={styles.avatarPlaceholder}>
                <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                  <circle cx="12" cy="8" r="4" /><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
                </svg>
              </div>
            )}
            <div className={styles.avatarOverlay}>
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
                <circle cx="12" cy="13" r="4" />
              </svg>
            </div>
          </button>
          <button type="button" className={styles.avatarHint} onClick={openModal}>Modifier la photo</button>
        </div>

        {/* Identity */}
        <div className={styles.identitySection}>
          <div className={styles.infoRow}>
            <span className={styles.infoLabel}>Identifiant</span>
            <span className={styles.infoValue}>{profile?.username ?? "-"}</span>
          </div>
          <form className={styles.pseudoForm} onSubmit={onSaveDisplayName}>
            <div className={styles.pseudoField}>
              <label htmlFor="displayName" className={styles.infoLabel}>Pseudo</label>
              <input id="displayName" className={styles.pseudoInput} value={displayName}
                onChange={(e) => setDisplayName(e.target.value)} placeholder="Ton pseudo" />
            </div>
            <button className={`btn btn-primary ${styles.saveBtn}`} disabled={loading}>Sauver</button>
          </form>
        </div>
        {message ? <p className={styles.message}>{message}</p> : null}
      </section>

      {/* ============ MODAL ============ */}
      {modalOpen && (
        <div className={styles.modalBackdrop} onClick={closeModal}>
          <div className={styles.modal} onClick={(e) => e.stopPropagation()}>
            {/* header */}
            <div className={styles.modalHeader}>
              <h2>Photo de profil</h2>
              <button type="button" className={styles.modalClose} onClick={closeModal} aria-label="Fermer">✕</button>
            </div>

            {/* tabs */}
            <div className={styles.tabs}>
              <button type="button" className={`${styles.tab} ${modalTab === "upload" ? styles.tabActive : ""}`}
                onClick={() => setModalTab("upload")}>Ma photo</button>
              {defaultAvatars.length > 0 && (
                <button type="button" className={`${styles.tab} ${modalTab === "defaults" ? styles.tabActive : ""}`}
                  onClick={() => setModalTab("defaults")}>Avatars</button>
              )}
            </div>

            {/* ----- tab: upload ----- */}
            {modalTab === "upload" && (
              <>
                {imageSrc ? (
                  /* --- Crop mode: new image selected --- */
                  <>
                    <div className={styles.cropContainer}>
                      <div ref={cropPreviewRef} className={styles.cropCircle}
                        style={{ width: CIRCLE_SIZE, height: CIRCLE_SIZE, background: bgColor }}
                        onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={onPointerUp}
                        onWheel={onWheel}>
                        {imageSrc && (
                          <img
                            src={imageSrc}
                            alt=""
                            className={styles.cropImg}
                            draggable={false}
                            onLoad={(e) => {
                              const el = e.currentTarget;
                              const bs = Math.max(
                                CIRCLE_SIZE / el.naturalWidth,
                                CIRCLE_SIZE / el.naturalHeight
                              );
                              setBaseScale(bs);
                              setImgNaturalSize({ w: el.naturalWidth, h: el.naturalHeight });
                            }}
                            style={imgNaturalSize ? {
                              width: imgNaturalSize.w * baseScale,
                              height: imgNaturalSize.h * baseScale,
                              marginLeft: -(imgNaturalSize.w * baseScale) / 2,
                              marginTop: -(imgNaturalSize.h * baseScale) / 2,
                              transform: `translate(${crop.x}px, ${crop.y}px) scale(${crop.scale})`,
                            } : { display: 'none' }}
                          />
                        )}
                      </div>
                    </div>

                    <div className={styles.zoomRow}>
                      <span className={styles.zoomLabel}>−</span>
                      <input type="range" min={MIN_SCALE * 100} max={MAX_SCALE * 100} value={crop.scale * 100}
                        className={styles.zoomSlider}
                        onChange={(e) => setCrop((prev) => ({ ...prev, scale: Number(e.target.value) / 100 }))} />
                      <span className={styles.zoomLabel}>+</span>
                    </div>

                    <button type="button" className={styles.changeFile}
                      onClick={() => fileInputRef.current?.click()}>Changer l&apos;image</button>
                  </>
                ) : hasCurrentPhoto ? (
                  /* --- Current photo exists: show it with delete option --- */
                  <div className={styles.currentPhotoSection}>
                    <div className={styles.currentPhotoCircle} style={{ background: profileBg }}>
                      <img src={profileImageSrc!} alt="Photo actuelle" />
                    </div>
                    <p className={styles.currentPhotoHint}>Photo actuelle</p>
                    <div className={styles.currentPhotoActions}>
                      <button type="button" className={styles.changeFile}
                        onClick={() => fileInputRef.current?.click()}>Changer la photo</button>
                      <button type="button" className={styles.deletePhotoBtn}
                        onClick={onDeletePhoto} disabled={loading}>
                        {loading ? "Suppression…" : "Supprimer la photo"}
                      </button>
                    </div>
                  </div>
                ) : (
                  /* --- No photo: drag & drop zone --- */
                  <div className={`${styles.dropZone} ${dragging ? styles.dropZoneActive : ""}`}
                    onDragOver={onDragOver} onDragLeave={onDragLeave} onDrop={onDrop}
                    onClick={() => fileInputRef.current?.click()}>
                    <svg className={styles.dropIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                      <polyline points="17 8 12 3 7 8" /><line x1="12" y1="3" x2="12" y2="15" />
                    </svg>
                    <p className={styles.dropText}>Glisse une image ici</p>
                    <p className={styles.dropSub}>ou clique pour parcourir · PNG, JPG, WEBP</p>
                  </div>
                )}

                <input ref={fileInputRef} type="file" accept="image/png,image/jpeg,image/jpg,image/webp"
                  className={styles.hiddenInput} onChange={onFileInputChange} />
              </>
            )}

            {/* ----- tab: defaults ----- */}
            {modalTab === "defaults" && (
              <div className={styles.defaultGrid}>
                {defaultAvatars.map((url) => (
                  <button key={url} type="button"
                    className={`${styles.defaultItem} ${selectedDefault === url ? styles.defaultItemActive : ""}`}
                    style={{ background: bgColor }}
                    onClick={() => { setSelectedDefault(url); setFile(null); setImageSrc(null); }}>
                    <img src={`${apiUrl}${url}`} alt="" />
                  </button>
                ))}
              </div>
            )}

            {/* ----- bg color picker — masqué si photo existante sans nouvelle sélection ----- */}
            {(imageSrc || selectedDefault || !profile?.profileImageUrl) && (
            <div className={styles.colorSection}>
              <span className={styles.colorLabel}>Couleur de fond</span>
              <div className={styles.colorRow}>
                {PASTEL_COLORS.map((c) => (
                  <button key={c} type="button"
                    className={`${styles.colorDot} ${bgColor === c ? styles.colorDotActive : ""}`}
                    style={{ background: c }} onClick={() => setBgColor(c)} />
                ))}
                <button type="button"
                  className={`${styles.colorDot} ${styles.colorCustom} ${!PASTEL_COLORS.includes(bgColor) ? styles.colorDotActive : ""}`}
                  style={!PASTEL_COLORS.includes(bgColor) ? { background: bgColor } : undefined}
                  onClick={() => setShowCustomPicker((v) => !v)}>
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                    <circle cx="12" cy="12" r="10" /><path d="M2 12h20" />
                  </svg>
                </button>
              </div>
              {showCustomPicker && (
                <input type="color" className={styles.nativeColorPicker} value={bgColor}
                  onChange={(e) => setBgColor(e.target.value)} />
              )}
            </div>
            )}

            {/* error */}
            {modalMessage && <p className={styles.modalError}>{modalMessage}</p>}

            {/* actions */}
            <div className={styles.modalActions}>
              <button type="button" className="btn btn-soft" onClick={closeModal}>Annuler</button>
              <button type="button" className="btn btn-primary" disabled={!canSave || loading}
                onClick={modalTab === "upload" ? onUploadPhoto : onSelectDefaultAvatar}>
                {loading ? "Envoi…" : "Enregistrer"}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* hidden canvas for crop rendering */}
      <canvas ref={canvasRef} style={{ display: "none" }} />
    </main>
  );
}
