"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { createClient, waitForRealtimeAuth } from "@/lib/supabase/client";
import { Avatar } from "@/components/avatar";
import { Podium } from "@/components/podium";
import { JudgePointControls } from "@/components/judge-point-controls";
import { EmptyState } from "@/components/empty-state";
import { computeRanks, computeProgress } from "@/lib/ranking";

type Profile = {
  id: string;
  pseudo: string;
  avatar_url: string | null;
  points: number;
  previous_rank: number | null;
};

function ProgressBadge({ direction, amount }: { direction: string; amount: number }) {
  if (direction === "up") {
    return <span className="text-xs font-semibold text-olive">▲{amount}</span>;
  }
  if (direction === "down") {
    return <span className="text-xs font-semibold text-oxblood">▼{amount}</span>;
  }
  if (direction === "same") {
    return <span className="text-xs text-text-mut">=</span>;
  }
  return null;
}

export function LeaderboardView({
  initialProfiles,
  isJudge,
}: {
  initialProfiles: Profile[];
  isJudge: boolean;
}) {
  const [profiles, setProfiles] = useState<Profile[]>(initialProfiles);
  const [flashingId, setFlashingId] = useState<string | null>(null);
  const pointsRef = useRef(new Map(initialProfiles.map((p) => [p.id, p.points])));

  function applyOptimisticDelta(id: string, delta: number) {
    setProfiles((current) =>
      current.map((p) => (p.id === id ? { ...p, points: p.points + delta } : p)),
    );
  }

  useEffect(() => {
    const supabase = createClient();
    let channel: ReturnType<typeof supabase.channel> | null = null;
    let cancelled = false;

    waitForRealtimeAuth(supabase).then(() => {
      if (cancelled) return;
      channel = supabase
        .channel("leaderboard-profiles")
        .on(
          "postgres_changes",
          { event: "*", schema: "public", table: "profiles" },
          (payload) => {
            if (payload.eventType === "DELETE") return;
            const row = payload.new as Profile;

            setProfiles((current) => {
              const exists = current.some((p) => p.id === row.id);
              return exists
                ? current.map((p) => (p.id === row.id ? { ...p, ...row } : p))
                : [...current, row];
            });

            const previousPoints = pointsRef.current.get(row.id);
            if (previousPoints !== undefined && previousPoints !== row.points) {
              setFlashingId(row.id);
              setTimeout(() => setFlashingId((current) => (current === row.id ? null : current)), 900);
            }
            pointsRef.current.set(row.id, row.points);
          },
        )
        .subscribe();
    });

    return () => {
      cancelled = true;
      if (channel) supabase.removeChannel(channel);
    };
  }, []);

  const ranked = useMemo(() => computeRanks(profiles), [profiles]);
  // Tant que personne n'a de gloires, tout le monde est à égalité à 0 et
  // partagerait le rang 1 — pas de podium tant qu'il n'y a rien à
  // départager, sinon tout le groupe se retrouverait sur la 1ère marche.
  const hasScores = (ranked[0]?.points ?? 0) > 0;
  const podiumProfiles = hasScores ? ranked.filter((p) => p.rank <= 3) : [];
  const rest = hasScores ? ranked.filter((p) => p.rank > 3) : ranked;

  if (profiles.length === 0) {
    return <EmptyState message="Personne n'est encore inscrit." />;
  }

  return (
    <div>
      <Podium
        profiles={podiumProfiles}
        renderValue={(member) => member.points}
        valueLabel="gloires"
        isJudge={isJudge}
        onApplyDelta={applyOptimisticDelta}
      />

      {/* Frise à méandre : marque la transition podium -> reste du
          classement, seulement quand il y a bien un podium au-dessus. */}
      {podiumProfiles.length > 0 && <div className="meander-divider mb-4" />}

      <ol className="flex flex-col gap-2">
        {rest.map((profile) => {
          const progress = computeProgress(profile.rank, profile.previous_rank);
          return (
            <li
              key={profile.id}
              className={`marble-surface flex flex-col gap-2 rounded-lg border border-gold/25 px-4 py-3 shadow-sm transition-colors sm:flex-row sm:items-center sm:gap-3 ${
                flashingId === profile.id ? "animate-points-flash" : ""
              }`}
            >
              <div className="flex items-center gap-3">
                <span className="w-6 shrink-0 text-center font-heading text-text-mut">
                  {profile.rank}
                </span>
                <Avatar pseudo={profile.pseudo} avatarUrl={profile.avatar_url} size="sm" />
                <span className="flex-1 truncate font-medium sm:flex-initial">{profile.pseudo}</span>
                <ProgressBadge direction={progress.direction} amount={progress.amount} />
                <span className="font-semibold text-text-marble sm:hidden">{profile.points}</span>
              </div>
              <div className="flex items-center gap-3 sm:ml-auto">
                <span className="hidden font-semibold text-text-marble sm:inline">
                  {profile.points}
                </span>
                {isJudge && (
                  <JudgePointControls memberId={profile.id} onApplyDelta={applyOptimisticDelta} />
                )}
              </div>
            </li>
          );
        })}
      </ol>
    </div>
  );
}
