import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import '../../../core/network/network_client.dart'; import '../../../core/errors/network_exceptions.dart'; /// 네이버 GraphQL API 클라이언트 /// /// 네이버 지도의 GraphQL API를 호출하여 상세 정보를 가져옵니다. class NaverGraphQLApi { final NetworkClient _networkClient; static const String _graphqlEndpoint = 'https://pcmap-api.place.naver.com/graphql'; NaverGraphQLApi({NetworkClient? networkClient}) : _networkClient = networkClient ?? NetworkClient(); /// GraphQL 쿼리 실행 Future> fetchGraphQL({ required String operationName, required String query, Map? variables, }) async { try { final response = await _networkClient.post>( _graphqlEndpoint, data: { 'operationName': operationName, 'query': query, 'variables': variables ?? {}, }, options: Options( headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Referer': 'https://map.naver.com/', 'Origin': 'https://map.naver.com', }, ), ); if (response.data == null) { throw ParseException( message: 'GraphQL 응답이 비어있습니다', ); } return response.data!; } on DioException catch (e) { debugPrint('fetchGraphQL error: $e'); throw ServerException( message: 'GraphQL 요청 중 오류가 발생했습니다', statusCode: e.response?.statusCode ?? 500, originalError: e, ); } } /// 장소 상세 정보 가져오기 (한국어 텍스트) Future> fetchKoreanTextsFromPcmap(String placeId) async { const query = ''' query getKoreanTexts(\$id: String!) { place(input: { id: \$id }) { id name category businessHours { description isDayOff openTime closeTime dayOfWeek businessHours } phone address { roadAddress jibunAddress } description menuInfo { menus { name price description images { url } } } keywords priceCategory imageCount visitorReviewCount visitorReviewScore } } '''; try { final response = await fetchGraphQL( operationName: 'getKoreanTexts', query: query, variables: {'id': placeId}, ); if (response['errors'] != null) { debugPrint('GraphQL errors: ${response['errors']}'); throw ParseException( message: 'GraphQL 오류: ${response['errors']}', ); } return response['data']?['place'] ?? {}; } catch (e) { debugPrint('fetchKoreanTextsFromPcmap error: $e'); rethrow; } } /// 장소 기본 정보 가져오기 Future> fetchPlaceBasicInfo(String placeId) async { const query = ''' query getPlaceBasicInfo(\$id: String!) { place(input: { id: \$id }) { id name category phone address { roadAddress jibunAddress } location { latitude longitude } homepageUrl bookingUrl } } '''; try { final response = await fetchGraphQL( operationName: 'getPlaceBasicInfo', query: query, variables: {'id': placeId}, ); if (response['errors'] != null) { throw ParseException( message: 'GraphQL 오류: ${response['errors']}', ); } return response['data']?['place'] ?? {}; } catch (e) { debugPrint('fetchPlaceBasicInfo error: $e'); rethrow; } } void dispose() { // 필요시 리소스 정리 } }