55import lombok .extern .slf4j .Slf4j ;
66import org .springframework .stereotype .Service ;
77import org .springframework .transaction .annotation .Transactional ;
8- import swyp .mingling .domain .meeting .dto .response .midpoint .*;
98import swyp .mingling .domain .meeting .dto .StationCoordinate ;
9+ import swyp .mingling .domain .meeting .dto .response .midpoint .*;
1010import swyp .mingling .domain .meeting .repository .HotPlaceRepository ;
1111import swyp .mingling .domain .meeting .repository .MeetingRepository ;
1212import swyp .mingling .domain .subway .dto .SubwayRouteInfo ;
1313import swyp .mingling .domain .subway .service .SubwayRouteService ;
14+ import swyp .mingling .external .dto .response .KakaoPlaceSearchResponse ;
1415
1516import java .util .*;
1617import java .util .concurrent .CompletableFuture ;
@@ -27,6 +28,7 @@ public class MidPointAsyncUseCase {
2728 private final FindStationCoordinateUseCase findStationCoordinateUseCase ;
2829 private final HotPlaceRepository hotPlaceRepository ;
2930 private final SubwayRouteService subwayRouteService ;
31+ private final SearchPlaceCountUseCase searchPlaceCountUseCase ;
3032
3133 public List <GetMidPointResponse > execute (UUID meetingId ) {
3234 long startTime = System .currentTimeMillis ();
@@ -71,6 +73,9 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
7173 .limit (5 )
7274 .toList ();
7375
76+ //카테고리 가져오기
77+ String category = meetingRepository .findPurposeNamesByMeetingId (meetingId ).orElse ("식당" );
78+
7479 // ========================================
7580 // 편차가 작은 번화가 3개 추출 (비동기 병렬 처리)
7681 // ========================================
@@ -118,21 +123,35 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
118123 }))
119124 .toList ();
120125
126+ //수정: 카카오 장소 추천 API를 비동기로 요청
127+ CompletableFuture <KakaoPlaceSearchResponse > kakaoPlaceSearchResponse = CompletableFuture .supplyAsync (() ->
128+ searchPlaceCountUseCase .execute (fivehotlist .getName (), category , 1 , 15 )
129+ );
130+
131+ // 비동기 작업을 하나의 리스트로 통합
132+ List <CompletableFuture <?>> allCombinedTasks = new ArrayList <>(routeFutures );
133+ allCombinedTasks .add (kakaoPlaceSearchResponse );
134+
121135 // [개선사항]
122136 // allOf()를 사용하여 모든 경로 조회를 한번에 대기
123137 // 기존: routeFutures.stream().map(CompletableFuture::join) == 순차 대기
124138 // 개선: allOf()로 묶어서 가장 느린 작업 하나만 기다림
125139 CompletableFuture <Void > allRoutes = CompletableFuture .allOf (
126- routeFutures .toArray (new CompletableFuture [0 ])
140+ allCombinedTasks .toArray (new CompletableFuture [0 ])
127141 );
128142
143+
129144 // 모든 경로가 완료되면 MidPointCandidate 생성
130145 // thenApply()로 비블로킹 방식으로 후속 처리
131146 return allRoutes .thenApply (v -> {
132147 List <SubwayRouteInfo > routes = routeFutures .stream ()
133148 .map (CompletableFuture ::join )
134149 .toList ();
135150
151+ KakaoPlaceSearchResponse place = kakaoPlaceSearchResponse .join ();
152+
153+ int placeCount = place .getMeta ().getTotalCount ();
154+
136155 int min = Integer .MAX_VALUE ;
137156 int max = Integer .MIN_VALUE ;
138157
@@ -151,7 +170,7 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
151170
152171 int avgTime = sum / routes .size ();
153172
154- return new MidPointCandidate (routes , deviation , avgTime );
173+ return new MidPointCandidate (routes , deviation , avgTime , false , placeCount );
155174 });
156175 })
157176 .toList ();
@@ -170,22 +189,46 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
170189 .map (CompletableFuture ::join )
171190 .toList ();
172191
173- List <List <SubwayRouteInfo >> midlist =
192+ // 이동시간 + 편차 고려한 리스트 중 2개 추출
193+ List <MidPointCandidate > sortedByFairness =
174194 candidates .stream ()
175195 .sorted (
176196 Comparator .comparing (MidPointCandidate ::getDeviation )
177197 .thenComparing (MidPointCandidate ::getAvgTime )
178198 )
179- .limit (3 )
180- .map (MidPointCandidate ::getRoutes )
199+ .limit (2 )
181200 .toList ();
182201
202+ // 장소 개수 기준 상위 1개 추출 (중복 여부 상관없이 1위 추출)
203+ MidPointCandidate hotnessSelection = candidates .stream ()
204+ .sorted (Comparator .comparing (MidPointCandidate ::getPlaceCount ).reversed ())
205+ .findFirst ()
206+ .orElse (sortedByFairness .get (0 )); // 만약 리스트가 비어있을 경우 대비
207+
208+ // 장소가 가장많은 중간지점은 Hot = true
209+ hotnessSelection .setHot (true );
210+
211+ // 중복 제거를 위한 LinkedHashSet
212+ Set <MidPointCandidate > set = new LinkedHashSet <>();
213+ // 중간지점 추가
214+ set .addAll (sortedByFairness );
215+ set .add (hotnessSelection );
216+
217+ List <MidPointCandidate > finalThree = new ArrayList <>(set );
218+
219+ // // List<List<SubwayRouteInfo>> 형식으로 변환
220+ // List<List<SubwayRouteInfo>> midlist = finalThree.stream()
221+ // .map(MidPointCandidate::getRoutes)
222+ // .toList();
223+
183224 // 1. 결과 데이터를 담을 리스트 (좌표 조회 캐시 적용)
184- List <GetMidPointResponse > finalResult = midlist .stream ()
225+ List <GetMidPointResponse > finalResult = finalThree .stream ()
185226 .map (routeList -> {
186227 // 이 그룹의 공통 목적지 추출
187- String endStationName = routeList .get (0 ).getEndStation ();
188- String endStationLine = routeList .get (0 ).getEndStationLine ();
228+ String endStationName = routeList .getRoutes ().get (0 ).getEndStation ();
229+ String endStationLine = routeList .getRoutes ().get (0 ).getEndStationLine ();
230+ Boolean isHot = routeList .isHot ();
231+ Integer placeCount = routeList .getPlaceCount ();
189232
190233 // 목적지 좌표 캐싱
191234 StationCoordinate endStationCoord = stationCoordinateCache .computeIfAbsent ( // 만약 데이터가 없으면 계산
@@ -194,9 +237,9 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
194237 );
195238
196239 // 2. 인덱스를 활용해 사용자별 닉네임과 경로 정보를 매핑 (IntStream 사용)
197- List <UserRouteDto > userRouteDtos = IntStream .range (0 , routeList .size ())
240+ List <UserRouteDto > userRouteDtos = IntStream .range (0 , routeList .getRoutes (). size ())
198241 .mapToObj (i -> {
199- SubwayRouteInfo route = routeList .get (i );
242+ SubwayRouteInfo route = routeList .getRoutes (). get (i );
200243 // 기존 참여자 리스트(departurelists)에서 같은 순서의 닉네임을 가져옴
201244 String nickname = departurelists .get (i ).getNickname ();
202245
@@ -225,13 +268,24 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
225268 // 경로 상 역들의 좌표 캐싱
226269 List <StationPathResponse > stationResponses = route .getStations ().stream ()
227270 .map (station -> {
271+ String name = station .getStationName ();
272+ String line = station .getLineNumber ();
273+
274+ //검색어
275+ String searchName = name ;
276+
277+ //경의중앙선 양평 검색어 변경
278+ if ("양평" .equals (name ) && "경의선" .equals (line )) {
279+ searchName = "양평(경의중앙선)" ;
280+ }
281+
228282 StationCoordinate coord = stationCoordinateCache .computeIfAbsent (
229- station . getStationName () ,
283+ searchName ,
230284 stationName -> findStationCoordinateUseCase .excute (stationName )
231285 );
232286 return StationPathResponse .from (
233- station . getLineNumber () ,
234- station . getStationName () ,
287+ line ,
288+ name ,
235289 coord .getLatitude (),
236290 coord .getLongitude ()
237291 );
@@ -257,6 +311,8 @@ public List<GetMidPointResponse> execute(UUID meetingId) {
257311 .endStation (endStationName )
258312 .latitude (endStationCoord .getLatitude ())
259313 .longitude (endStationCoord .getLongitude ())
314+ .isHot (isHot )
315+ .placeCount (placeCount )
260316 .userRoutes (userRouteDtos )
261317 .build ();
262318 })
0 commit comments