package com.red.circle.other.app.common.gift;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftBusinessEvent;
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftUser;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.game.GameLuckyGiftMsgCO;
import com.red.circle.other.app.service.task.RoomDailyTaskProgressService;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.other.GiftCacheService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.entity.game.GameLuckyGiftCount;
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftCountService;
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import java.math.BigDecimal;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

class LuckyGiftResultProcessorTest {

  @Test
  void process_shouldUseGiftUnitPriceToCalculateMultiple() {
    GameLuckyGiftCountService gameLuckyGiftCountService = mock(GameLuckyGiftCountService.class);
    GiftCacheService giftCacheService = mock(GiftCacheService.class);
    UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
    UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
    ImGroupClient imGroupClient = mock(ImGroupClient.class);
    RoomDailyTaskProgressService roomDailyTaskProgressService = mock(RoomDailyTaskProgressService.class);
    RoomMemberService roomMemberService = mock(RoomMemberService.class);
    RedisService redisService = mock(RedisService.class);
    RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
    GameLuckyGiftCommon gameLuckyGiftCommon = mock(GameLuckyGiftCommon.class);
    LuckyGiftSendMetricsService luckyGiftSendMetricsService = mock(LuckyGiftSendMetricsService.class);
    LuckyGiftResultProcessor processor = new LuckyGiftResultProcessor(
        gameLuckyGiftCountService,
        giftCacheService,
        userProfileGateway,
        userProfileAppConvertor,
        imGroupClient,
        roomDailyTaskProgressService,
        roomMemberService,
        redisService,
        roomProfileManagerService,
        gameLuckyGiftCommon,
        luckyGiftSendMetricsService
    );

    GiftConfigDTO giftConfig = new GiftConfigDTO()
        .setId(11L)
        .setGiftCandy(BigDecimal.valueOf(173))
        .setGiftPhoto("gift.png");
    UserProfile senderProfile = new UserProfile();
    senderProfile.setId(1001L);
    senderProfile.setAccount("sender001");
    senderProfile.setUserNickname("sender");

    UserProfile acceptProfile = new UserProfile();
    acceptProfile.setId(2002L);
    acceptProfile.setUserNickname("receiver");

    UserProfileDTO senderProfileDTO = new UserProfileDTO();
    senderProfileDTO.setId(1001L);
    senderProfileDTO.setAccount("sender001");
    senderProfileDTO.setUserNickname("sender");
    senderProfileDTO.setUserAvatar("sender.png");

    when(giftCacheService.getById(11L)).thenReturn(giftConfig);
    when(userProfileGateway.getByUserId(1001L)).thenReturn(senderProfile);
    when(userProfileGateway.getByUserId(2002L)).thenReturn(acceptProfile);
    when(userProfileAppConvertor.toUserProfileDTO(senderProfile)).thenReturn(senderProfileDTO);
    when(gameLuckyGiftCommon.getRewardMultipleType(20)).thenReturn("SUPER");
    when(roomMemberService.getRoomMember(3003L, 1001L)).thenReturn(null);

    GameLuckyGiftBusinessEvent event = new GameLuckyGiftBusinessEvent()
        .setBusinessId("biz-001")
        .setUserId(1001L)
        .setRoomId(3003L)
        .setRoomAccount("room-account")
        .setSysOrigin("LIKEI")
        .setGiftId(11L)
        .setGiftPrice(BigDecimal.valueOf(173))
        .setQuantity(4)
        .setGiftCombos(0)
        .setRegionCode("SA")
        .setUsers(List.of(
            new GameLuckyGiftUser()
                .setId(90001L)
                .setAcceptUserId(2002L)
        ));

    LuckyGiftGoClient.LuckyGiftGoDrawResponse response = new LuckyGiftGoClient.LuckyGiftGoDrawResponse()
        .setBusinessId("biz-001")
        .setBalanceAfter(999999L)
        .setResults(List.of(
            new LuckyGiftGoClient.LuckyGiftGoDrawResult()
                .setId("90001")
                .setAcceptUserId(2002L)
                .setIsWin(true)
                .setRewardNum(3460L)
        ));

    processor.process(event, response);

    verify(luckyGiftSendMetricsService).settle(
        "biz-001",
        3003L,
        1001L,
        BigDecimal.valueOf(173),
        4,
        List.of(2002L)
    );

    ArgumentCaptor<GameLuckyGiftCount> countCaptor = ArgumentCaptor.forClass(GameLuckyGiftCount.class);
    verify(gameLuckyGiftCountService).saveOrUpdate(countCaptor.capture());
    GameLuckyGiftCount saved = countCaptor.getValue();
    assertEquals(Long.valueOf(692L), saved.getPayAmount());
    assertEquals(Integer.valueOf(20), saved.getMultiple());
    assertEquals(Long.valueOf(3460L), saved.getAwardAmount());

    ArgumentCaptor<BroadcastGroupMsgBodyCmd> messageCaptor = ArgumentCaptor.forClass(BroadcastGroupMsgBodyCmd.class);
    verify(imGroupClient).sendMessageBroadcast(messageCaptor.capture());
    GameLuckyGiftMsgCO message = (GameLuckyGiftMsgCO) messageCaptor.getValue().getData();
    assertEquals(Integer.valueOf(20), message.getMultiple());
    assertEquals(Long.valueOf(3460L), message.getAwardAmount());
  }
}
