"use client";

import { useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { Skeleton } from "@/components/ui/skeleton";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { PlayerAvatar } from "@/components/PlayerAvatar";
import { formatHours, timeAgo } from "@/lib/time";
import type { PlayerStats } from "@/lib/player-stats";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";

type MetricKey =
  | "playtimeHours"
  | "distanceKm"
  | "mobKills"
  | "playerKills"
  | "deaths"
  | "kdr"
  | "damageDealt"
  | "damageTaken"
  | "blocksMined"
  | "itemsUsed"
  | "itemsCrafted"
  | "itemsPickedUp"
  | "uniqueItemsPickedUp"
  | "advancements"
  | "recipesUnlocked"
  | "chestOpens"
  | "netherPortalEnters"
  | "endPortalEnters"
  | "villagerTrades"
  | "fishCaught"
  | "animalsBred"
  | "longestLifeHours";

type Metric = {
  key: MetricKey;
  label: string;
  group: string;
  format: (v: number) => string;
  suffix?: string;
};

const METRICS: Metric[] = [
  { key: "playtimeHours", label: "Playtime", group: "Time", format: (v) => formatHours(v) },
  { key: "longestLifeHours", label: "Longest life", group: "Time", format: (v) => formatHours(v) },

  { key: "mobKills", label: "Mob kills", group: "Combat", format: fmtInt },
  { key: "playerKills", label: "Player kills", group: "Combat", format: fmtInt },
  { key: "deaths", label: "Deaths", group: "Combat", format: fmtInt },
  { key: "kdr", label: "K/D ratio", group: "Combat", format: (v) => v.toFixed(2) },
  { key: "damageDealt", label: "Damage dealt", group: "Combat", format: fmtInt, suffix: " HP" },
  { key: "damageTaken", label: "Damage taken", group: "Combat", format: fmtInt, suffix: " HP" },

  { key: "blocksMined", label: "Blocks mined", group: "World", format: fmtInt },
  { key: "itemsUsed", label: "Items used / placed", group: "World", format: fmtInt },
  { key: "itemsCrafted", label: "Items crafted", group: "World", format: fmtInt },
  { key: "itemsPickedUp", label: "Items picked up", group: "World", format: fmtInt },
  { key: "uniqueItemsPickedUp", label: "Unique items seen", group: "World", format: fmtInt },

  { key: "distanceKm", label: "Distance traveled", group: "Exploration", format: (v) => v.toFixed(1), suffix: " km" },
  { key: "chestOpens", label: "Chests opened", group: "Exploration", format: fmtInt },
  { key: "netherPortalEnters", label: "Nether trips", group: "Exploration", format: fmtInt },
  { key: "endPortalEnters", label: "End trips", group: "Exploration", format: fmtInt },

  { key: "advancements", label: "Advancements", group: "Progression", format: fmtInt },
  { key: "recipesUnlocked", label: "Recipes unlocked", group: "Progression", format: fmtInt },

  { key: "villagerTrades", label: "Villager trades", group: "Economy", format: fmtInt },
  { key: "fishCaught", label: "Fish caught", group: "Economy", format: fmtInt },
  { key: "animalsBred", label: "Animals bred", group: "Economy", format: fmtInt },
];

function fmtInt(v: number): string {
  if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`;
  if (v >= 10_000) return `${(v / 1_000).toFixed(1)}k`;
  return v.toLocaleString();
}

const TOP_N = 10;

export function Leaderboard() {
  const [metricKey, setMetricKey] = useState<MetricKey>("playtimeHours");
  const [showAll, setShowAll] = useState(false);

  const { data = [], isLoading, isError } = useQuery<PlayerStats[]>({
    queryKey: ["players-stats"],
    queryFn: () => fetch("/api/players/stats").then((r) => r.json()),
    staleTime: 60_000,
    refetchInterval: 5 * 60_000,
  });

  const metric = METRICS.find((m) => m.key === metricKey)!;

  const sorted = useMemo(() => {
    return [...data].sort(
      (a, b) => (b[metricKey] as number) - (a[metricKey] as number)
    );
  }, [data, metricKey]);

  const visible = showAll ? sorted : sorted.slice(0, TOP_N);

  const groups = useMemo(() => {
    const g = new Map<string, Metric[]>();
    for (const m of METRICS) {
      if (!g.has(m.group)) g.set(m.group, []);
      g.get(m.group)!.push(m);
    }
    return g;
  }, []);

  return (
    <Card>
      <CardHeader>
        <div className="flex items-start justify-between gap-2 flex-wrap">
          <div>
            <CardTitle className="text-base">Leaderboard</CardTitle>
            <CardDescription>
              Ranked by{" "}
              <span className="text-foreground font-medium">{metric.label}</span>
            </CardDescription>
          </div>
          <select
            value={metricKey}
            onChange={(e) => {
              setMetricKey(e.target.value as MetricKey);
              setShowAll(false);
            }}
            aria-label="Ranking metric"
            className="h-9 rounded-md border border-input bg-muted px-2 text-sm max-w-full"
          >
            {Array.from(groups.entries()).map(([group, metrics]) => (
              <optgroup key={group} label={group}>
                {metrics.map((m) => (
                  <option key={m.key} value={m.key}>
                    {m.label}
                  </option>
                ))}
              </optgroup>
            ))}
          </select>
        </div>
      </CardHeader>
      <CardContent>
        {isLoading ? (
          <ul className="space-y-1">
            {Array.from({ length: 5 }).map((_, i) => (
              <li key={i} className="flex items-center gap-3 px-3 py-2">
                <Skeleton className="h-6 w-6 rounded" />
                <Skeleton className="h-4 w-32" />
                <Skeleton className="h-3 w-14 ml-auto" />
              </li>
            ))}
          </ul>
        ) : isError ? (
          <p className="text-sm text-red-300 text-center py-4">
            Failed to load stats.
          </p>
        ) : sorted.length === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-4">
            No player stats yet.
          </p>
        ) : (
          <>
            <ol className="space-y-1">
              {visible.map((p, i) => {
                const raw = p[metricKey] as number;
                const display = `${metric.format(raw)}${metric.suffix || ""}`;
                return (
                  <li
                    key={p.uuid}
                    className="flex items-center gap-3 px-3 py-2 rounded-md bg-muted/50"
                  >
                    <span className="text-xs font-bold text-muted-foreground tabular-nums w-5 text-center shrink-0">
                      {i + 1}
                    </span>
                    <PlayerAvatar name={p.name} size={24} />
                    <div className="min-w-0 flex-1">
                      <p className="text-sm font-medium truncate">{p.name}</p>
                      <p
                        className="text-xs text-muted-foreground"
                        title={new Date(p.lastPlayedMs).toLocaleString()}
                      >
                        last seen {timeAgo(p.lastPlayedMs)}
                      </p>
                    </div>
                    <Badge
                      variant="secondary"
                      className="text-xs px-1.5 py-0 tabular-nums shrink-0"
                    >
                      {display}
                    </Badge>
                  </li>
                );
              })}
            </ol>
            {sorted.length > TOP_N && (
              <div className="text-center mt-3">
                <Button
                  size="sm"
                  variant="ghost"
                  onClick={() => setShowAll((v) => !v)}
                  className="text-xs"
                >
                  {showAll ? "Show top 10" : `Show all ${sorted.length}`}
                </Button>
              </div>
            )}
          </>
        )}
      </CardContent>
    </Card>
  );
}
