import type { Metadata } from "next";
import type { ReactElement } from "react";
import AutoRefresh from "@/components/AutoRefresh";
import { prisma } from "@/lib/prisma";
import styles from "./Leaderboard.module.css";

export const dynamic = "force-dynamic";
export const revalidate = 0;

type Params = {
  klasse: string;
};

type RankingMethod = "time_password" | "time_per_char";

type LeaderboardEntry = {
  username: string;
  durationMs: number;
  createdAt: Date;
  passwordLength: number | null;
  scoreMs: number;
};

type PodiumSlot = {
  label: string;
  username: string;
  scoreText: string;
  metaText: string;
  dateText: string;
  initial: string;
  muted: boolean;
  disqualified: boolean;
};

type ListSlot = {
  rank: number;
  username: string;
  scoreText: string;
  metaText: string;
  dateText: string;
  muted: boolean;
  disqualified: boolean;
};

function parseClass(raw: string): string {
  return decodeURIComponent(raw);
}

function getRankingMethod(): RankingMethod {
  return "time_per_char";
}

function getDopingThreshold(): number {
  const raw = process.env.DOPING_THRESHOLD_MS_PER_CHAR;
  const parsed = raw === undefined ? Number.NaN : Number.parseFloat(raw);
  if (!Number.isFinite(parsed) || parsed <= 0) {
    return 200;
  }
  return parsed;
}

function formatDuration(value: number): string {
  const seconds = value / 1000;
  const digits = seconds >= 10 ? 0 : 1;
  return `${seconds.toFixed(digits)}s`;
}

function formatMsPerChar(value: number): string {
  const rounded = value >= 100 ? Math.round(value) : Number(value.toFixed(1));
  return `${rounded}ms / Zeichen`;
}

function formatDate(value: Date): string {
  return new Intl.DateTimeFormat("de-DE", {
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  }).format(value);
}

function initial(username: string): string {
  const letter = username.trim().charAt(0);
  return letter ? letter.toUpperCase() : "?";
}

async function loadLeaderboard(className: string, method: RankingMethod): Promise<LeaderboardEntry[]> {
  const attempts = await prisma.loginAttempt.findMany({
    where: {
      success: true,
      className,
      loginDurationMs: { not: null },
    },
    select: {
      username: true,
      loginDurationMs: true,
      createdAt: true,
      passwordLength: true,
    },
    orderBy: { createdAt: "desc" },
  });

  const bestByUser = new Map<string, LeaderboardEntry>();
  for (const attempt of attempts) {
    if (attempt.loginDurationMs === null) continue;
    const passwordLength = attempt.passwordLength ?? null;
    if (method === "time_per_char") {
      if (passwordLength === null || passwordLength <= 0) continue;
    }

    const scoreMs = method === "time_per_char"
      ? attempt.loginDurationMs / (passwordLength ?? 1)
      : attempt.loginDurationMs;

    const existing = bestByUser.get(attempt.username);
    if (
      !existing ||
      scoreMs < existing.scoreMs ||
      (scoreMs === existing.scoreMs && attempt.createdAt.getTime() < existing.createdAt.getTime())
    ) {
      bestByUser.set(attempt.username, {
        username: attempt.username,
        durationMs: attempt.loginDurationMs,
        createdAt: attempt.createdAt,
        passwordLength,
        scoreMs,
      });
    }
  }

  return Array.from(bestByUser.values())
    .sort((a, b) => {
      if (a.scoreMs !== b.scoreMs) return a.scoreMs - b.scoreMs;
      if (a.durationMs !== b.durationMs) return a.durationMs - b.durationMs;
      return a.createdAt.getTime() - b.createdAt.getTime();
    });
}

function podiumEntry(entry: LeaderboardEntry | undefined, label: string, method: RankingMethod): PodiumSlot {
  if (!entry) {
    return {
      label,
      username: "Noch frei",
      scoreText: "–",
      metaText: "Wartet auf Eintrag",
      dateText: "",
      initial: "★",
      muted: true,
      disqualified: false,
    };
  }

  const scoreText =
    method === "time_per_char"
      ? `${formatDuration(entry.scoreMs)} / Zeichen`
      : formatDuration(entry.scoreMs);

  const metaParts: string[] = [];
  if (method === "time_per_char") {
    metaParts.push(`Gesamt ${formatDuration(entry.durationMs)}`);
  }
  const passwordLength = entry.passwordLength ?? 0;
  if (passwordLength > 0) {
    metaParts.push(`${passwordLength} Zeichen`);
  }

  const disqualified = passwordLength > 0 && passwordLength < 11;

  return {
    label,
    username: entry.username,
    scoreText,
    metaText: metaParts.join(" · "),
    dateText: formatDate(entry.createdAt),
    initial: initial(entry.username),
    muted: false,
    disqualified,
  };
}

