"use client";

import achievementsJson from "../../../data/achievements.json";
import type { AchievementDef, AchievementUnlock, PlayHistoryEntry } from "./types";
import { getFavorites, getHistoryForProfile, getUnlocks, unlockAchievement } from "./db";
import { getAllGames } from "@/lib/games";

const DEFS = achievementsJson as AchievementDef[];

export function getAchievementDefs(): AchievementDef[] {
  return DEFS;
}

export function getAchievementDef(id: string): AchievementDef | undefined {
  return DEFS.find((d) => d.id === id);
}

function totalSeconds(history: PlayHistoryEntry[], gameSlug?: string): number {
  return history
    .filter((h) => (gameSlug ? h.gameSlug === gameSlug : true))
    .reduce((sum, h) => sum + h.totalSeconds, 0);
}

function totalSessions(history: PlayHistoryEntry[], gameSlug?: string): number {
  return history
    .filter((h) => (gameSlug ? h.gameSlug === gameSlug : true))
    .reduce((sum, h) => sum + h.sessions, 0);
}

function systemsPlayed(history: PlayHistoryEntry[]): number {
  const games = getAllGames();
  const bySlug = new Map(games.map((g) => [g.slug, g.system]));
  const systems = new Set<string>();
  for (const h of history) {
    const sys = bySlug.get(h.gameSlug);
    if (sys) systems.add(sys);
  }
  return systems.size;
}

function secondsForSystem(
  history: PlayHistoryEntry[],
  system: string,
): number {
  const games = getAllGames();
  const slugs = new Set(
    games.filter((g) => g.system === system).map((g) => g.slug),
  );
  return history
    .filter((h) => slugs.has(h.gameSlug))
    .reduce((sum, h) => sum + h.totalSeconds, 0);
}

function gamesPlayed(history: PlayHistoryEntry[]): number {
  return history.filter((h) => h.sessions > 0 || h.totalSeconds > 0).length;
}

export function isRuleMet(
  def: AchievementDef,
  history: PlayHistoryEntry[],
  favoriteCount: number,
): boolean {
  const rule = def.rule;
  switch (rule.type) {
    case "first_play":
      return history.some((h) => h.sessions > 0 || h.totalSeconds > 0);
    case "play_minutes": {
      if (def.system) {
        return secondsForSystem(history, def.system) >= rule.minutes * 60;
      }
      return totalSeconds(history, rule.gameSlug) >= rule.minutes * 60;
    }
    case "sessions":
      return totalSessions(history, rule.gameSlug) >= rule.count;
    case "favorite_count":
      return favoriteCount >= rule.count;
    case "systems_played":
      return systemsPlayed(history) >= rule.count;
    case "games_played":
      return gamesPlayed(history) >= rule.count;
    case "single_game_minutes":
      return history.some((h) => h.totalSeconds >= rule.minutes * 60);
    case "single_game_sessions":
      return history.some((h) => h.sessions >= rule.count);
    default:
      return false;
  }
}

/** Evaluate all defs; unlock newly earned; return fresh unlocks. */
export async function evaluateAchievements(
  profileId: string,
): Promise<AchievementUnlock[]> {
  const history = await getHistoryForProfile(profileId);
  const favorites = await getFavorites(profileId);
  const already = new Set(
    (await getUnlocks(profileId)).map((u) => u.achievementId),
  );
  const fresh: AchievementUnlock[] = [];
  for (const def of DEFS) {
    if (already.has(def.id)) continue;
    if (!isRuleMet(def, history, favorites.length)) continue;
    const unlocked = await unlockAchievement(profileId, def.id);
    if (unlocked) fresh.push(unlocked);
  }
  return fresh;
}
