import 'dart:convert'; import 'dart:developer'; import 'package:http/http.dart' as http; import 'package:service_api/models/sudoku_game_dto.dart'; import 'package:service_api/models/unified_rank_dto.dart'; import 'package:service_api/models/game_rank_dto.dart'; class PuzzleService { final String _baseUrl = "https://lunaticbum.kr"; // πŸ”½ [μˆ˜μ •] 'difficulty' νŒŒλΌλ―Έν„° 1개만 λ°›μŒ (1~11) Future startGame(String difficulty) async { final response = await http.get( // πŸ”½ [μˆ˜μ •] 'difficulty' νŒŒλΌλ―Έν„°λ§Œ 전달 Uri.parse('$_baseUrl/puzzle/sudoku/start?difficulty=$difficulty'), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); return SudokuGameDto.fromJson(data); } else { throw Exception('κ²Œμž„ λ‘œλ”© μ‹€νŒ¨: ${response.statusCode}'); } } // 'puzzleId'λ₯Ό λ°›μ•„ 검증 (μ„œλ²„ DTO와 일치) Future validateSolution(int puzzleId, String answer) async { final response = await http.post( Uri.parse('$_baseUrl/puzzle/sudoku/validate'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'puzzleId': puzzleId, 'answer': answer, }), ); if (response.statusCode == 200) { return jsonDecode(response.body)['correct'] ?? false; } else { log("μ •λ‹΅ 확인 μ‹€νŒ¨: ${response.statusCode}"); log("응닡 λ³Έλ¬Έ: ${response.body}"); throw Exception('μ •λ‹΅ 확인 μ‹€νŒ¨: ${response.statusCode}'); } } // πŸ”½ [전체 μˆ˜μ •] submitRank ν•¨μˆ˜ // λ°˜ν™˜ νƒ€μž…μ΄ Future둜 λ³€κ²½λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Future submitRank(UnifiedRankDto rankDto) async { final requestBody = jsonEncode(rankDto.toJson()); log(">>> λž­ν‚Ή 등둝 μš”μ²­: $requestBody"); final response = await http.post( // πŸ”½ [μˆ˜μ •] API κ²½λ‘œκ°€ /api/ranks/submit Uri.parse('$_baseUrl/api/ranks/submit'), headers: {'Content-Type': 'application/json'}, body: requestBody, ); // πŸ”½ [μˆ˜μ •] 성곡(200) μ‹œ, μ„œλ²„κ°€ λ°˜ν™˜ν•œ RankSubmissionResult 객체λ₯Ό νŒŒμ‹± if (response.statusCode == 200) { log("<<< λž­ν‚Ή 등둝 성곡: 200 OK (RankSubmissionResult λ°˜ν™˜λ¨)"); try { final Map data = jsonDecode(utf8.decode(response.bodyBytes)); // πŸ”½ [μˆ˜μ •] RankSubmissionResult.fromJson으둜 νŒŒμ‹± return RankSubmissionResult.fromJson(data); } catch (e) { log("<<< λž­ν‚Ή 등둝 μ„±κ³΅ν–ˆμœΌλ‚˜, λ°˜ν™˜λœ λž­ν‚Ή λͺ©λ‘ νŒŒμ‹± μ‹€νŒ¨: $e"); throw Exception('λž­ν‚Ή λͺ©λ‘ νŒŒμ‹± μ‹€νŒ¨: $e'); } } // πŸ”½ [μˆ˜μ •] μ‹€νŒ¨ μ‹œ, κΈ°μ‘΄ 둜직과 λ™μΌν•˜κ²Œ μ—λŸ¬ 처리 else { log("<<< λž­ν‚Ή 등둝 μ‹€νŒ¨: ${response.statusCode}"); try { final errorBody = utf8.decode(response.bodyBytes); log("<<< μ„œλ²„ μ—λŸ¬ λ©”μ‹œμ§€: $errorBody"); throw Exception(errorBody); } catch (e) { throw Exception('λž­ν‚Ή 등둝 μ‹€νŒ¨: ${response.reasonPhrase}'); } } } // λž­ν‚Ή 쑰회 Future> fetchRanks(String gameType, String? contextId) async { final queryParams = { 'gameType': gameType, if (contextId != null) 'contextId': contextId, }; final uri = Uri.parse('$_baseUrl/api/ranks/list').replace(queryParameters: queryParams); final response = await http.get(uri); if (response.statusCode == 200) { final List data = jsonDecode(utf8.decode(response.bodyBytes)); return data.map((json) => GameRankDto.fromJson(json)).toList(); } else { // [πŸ”₯ μˆ˜μ •] μ‹€νŒ¨ μ‹œ HTTP μƒνƒœ μ½”λ“œ λͺ…μ‹œ log("λž­ν‚Ή λ‘œλ”© μ‹€νŒ¨: HTTP Status ${response.statusCode}"); throw Exception('λž­ν‚Ή λ‘œλ”© μ‹€νŒ¨: HTTP Status ${response.statusCode}'); } } }