2025-11-07 17:07:22 +09:00
|
|
|
import 'dart:convert';
|
2025-11-10 18:02:01 +09:00
|
|
|
import 'dart:developer'; // 👈 [추가] log 함수를 위한 임포트
|
2025-11-07 17:07:22 +09:00
|
|
|
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 {
|
2025-11-10 18:02:01 +09:00
|
|
|
final String _baseUrl = "https://lunaticbum.kr";
|
2025-11-07 17:07:22 +09:00
|
|
|
|
2025-11-10 18:02:01 +09:00
|
|
|
// ... (startGame 함수는 동일) ...
|
|
|
|
|
Future<SudokuGameDto> startGame(String difficulty) async {
|
2025-11-07 17:07:22 +09:00
|
|
|
final response = await http.get(
|
2025-11-10 18:02:01 +09:00
|
|
|
Uri.parse('$_baseUrl/puzzle/sudoku/start?difficulty=$difficulty'),
|
2025-11-07 17:07:22 +09:00
|
|
|
);
|
|
|
|
|
if (response.statusCode == 200) {
|
|
|
|
|
final data = jsonDecode(utf8.decode(response.bodyBytes));
|
|
|
|
|
return SudokuGameDto.fromJson(data);
|
|
|
|
|
} else {
|
|
|
|
|
throw Exception('게임 로딩 실패: ${response.statusCode}');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-10 18:02:01 +09:00
|
|
|
// ... (validateSolution 함수는 동일) ...
|
|
|
|
|
Future<bool> validateSolution(int puzzleId, String answer) async {
|
2025-11-07 17:07:22 +09:00
|
|
|
final response = await http.post(
|
|
|
|
|
Uri.parse('$_baseUrl/puzzle/sudoku/validate'),
|
|
|
|
|
headers: {'Content-Type': 'application/json'},
|
|
|
|
|
body: jsonEncode({
|
2025-11-10 18:02:01 +09:00
|
|
|
'puzzleId': puzzleId,
|
2025-11-07 17:07:22 +09:00
|
|
|
'answer': answer,
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
if (response.statusCode == 200) {
|
|
|
|
|
return jsonDecode(response.body)['correct'] ?? false;
|
|
|
|
|
} else {
|
|
|
|
|
log("정답 확인 실패: ${response.statusCode}");
|
|
|
|
|
log("응답 본문: ${response.body}");
|
|
|
|
|
throw Exception('정답 확인 실패: ${response.statusCode}');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// POST /api/ranks/submit
|
|
|
|
|
Future<void> submitRank(UnifiedRankDto rankDto) async {
|
2025-11-10 18:02:01 +09:00
|
|
|
|
|
|
|
|
final requestBody = jsonEncode(rankDto.toJson());
|
|
|
|
|
|
|
|
|
|
// 🔽 [로그 추가] 1. 서버로 전송하는 JSON 데이터 출력
|
|
|
|
|
log(">>> 랭킹 등록 요청: $requestBody");
|
|
|
|
|
|
2025-11-07 17:07:22 +09:00
|
|
|
final response = await http.post(
|
|
|
|
|
Uri.parse('$_baseUrl/api/ranks/submit'),
|
|
|
|
|
headers: {'Content-Type': 'application/json'},
|
2025-11-10 18:02:01 +09:00
|
|
|
body: requestBody,
|
2025-11-07 17:07:22 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (response.statusCode != 200) {
|
2025-11-10 18:02:01 +09:00
|
|
|
// 🔽 [로그 추가] 2. 서버가 200(OK)이 아닌 응답을 줬을 때
|
|
|
|
|
log("<<< 랭킹 등록 실패: ${response.statusCode}");
|
2025-11-07 17:07:22 +09:00
|
|
|
try {
|
|
|
|
|
final errorBody = utf8.decode(response.bodyBytes);
|
2025-11-10 18:02:01 +09:00
|
|
|
log("<<< 서버 에러 메시지: $errorBody"); // 👈 (예: "이미 사용 중인 이름입니다.")
|
2025-11-07 17:07:22 +09:00
|
|
|
throw Exception(errorBody);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
throw Exception('랭킹 등록 실패: ${response.reasonPhrase}');
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-10 18:02:01 +09:00
|
|
|
|
|
|
|
|
// 🔽 [로그 추가] 3. 성공 시
|
|
|
|
|
log("<<< 랭킹 등록 성공: 200 OK");
|
2025-11-07 17:07:22 +09:00
|
|
|
}
|
|
|
|
|
|
2025-11-10 18:02:01 +09:00
|
|
|
// ... (fetchRanks 함수는 동일) ...
|
2025-11-07 17:07:22 +09:00
|
|
|
Future<List<GameRankDto>> 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<dynamic> data = jsonDecode(utf8.decode(response.bodyBytes));
|
|
|
|
|
return data.map((json) => GameRankDto.fromJson(json)).toList();
|
|
|
|
|
} else {
|
|
|
|
|
throw Exception('랭킹 로딩 실패');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|