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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.mq.MessageEventProcess;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
import com.red.circle.external.inner.model.enums.message.GroupMessageTypeEnum;
import com.red.circle.mq.business.model.event.gift.GiveAwayGiftBatchEvent;
import com.red.circle.mq.business.model.event.gift.GiveAwayGiftRoomAccepts;
import com.red.circle.mq.business.model.event.gift.GiveGiftConfig;
import com.red.circle.mq.rocket.business.producer.GameMqMessage;
import com.red.circle.mq.rocket.business.producer.GiftMqMessage;
import com.red.circle.other.app.command.game.barrage.BarrageGameBaishunExe;
import com.red.circle.other.app.command.game.burstcrystal.GameBurstCrystalScheduleTwoFunQueryExe;
import com.red.circle.other.app.command.game.roompk.GameRoomPkUserCmdExe;
import com.red.circle.other.app.command.game.teampk.GameTeamPkBaseInfoCmdExe;
import com.red.circle.other.app.common.gift.GameLuckyGiftCommon;
import com.red.circle.other.app.dto.clientobject.gift.SendGiftNotifyCO;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.cache.service.other.LiveHeartbeatCacheService;
import com.red.circle.other.infra.database.mongo.entity.gift.GiftGiveRunningWater;
import com.red.circle.other.infra.database.mongo.entity.gift.GiftValue;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.service.gift.GiftCountAnchorDailyRunningWaterService;
import com.red.circle.other.infra.database.mongo.service.gift.GiftGiveRunningWaterService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamBillCycleService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService;
import com.red.circle.other.inner.enums.material.GiftSpecialEnum;
import java.math.BigDecimal;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

class GiveGiftsListenerTest {

  private final ImGroupClient imGroupClient = mock(ImGroupClient.class);
  private final RoomProfileManagerService roomProfileManagerService = mock(
      RoomProfileManagerService.class);
  private final GiveGiftsListener listener = new GiveGiftsListener(
      mock(GameMqMessage.class),
      mock(GiftMqMessage.class),
      mock(TeamMemberService.class),
      mock(UserRegionGateway.class),
      mock(MessageEventProcess.class),
      mock(GameLuckyGiftCommon.class),
      mock(TeamBillCycleService.class),
      mock(TeamPolicyManagerService.class),
      mock(EnumConfigCacheService.class),
      mock(LiveHeartbeatCacheService.class),
      mock(GiftGiveRunningWaterService.class),
      imGroupClient,
      roomProfileManagerService,
      mock(GameTeamPkBaseInfoCmdExe.class),
      mock(GameRoomPkUserCmdExe.class),
      mock(BarrageGameBaishunExe.class),
      mock(GameBurstCrystalScheduleTwoFunQueryExe.class),
      mock(GiftCountAnchorDailyRunningWaterService.class)
  );

  @Test
  void sendNoticeGiftBroadcastShouldBroadcastNoticeGift() {
    RoomProfile roomProfile = new RoomProfile();
    roomProfile.setRoomAccount("1002001");
    when(roomProfileManagerService.getProfileById(2001L))
        .thenReturn(roomProfile);

    listener.sendNoticeGiftBroadcast(
        event(GiftSpecialEnum.NOTICE.name(), "GOLD"),
        runningWater()
    );

    ArgumentCaptor<BroadcastGroupMsgBodyCmd> captor = ArgumentCaptor.forClass(
        BroadcastGroupMsgBodyCmd.class);
    verify(imGroupClient).sendMessageBroadcast(captor.capture());

    BroadcastGroupMsgBodyCmd message = captor.getValue();
    assertEquals(GroupMessageTypeEnum.SEND_GIFT.name(), message.getType());
    assertEquals(SysOriginPlatformEnum.LIKEI, message.getSysOrigin());

    SendGiftNotifyCO data = (SendGiftNotifyCO) message.getData();
    assertTrue(data.getGlobalNews());
    assertEquals(2001L, data.getRoomId());
    assertEquals("1002001", data.getRoomAccount());
    assertEquals(3001L, data.getSendUserId());
    assertEquals(List.of(4001L), data.getAcceptUserIds());
    assertEquals(5001L, data.getGiftId());
    assertEquals(2, data.getGiftQuantity());
    assertEquals(new BigDecimal("20"), data.getGiftCandy());
    assertEquals(new BigDecimal("40"), data.getActualAmount());
    assertEquals("NORMAL", data.getGiftType());
  }

  @Test
  void sendNoticeGiftBroadcastShouldIgnoreNonNoticeGift() {
    listener.sendNoticeGiftBroadcast(event("ANIMATION", "GOLD"), runningWater());

    verify(imGroupClient, never()).sendMessageBroadcast(any());
  }

  @Test
  void sendNoticeGiftBroadcastShouldIgnoreLuckyGift() {
    listener.sendNoticeGiftBroadcast(event(GiftSpecialEnum.NOTICE.name(), "LUCKY_GIFT"),
        runningWater());

    verify(imGroupClient, never()).sendMessageBroadcast(any());
  }

  private GiveAwayGiftBatchEvent event(String special, String giftTab) {
    return new GiveAwayGiftBatchEvent()
        .setSysOrigin(SysOriginPlatformEnum.LIKEI)
        .setRoomId(2001L)
        .setSendUserId(3001L)
        .setAccepts(List.of(new GiveAwayGiftRoomAccepts().setAcceptUserId(4001L)))
        .setQuantity(2)
        .setTrackId(6001L)
        .setGiftConfig(new GiveGiftConfig()
            .setId(5001L)
            .setSpecial(special)
            .setType("GOLD")
            .setGiftTab(giftTab)
            .setGiftCandy(new BigDecimal("20")));
  }

  private GiftGiveRunningWater runningWater() {
    return new GiftGiveRunningWater()
        .setGiftValue(new GiftValue()
            .setGiftType("NORMAL")
            .setActualAmount(new BigDecimal("40")));
  }
}