function listEntry(entry: LeaderboardEntry | undefined, rank: number, method: RankingMethod): ListSlot {
  if (!entry) {
    return {
      rank,
      username: "Noch frei",
      scoreText: "–",
      metaText: "",
      dateText: "Wartet auf Eintrag",
      muted: true,
      disqualified: false,
    };
  }

  const scoreText =
    method === "time_per_char"
      ? `${formatDuration(entry.scoreMs)} / Zeichen`
      : formatDuration(entry.scoreMs);

  const metaParts: string[] = [];
  if (method === "time_per_char") {
    metaParts.push(`Gesamt ${formatDuration(entry.durationMs)}`);
  }
  const passwordLength = entry.passwordLength ?? 0;
  if (passwordLength > 0) {
    metaParts.push(`${passwordLength} Zeichen`);
  }

  const disqualified = passwordLength > 0 && passwordLength < 11;

  return {
    rank,
    username: entry.username,
    scoreText,
    metaText: metaParts.join(" · "),
    dateText: formatDate(entry.createdAt),
    muted: false,
    disqualified,
  };
}

export async function generateMetadata({ params }: { params: Promise<Params> }): Promise<Metadata> {
  const { klasse } = await params;
  const className = parseClass(klasse);
  return {
    title: `Leaderboard ${className}`,
    description: `Arcade-Highscore für die Klasse ${className}.`,
  };
}

