import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { supabase } from "@/integrations/supabase/client"; import { VOTI_MINIMI_PAGELLA } from "./badges"; /** Voto anonimo da 1 a 10 dato a un compagno per una partita. */ export type VotoPagella = { match_id: string; votante_id: string; votato_id: string; voto: number; }; export const PAGELLE_KEY = ["pagelle"] as const; /** Poche righe per stagione: una lettura per sessione basta. */ export function usePagelle() { const query = useQuery({ queryKey: PAGELLE_KEY, staleTime: 10 * 60_000, queryFn: async (): Promise => { const { data, error } = await supabase .from("pagelle_voti") .select("match_id, votante_id, votato_id, voto"); if (error) throw error; return (data ?? []) as VotoPagella[]; }, }); return { ...query, voti: query.data ?? [] }; } export function useVotaPagella() { const qc = useQueryClient(); return useMutation({ mutationFn: async (voto: VotoPagella) => { const { error } = await supabase .from("pagelle_voti") .upsert(voto, { onConflict: "match_id,votante_id,votato_id" }); if (error) throw error; return voto; }, // Cache aggiornata localmente: nessuna rilettura. onSuccess: (voto) => { qc.setQueryData(PAGELLE_KEY, (prec) => { const altri = (prec ?? []).filter( (v) => !( v.match_id === voto.match_id && v.votante_id === voto.votante_id && v.votato_id === voto.votato_id ), ); return [...altri, voto]; }); }, }); } export type MediaPagella = { media: number; voti: number }; function arrotonda(n: number) { return Math.round(n * 10) / 10; } /** * Media storica di ciascun giocatore su tutti i voti mai ricevuti (l'app non ha un concetto * di stagione/reset): giocatoreId -> media e numero di voti. Chi non ha ancora ricevuto voti * non compare nella mappa (nessuna divisione per zero): sta al chiamante gestire il fallback. */ export function mediePagelle(voti: VotoPagella[]): Record { const somma: Record = {}; for (const v of voti) { const cur = somma[v.votato_id] ?? { tot: 0, n: 0 }; cur.tot += v.voto; cur.n += 1; somma[v.votato_id] = cur; } const out: Record = {}; for (const [id, s] of Object.entries(somma)) { out[id] = { media: arrotonda(s.tot / s.n), voti: s.n }; } return out; } /** Media della singola partita, giocatore per giocatore (voti anonimi). */ export function pagellePartita(voti: VotoPagella[], matchId: string): Record { return mediePagelle(voti.filter((v) => v.match_id === matchId)); } /** I voti che ho già dato in questa partita: votatoId -> voto. */ export function mieiVoti(voti: VotoPagella[], matchId: string, votanteId: string) { const out: Record = {}; for (const v of voti) { if (v.match_id === matchId && v.votante_id === votanteId) out[v.votato_id] = v.voto; } return out; } /** * Media voto da mostrare nella StatTile home (sezione «Colpo d'occhio», DD-028): sotto * `VOTI_MINIMI_PAGELLA` voti ricevuti, `—` invece della media grezza — stessa soglia del * badge Pagellone, non applicata invece dalle StatTile di profilo e squadra. */ export function mediaVotoColpoDOcchio(g: { mediaVoto: number; votiPagella: number }): number | "—" { return g.votiPagella >= VOTI_MINIMI_PAGELLA ? g.mediaVoto : "—"; } /** Media pagelle di tutta la squadra su tutte le partite. */ export function mediaSquadra(voti: VotoPagella[]) { if (voti.length === 0) return 0; return arrotonda(voti.reduce((s, v) => s + v.voto, 0) / voti.length); }