package eric.Roullette.service; import eric.Roullette.dto.PlayersMessage; import eric.Roullette.util.JsonUtil; import io.javalin.websocket.WsContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.*; public class GameService { private static final Logger log = LoggerFactory.getLogger(GameService.class); private final SpotifyAuthService authService; private final Map> sessions = new ConcurrentHashMap<>(); private final Map games = new ConcurrentHashMap<>(); public GameService(SpotifyAuthService authService) { // <-- Konstruktor this.authService = authService; } public Map> getTrackInfos(Map> allPlayerTracks) { // für jeden String Spieler in allPlayerTracks die Liste der Tracks an authservice übergeben Map> trackInfos = new ConcurrentHashMap<>(); for (Map.Entry> entry : allPlayerTracks.entrySet()) { String player = entry.getKey(); List tracks = entry.getValue(); if (tracks.isEmpty()) continue; // Keine Tracks, skip try { List trackInfo = authService.getTrackInfos(tracks); trackInfos.put(player, trackInfo); } catch (Exception e) { log.error("Fehler beim Abrufen der Track-Infos für Spieler {}: {}", player, e.getMessage()); } } return trackInfos; } public record Game(String id, List players, Map scores, String currentOwner, String currentSong, List allTracks, Map> playerTracks) { public static Game create(String id) { return new Game(id, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>(), new ConcurrentHashMap<>()); } } public Game getOrCreateGame(String gameId) { return games.computeIfAbsent(gameId, Game::create); } public void addPlayer(String gameId, String user) throws InterruptedException { Game g = getOrCreateGame(gameId); if (user != null && !g.players().contains(user)) { g.players().add(user); g.scores().putIfAbsent(user, 0); // Songs einmalig laden und speichern List tracks = authService.getRecentTracks(user); g.playerTracks().put(user, tracks); } } public void registerSession(String gameId, WsContext ctx) { sessions .computeIfAbsent(gameId, id -> ConcurrentHashMap.newKeySet()) .add(ctx); broadcastPlayers(gameId); } public void removeSession(String gameId, WsContext ctx) { sessions.getOrDefault(gameId, Collections.emptySet()).remove(ctx); broadcastPlayers(gameId); } public void broadcastPlayers(String gameId) { Game game = games.get(gameId); if (game == null) return; PlayersMessage msg = new PlayersMessage(new ArrayList<>(game.players())); sessions.getOrDefault(gameId, Collections.emptySet()) .forEach(ctx -> ctx.send(JsonUtil.toJson(msg))); } public void createGame(String gameId) { Game game = new Game(gameId, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>(), new ConcurrentHashMap<>()); games.put(gameId, game); } public boolean gameExists(String gameId) { return games.containsKey(gameId); } public Game startRound(String gameId, List uris) { Game g = getOrCreateGame(gameId); if (g.players().isEmpty()) throw new IllegalStateException("No players"); String owner = g.players().get(ThreadLocalRandom.current().nextInt(g.players().size())); List ownerTracks = g.playerTracks().getOrDefault(owner, List.of()); if (ownerTracks.isEmpty()) throw new IllegalStateException("Owner hat keine Tracks"); String song = ownerTracks.get(ThreadLocalRandom.current().nextInt(ownerTracks.size())); //String song = uris.get(ThreadLocalRandom.current().nextInt(uris.size())); Game updated = new Game(gameId, g.players(), g.scores(), owner, song, uris, g.playerTracks()); games.put(gameId, updated); return updated; } public Set getSessions(String gameId) { return sessions.getOrDefault(gameId, Collections.emptySet()); } // Map> public Map> getPlayerTracks(String gameId) { Game game = games.get(gameId); if (game == null) return Collections.emptyMap(); return game.playerTracks(); } }