11package com .ccapp .ccgo .mission .service ;
22
33import com .ccapp .ccgo .matching .domain .entity .SubGroup ;
4+ import com .ccapp .ccgo .matching .domain .entity .SubGroupMember ;
45import com .ccapp .ccgo .matching .repository .SubGroupRepository ;
6+ import com .ccapp .ccgo .matching .repository .SubGroupMemberRepository ;
57import com .ccapp .ccgo .mission .dto .ScoreboardResponseDto ;
68import com .ccapp .ccgo .mission .dto .SubGroupMissionDto ;
79import com .ccapp .ccgo .mission .dto .SubGroupScoreDto ;
10+ import com .ccapp .ccgo .mission .dto .MissionHistoryDto ;
811import com .ccapp .ccgo .mission .entity .MissionTemplate ;
912import com .ccapp .ccgo .mission .entity .SubGroupMission ;
13+ import com .ccapp .ccgo .mission .entity .MissionHistory ;
1014import com .ccapp .ccgo .mission .repository .MissionTemplateRepository ;
1115import com .ccapp .ccgo .mission .repository .SubGroupMissionRepository ;
16+ import com .ccapp .ccgo .mission .repository .MissionHistoryRepository ;
1217import lombok .RequiredArgsConstructor ;
1318import java .util .concurrent .ThreadLocalRandom ;
1419import org .springframework .stereotype .Service ;
1722import java .util .Collections ;
1823import java .util .List ;
1924import java .util .stream .Collectors ;
25+ import java .time .LocalDateTime ;
2026
2127@ Service
2228@ RequiredArgsConstructor
2329public class SubGroupMissionService {
2430
2531 private final SubGroupRepository subGroupRepository ;
32+ private final SubGroupMemberRepository subGroupMemberRepository ;
2633 private final MissionTemplateRepository missionTemplateRepository ;
2734 private final SubGroupMissionRepository subGroupMissionRepository ;
35+ private final MissionHistoryRepository missionHistoryRepository ;
2836
2937 // 서브그룹에 미션 부여
3038 @ Transactional
@@ -36,33 +44,34 @@ public void assignMissionsToSubGroup(Long subGroupId) {
3644 throw new IllegalStateException ("이미 이 서브그룹에 미션이 부여되어 있습니다." );
3745 }
3846
39- assignMissionsByScore (subGroup , 1 , 6 );
47+ // 그룹장 중복 미션 방지: 이미 미션을 받은 사용자가 있는지 체크
48+ List <SubGroupMember > groupMembers = subGroupMemberRepository .findBySubGroup_Id (subGroupId );
49+ List <Long > groupMemberIds = groupMembers .stream ()
50+ .map (member -> member .getUser ().getId ())
51+ .collect (Collectors .toList ());
52+
53+ for (Long memberId : groupMemberIds ) {
54+ boolean hasExistingMission = subGroupMissionRepository .existsBySubGroup_Team_TeamIdAndSubGroup_SubGroupMembers_User_Id (
55+ subGroup .getTeam ().getTeamId (), memberId );
56+ if (hasExistingMission ) {
57+ throw new IllegalStateException ("사용자 ID " + memberId + "가 이미 다른 서브그룹에서 미션을 받았습니다." );
58+ }
59+ }
60+
4061 assignMissionsByScore (subGroup , 3 , 6 );
4162 assignMissionsByScore (subGroup , 5 , 6 );
4263 assignMissionsByScore (subGroup , 10 , 6 );
4364 }
4465
4566 private void assignMissionsByScore (SubGroup subGroup , Integer score , int count ) {
46- // 1. 이미 할당된 미션 Template ID 목록 조회
47- List <Long > existingMissionTemplateIds = subGroupMissionRepository .findBySubGroup (subGroup ).stream ()
48- .map (m -> m .getMissionTemplate ().getId ())
49- .toList ();
50-
51- // 2. score 조건에 맞는 미션 템플릿 중 기존 할당 미션 제외
52- List <MissionTemplate > missions = missionTemplateRepository .findByScore (score ).stream ()
53- .filter (m -> !existingMissionTemplateIds .contains (m .getId ()))
54- .toList ();
55-
56- // 3. 미션 개수 체크
67+ List <MissionTemplate > missions = missionTemplateRepository .findByScore (score );
5768 if (missions .size () < count ) {
5869 throw new IllegalStateException (score + "점 미션이 최소 " + count + "개 이상 필요합니다." );
5970 }
6071
61- // 4. 랜덤 섞고 필요한 개수만큼 선택
6272 Collections .shuffle (missions );
6373 List <MissionTemplate > selected = missions .subList (0 , count );
6474
65- // 5. 새 미션 할당
6675 for (MissionTemplate missionTemplate : selected ) {
6776 SubGroupMission mission = SubGroupMission .builder ()
6877 .subGroup (subGroup )
@@ -73,7 +82,6 @@ private void assignMissionsByScore(SubGroup subGroup, Integer score, int count)
7382 }
7483 }
7584
76-
7785 // 미션 완료 처리
7886 @ Transactional
7987 public void completeMission (Long subGroupMissionId ) {
@@ -181,8 +189,71 @@ public void completeMission(Long teamId, Long subGroupId, Long missionTemplateId
181189
182190 // 완료 처리
183191 mission .setCompleted (true );
192+
193+ // 미션 히스토리에 저장
194+ saveMissionHistory (subGroup , mission .getMissionTemplate ());
195+ }
196+
197+ // 미션 히스토리 저장
198+ private void saveMissionHistory (SubGroup subGroup , MissionTemplate missionTemplate ) {
199+ // 서브그룹의 모든 멤버에 대해 히스토리 저장
200+ List <SubGroupMember > members = subGroupMemberRepository .findBySubGroup_Id (subGroup .getId ());
201+
202+ for (SubGroupMember member : members ) {
203+ MissionHistory history = MissionHistory .builder ()
204+ .subGroup (subGroup )
205+ .user (member .getUser ())
206+ .missionTemplate (missionTemplate )
207+ .completedAt (LocalDateTime .now ())
208+ .build ();
209+
210+ missionHistoryRepository .save (history );
211+ }
212+ }
213+
214+ // 서브그룹의 미션 히스토리 조회
215+ @ Transactional (readOnly = true )
216+ public List <MissionHistoryDto > getMissionHistoryBySubGroup (Long subGroupId ) {
217+ List <MissionHistory > histories = missionHistoryRepository .findBySubGroup_IdOrderByCompletedAtDesc (subGroupId );
218+
219+ return histories .stream ()
220+ .map (this ::convertToDto )
221+ .collect (Collectors .toList ());
222+ }
223+
224+ // 사용자의 미션 히스토리 조회
225+ @ Transactional (readOnly = true )
226+ public List <MissionHistoryDto > getMissionHistoryByUser (Long userId ) {
227+ List <MissionHistory > histories = missionHistoryRepository .findByUser_IdOrderByCompletedAtDesc (userId );
228+
229+ return histories .stream ()
230+ .map (this ::convertToDto )
231+ .collect (Collectors .toList ());
232+ }
233+
234+ // 팀의 미션 히스토리 조회
235+ @ Transactional (readOnly = true )
236+ public List <MissionHistoryDto > getMissionHistoryByTeam (Long teamId ) {
237+ List <MissionHistory > histories = missionHistoryRepository .findByTeamIdOrderByCompletedAtDesc (teamId );
238+
239+ return histories .stream ()
240+ .map (this ::convertToDto )
241+ .collect (Collectors .toList ());
242+ }
243+
244+ // MissionHistory를 DTO로 변환
245+ private MissionHistoryDto convertToDto (MissionHistory history ) {
246+ return MissionHistoryDto .builder ()
247+ .id (history .getId ())
248+ .subGroupId (history .getSubGroup ().getId ())
249+ .userId (history .getUser ().getId ())
250+ .userName (history .getUser ().getName ())
251+ .missionTemplateId (history .getMissionTemplate ().getId ())
252+ .missionTitle (history .getMissionTemplate ().getTitle ())
253+ .missionDescription (history .getMissionTemplate ().getDescription ())
254+ .missionScore (history .getMissionTemplate ().getScore ())
255+ .completedAt (history .getCompletedAt ())
256+ .createdAt (history .getCreatedAt ())
257+ .build ();
184258 }
185-
186-
187-
188259}
0 commit comments