1212import com .back .domain .cocktail .entity .Cocktail ;
1313import com .back .domain .cocktail .enums .AlcoholBaseType ;
1414import com .back .domain .cocktail .enums .AlcoholStrength ;
15+ import com .back .domain .cocktail .enums .CocktailType ;
1516import com .back .domain .cocktail .repository .CocktailRepository ;
17+ import com .fasterxml .jackson .core .JsonProcessingException ;
1618import com .fasterxml .jackson .databind .ObjectMapper ;
1719import jakarta .annotation .PostConstruct ;
1820import lombok .RequiredArgsConstructor ;
2729import org .springframework .stereotype .Service ;
2830import org .springframework .transaction .annotation .Transactional ;
2931import org .springframework .util .StreamUtils ;
30- import com .fasterxml .jackson .core .JsonProcessingException ;
3132
3233import java .io .IOException ;
3334import java .nio .charset .StandardCharsets ;
@@ -722,8 +723,18 @@ private ChatResponseDto handleStepRecommendation(ChatRequestDto requestDto) {
722723 break ;
723724
724725 case 2 :
725- stepData = getAlcoholBaseTypeOptions (parseAlcoholStrength (requestDto .getSelectedAlcoholStrength ()));
726- message = "좋은 선택이네요! \n 이제 베이스가 될 술을 선택해주세요 🍸" ;
726+ // 논알콜 선택 여부에 따라 다른 옵션 제공
727+ boolean isNonAlcoholic = "NON_ALCOHOLIC" .equals (requestDto .getSelectedAlcoholStrength ());
728+
729+ if (isNonAlcoholic ) {
730+ // 논알콜인 경우: 글라스 타입 선택
731+ stepData = getCocktailTypeOptions ();
732+ message = "논알콜 칵테일이네요! 🥤\n 어떤 스타일의 칵테일을 원하시나요?" ;
733+ } else {
734+ // 알콜인 경우: 베이스 타입 선택
735+ stepData = getAlcoholBaseTypeOptions (parseAlcoholStrength (requestDto .getSelectedAlcoholStrength ()));
736+ message = "좋은 선택이네요! \n 이제 베이스가 될 술을 선택해주세요 🍸" ;
737+ }
727738 type = MessageType .RADIO_OPTIONS ;
728739 break ;
729740
@@ -740,11 +751,23 @@ private ChatResponseDto handleStepRecommendation(ChatRequestDto requestDto) {
740751 break ;
741752
742753 case 4 :
743- stepData = getFinalRecommendationsWithMessage (
744- parseAlcoholStrength (requestDto .getSelectedAlcoholStrength ()),
745- parseAlcoholBaseType (requestDto .getSelectedAlcoholBaseType ()),
746- requestDto .getMessage ()
747- );
754+ // 논알콜 여부 다시 확인
755+ boolean isNonAlcoholicFinal = "NON_ALCOHOLIC" .equals (requestDto .getSelectedAlcoholStrength ());
756+
757+ if (isNonAlcoholicFinal ) {
758+ // 논알콜: 도수와 칵테일 타입으로 검색
759+ stepData = getFinalRecommendationsForNonAlcoholic (
760+ parseCocktailType (requestDto .getSelectedCocktailType ()),
761+ requestDto .getMessage ()
762+ );
763+ } else {
764+ // 알콜: 도수와 베이스 타입으로 검색
765+ stepData = getFinalRecommendationsWithMessage (
766+ parseAlcoholStrength (requestDto .getSelectedAlcoholStrength ()),
767+ parseAlcoholBaseType (requestDto .getSelectedAlcoholBaseType ()),
768+ requestDto .getMessage ()
769+ );
770+ }
748771 message = stepData .getStepTitle ();
749772 type = MessageType .CARD_LIST ;
750773 break ;
@@ -776,6 +799,44 @@ private ChatResponseDto handleStepRecommendation(ChatRequestDto requestDto) {
776799 .build ();
777800 }
778801
802+ private StepRecommendationResponseDto getCocktailTypeOptions () {
803+ List <StepRecommendationResponseDto .StepOption > options = new ArrayList <>();
804+
805+ options .add (new StepRecommendationResponseDto .StepOption (
806+ "ALL" ,
807+ "전체" ,
808+ null
809+ ));
810+
811+ for (CocktailType type : CocktailType .values ()) {
812+ options .add (new StepRecommendationResponseDto .StepOption (
813+ type .name (),
814+ type .getDescription (),
815+ null
816+ ));
817+ }
818+
819+ return new StepRecommendationResponseDto (
820+ 2 ,
821+ "어떤 스타일의 칵테일을 원하시나요?" ,
822+ options ,
823+ null ,
824+ false
825+ );
826+ }
827+
828+ private CocktailType parseCocktailType (String value ) {
829+ if (value == null || value .trim ().isEmpty () || "ALL" .equalsIgnoreCase (value )) {
830+ return null ;
831+ }
832+ try {
833+ return CocktailType .valueOf (value );
834+ } catch (IllegalArgumentException e ) {
835+ log .warn ("Invalid CocktailType value: {}" , value );
836+ return null ;
837+ }
838+ }
839+
779840 private AlcoholStrength parseAlcoholStrength (String value ) {
780841 if (value == null || value .trim ().isEmpty () || "ALL" .equalsIgnoreCase (value )) {
781842 return null ;
@@ -900,4 +961,52 @@ private StepRecommendationResponseDto getFinalRecommendationsWithMessage(
900961 true
901962 );
902963 }
903- }
964+ private StepRecommendationResponseDto getFinalRecommendationsForNonAlcoholic (
965+ CocktailType cocktailType ,
966+ String userMessage ) {
967+
968+ // 논알콜 도수만 필터링
969+ List <AlcoholStrength > strengths = List .of (AlcoholStrength .NON_ALCOHOLIC );
970+ List <CocktailType > types = (cocktailType == null ) ? null : List .of (cocktailType );
971+
972+ String keyword = null ;
973+ if (userMessage != null && !userMessage .trim ().isEmpty ()) {
974+ String trimmed = userMessage .trim ().toLowerCase ();
975+ if (!trimmed .equals ("x" ) && !trimmed .equals ("없음" )) {
976+ keyword = userMessage ;
977+ }
978+ }
979+
980+ Page <Cocktail > cocktailPage = cocktailRepository .searchWithFilters (
981+ keyword ,
982+ strengths ,
983+ types , // 칵테일 타입 필터 적용
984+ null , // 베이스 타입은 null
985+ PageRequest .of (0 , 3 )
986+ );
987+
988+ List <CocktailSummaryResponseDto > recommendations = cocktailPage .getContent ().stream ()
989+ .map (cocktail -> new CocktailSummaryResponseDto (
990+ cocktail .getId (),
991+ cocktail .getCocktailName (),
992+ cocktail .getCocktailNameKo (),
993+ cocktail .getCocktailImgUrl (),
994+ cocktail .getAlcoholStrength ().getDescription ()
995+ ))
996+ .collect (Collectors .toList ());
997+
998+ String stepTitle = recommendations .isEmpty ()
999+ ? "조건에 맞는 논알콜 칵테일을 찾을 수 없습니다 😢"
1000+ : "짠🎉🎉 논알콜 칵테일 추천!\n " +
1001+ "칵테일의 자세한 정보는 '상세보기'를 클릭해서 확인할 수 있어요.\n " +
1002+ "마음에 드는 칵테일은 '킵' 버튼을 눌러 나만의 Bar에 저장해보세요!" ;
1003+
1004+ return new StepRecommendationResponseDto (
1005+ 4 ,
1006+ stepTitle ,
1007+ null ,
1008+ recommendations ,
1009+ true
1010+ );
1011+ }
1012+ }
0 commit comments