export default async function LeaderboardPage({ params }: { params: Promise<Params> }): Promise<ReactElement> {
  const { klasse } = await params;
  const className = parseClass(klasse);
  const rankingMethod = getRankingMethod();
  const leaderboardEntries = await loadLeaderboard(className, rankingMethod);
  const leaderboard = leaderboardEntries.slice(0, 12);

  const champion = leaderboard[0];
  const second = leaderboard[1];
  const third = leaderboard[2];

  const podium = {
    first: podiumEntry(champion, "1. Platz", rankingMethod),
    second: podiumEntry(second, "2. Platz", rankingMethod),
    third: podiumEntry(third, "3. Platz", rankingMethod),
  };

  const totalListSlots = 9;
  const listSlots = Array.from({ length: totalListSlots }, (_, index) => {
    const rank = index + 4;
    return listEntry(leaderboard[rank - 1], rank, rankingMethod);
  });

  const columnSize = Math.ceil(listSlots.length / 3);
  const listColumns = Array.from({ length: 3 }, (_, columnIndex) =>
    listSlots.slice(columnIndex * columnSize, (columnIndex + 1) * columnSize)
  ).filter((column) => column.length > 0);

  const dopingThreshold = getDopingThreshold();
  const dopingCandidates: Array<{ entry: LeaderboardEntry; perCharMs: number }> = leaderboardEntries
    .filter((entry) => {
      const length = entry.passwordLength ?? 0;
      if (length <= 0) return false;
      const perChar = entry.durationMs / length;
      return perChar < dopingThreshold;
    })
    .map((entry) => ({
      entry,
      perCharMs: entry.durationMs / Math.max(entry.passwordLength ?? 1, 1),
    }))
    .sort((a, b) => a.perCharMs - b.perCharMs);

  return (
    <>
      <AutoRefresh intervalMs={15000} />
      <div className={styles.page}>
        <div className={styles.stage}>
          <div className={styles.board}>
            <header className={styles.header}>
              <div className={styles.badge}>Leaderboard</div>
              <h1 className={styles.title}>Klasse {className}</h1>
              <p className={styles.subtitle}>
                Wer schnappt sich den Pokal?
              <br /><br /><br /></p>         
            </header>

            {leaderboard.length === 0 ? (
              <div className={styles.emptyState}>
                <p className={styles.emptyHeadline}>Noch keine Bestzeiten</p>
                <p className={styles.emptyText}>
                  Sobald die ersten Logins gemessen werden, erscheint hier eure Hall of Fame.
                </p>
              </div>
            ) : (
              <>
                <section className={styles.podium}>
                  <article className={`${styles.podiumCard} ${styles.second}`}>
                    {podium.second.disqualified && (
                      <div className={styles.podiumBadge}>Disqualified</div>
                    )}
                    <div className={styles.avatar}>{podium.second.initial}</div>
                    <h2 className={styles.podiumLabel}>{podium.second.label}</h2>
                    <p className={`${styles.podiumName} ${podium.second.muted ? styles.muted : ""}`}>
                      {podium.second.username}
                    </p>
                    <p className={`${styles.podiumScore} ${podium.second.muted ? styles.muted : ""}`}>
                      {podium.second.scoreText}
                    </p>
                    {podium.second.metaText && (
                      <div className={`${styles.metaWrapper} ${podium.second.muted ? styles.muted : ""}`}>
                        <span className={styles.podiumMeta}>{podium.second.metaText}</span>
                        {podium.second.disqualified && (
                          <span className={styles.diagonalStamp}>Disqualified</span>
                        )}
                      </div>
                    )}
                    {podium.second.dateText && (
                      <p className={`${styles.podiumDate} ${podium.second.muted ? styles.muted : ""}`}>
                        {podium.second.dateText}
                      </p>
                    )}
                  </article>
                  <article className={`${styles.podiumCard} ${styles.first}`}>
                    {podium.first.disqualified && (
                      <div className={styles.podiumBadge}>Disqualified</div>
                    )}
                    <div className={styles.crown}>🏆</div>
                    <div className={styles.avatar}>{podium.first.initial}</div>
                    <h2 className={styles.podiumLabel}>{podium.first.label}</h2>
                    <p className={`${styles.podiumName} ${podium.first.muted ? styles.muted : ""}`}>
                      {podium.first.username}
                    </p>
                    <p className={`${styles.podiumScore} ${podium.first.muted ? styles.muted : ""}`}>
                      {podium.first.scoreText}
                    </p>
                    {podium.first.metaText && (
                      <div className={`${styles.metaWrapper} ${podium.first.muted ? styles.muted : ""}`}>
                        <span className={styles.podiumMeta}>{podium.first.metaText}</span>
                        {podium.first.disqualified && (
                          <span className={styles.diagonalStamp}>Disqualified</span>
                        )}
                      </div>
                    )}
                    {podium.first.dateText && (
                      <p className={`${styles.podiumDate} ${podium.first.muted ? styles.muted : ""}`}>
                        {podium.first.dateText}
                      </p>
                    )}
                  </article>
                  <article className={`${styles.podiumCard} ${styles.third}`}>
                    {podium.third.disqualified && (
                      <div className={styles.podiumBadge}>Disqualified</div>
                    )}
                    <div className={styles.avatar}>{podium.third.initial}</div>
                    <h2 className={styles.podiumLabel}>{podium.third.label}</h2>
                    <p className={`${styles.podiumName} ${podium.third.muted ? styles.muted : ""}`}>
                      {podium.third.username}
                    </p>
                    <p className={`${styles.podiumScore} ${podium.third.muted ? styles.muted : ""}`}>
                      {podium.third.scoreText}
                    </p>
                    {podium.third.metaText && (
                      <div className={`${styles.metaWrapper} ${podium.third.muted ? styles.muted : ""}`}>
                        <span className={styles.podiumMeta}>{podium.third.metaText}</span>
                        {podium.third.disqualified && (
                          <span className={styles.diagonalStamp}>Disqualified</span>
                        )}
                      </div>
                    )}
                    {podium.third.dateText && (
                      <p className={`${styles.podiumDate} ${podium.third.muted ? styles.muted : ""}`}>
                        {podium.third.dateText}
                      </p>
                    )}
                  </article>
                </section>

                <section className={styles.listSection}>
                  {listColumns.map((column, columnIndex) => (
                    <div key={columnIndex} className={styles.listColumn}>
                      {column.map((slot) => (
                        <div
                          key={slot.rank}
                          className={`${styles.listItem} ${slot.disqualified ? styles.listDisqualified : ""}`}
                        >
                          <span className={styles.rankBadge}>{slot.rank}</span>
                          <div className={styles.listInfo}>
                            <span className={`${styles.listName} ${slot.muted ? styles.muted : ""}`}>
                              {slot.username}
                            </span>
                            {slot.metaText && (
                              <div className={styles.listMetaWrapper}>
                                <span className={`${styles.listMeta} ${slot.muted ? styles.muted : ""}`}>
                                  {slot.metaText}
                                </span>
                                {slot.disqualified && (
                                  <span className={styles.diagonalStampSmall}>Disqualified</span>
                                )}
                              </div>
                            )}
                            <span className={`${styles.listDate} ${slot.muted ? styles.muted : ""}`}>
                              {slot.dateText}
                            </span>
                          </div>
                          <span className={`${styles.listScore} ${slot.muted ? styles.muted : ""}`}>
                            {slot.scoreText}
                          </span>
                        </div>
                      ))}
                    </div>
                  ))}
                </section>
            </>
          )}
          </div>
          <aside className={styles.dopingCard} aria-label="Doping-Kontrolle">
            <div className={styles.dopingHeader}>
              <h2 className={styles.dopingTitle}>Doping-Kontrolle</h2>
              <p className={styles.dopingSubtitle}>
                Meldungen unter {formatMsPerChar(dopingThreshold)} werden geprüft.
              </p>
            </div>
            {dopingCandidates.length === 0 ? (
              <p className={styles.dopingClean}>
                Alles sauber! Keine verdächtigen Tippgeschwindigkeiten.
              </p>
            ) : (
              <ul className={styles.dopingList}>
                {dopingCandidates.map(({ entry, perCharMs }) => (
                  <li key={entry.username} className={styles.dopingItem}>
                    <div className={styles.dopingUser}>
                      <span className={styles.dopingInitial}>{initial(entry.username)}</span>
                      <div className={styles.dopingInfo}>
                        <span className={styles.dopingName}>{entry.username}</span>
                        <span className={styles.dopingDate}>{formatDate(entry.createdAt)}</span>
                      </div>
                    </div>
                    <span className={styles.dopingStat}>{formatMsPerChar(perCharMs)}</span>
                  </li>
                ))}
              </ul>
            )}
          </aside>
        </div>
      </div>
</>
  );
}
