import 'dart:convert'; import 'dart:developer'; import 'package:http/http.dart' as http; import 'package:sudoku_app/models/sudoku_game_dto.dart'; import 'package:sudoku_app/models/unified_rank_dto.dart'; import 'package:sudoku_app/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}'); } } // ๋žญํ‚น ๋“ฑ๋ก Future> submitRank(UnifiedRankDto rankDto) async { final requestBody = jsonEncode(rankDto.toJson()); log(">>> ๋žญํ‚น ๋“ฑ๋ก ์š”์ฒญ: $requestBody"); final response = await http.post( Uri.parse('$_baseUrl/api/ranks/submit'), headers: {'Content-Type': 'application/json'}, body: requestBody, ); // ๐Ÿ”ฝ [์ˆ˜์ •] ์„ฑ๊ณต(200) ์‹œ, ์„œ๋ฒ„๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๋žญํ‚น ๋ฆฌ์ŠคํŠธ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ if (response.statusCode == 200) { log("<<< ๋žญํ‚น ๋“ฑ๋ก ์„ฑ๊ณต: 200 OK (๋žญํ‚น ๋ชฉ๋ก ๋ฐ˜ํ™˜๋จ)"); try { final List data = jsonDecode(utf8.decode(response.bodyBytes)); return data.map((json) => GameRankDto.fromJson(json)).toList(); } 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 { throw Exception('๋žญํ‚น ๋กœ๋”ฉ ์‹คํŒจ'); } } }