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

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
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.mq.rocket.business.producer.GiftMqMessage;
import com.red.circle.mq.rocket.business.service.MessageSenderService;
import com.red.circle.other.app.convertor.material.GiftAppConvertor;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.app.service.game.BaishunRuntimeConfigResolver;
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.config.LuckyGiftApiConfig;
import com.red.circle.other.infra.database.cache.entity.game.luckgift.GameLuckyGiftInventoryCache;
import com.red.circle.other.infra.database.cache.entity.game.luckgift.LuckyGiftInventoryTemplateCache;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.cache.service.other.GameLuckyGiftCacheService;
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.game.GameLuckyGiftRuleConfigService;
import com.red.circle.other.infra.database.rds.service.game.LuckyGiftProbabilityDetailsService;
import com.red.circle.other.infra.database.rds.service.game.LuckyGiftProbabilityService;
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
import com.red.circle.other.infra.database.rds.service.sys.EnumConfigService;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

class GameLuckyGiftCommonTest {

  @Test
  void run_shouldSettleLegacyMetricsWhenAwardIsZero() {
    TestFixture fixture = new TestFixture();
    fixture.mockGiftAndSender();

    GameLuckyGiftParamCmd cmd = fixture.newCmd().setAcceptUserId(3001L);

    fixture.common.run(cmd);

    verify(fixture.luckyGiftSendMetricsService).settle(
        "legacy:9001",
        1001L,
        2001L,
        BigDecimal.valueOf(100),
        2,
        List.of(3001L)
    );

    ArgumentCaptor<GameLuckyGiftCount> countCaptor = ArgumentCaptor.forClass(GameLuckyGiftCount.class);
    verify(fixture.gameLuckyGiftCountService).save(countCaptor.capture());
    assertEquals(Long.valueOf(0), countCaptor.getValue().getAwardAmount());
    assertEquals(Long.valueOf(200), countCaptor.getValue().getPayAmount());
  }

  @Test
  void run_shouldHandleNullAcceptUserIdWhenAwardIsZero() {
    TestFixture fixture = new TestFixture();
    fixture.mockGiftAndSender();

    GameLuckyGiftParamCmd cmd = fixture.newCmd().setAcceptUserId(null);

    assertDoesNotThrow(() -> fixture.common.run(cmd));
    verify(fixture.luckyGiftSendMetricsService).settle(
        "legacy:9001",
        1001L,
        2001L,
        BigDecimal.valueOf(100),
        2,
        Collections.emptyList()
    );
  }

  private static final class TestFixture {

    private final MessageSenderService senderService = mock(MessageSenderService.class);
    private final ImGroupClient imGroupClient = mock(ImGroupClient.class);
    private final WalletGoldClient walletGoldClient = mock(WalletGoldClient.class);
    private final GiftCacheService giftCacheService = mock(GiftCacheService.class);
    private final EnumConfigService enumConfigService = mock(EnumConfigService.class);
    private final UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
    private final EnumConfigCacheService enumConfigCacheService = mock(EnumConfigCacheService.class);
    private final UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
    private final GameLuckyGiftCountService gameLuckyGiftCountService = mock(GameLuckyGiftCountService.class);
    private final GameLuckyGiftCacheService gameLuckyGiftCacheService = mock(GameLuckyGiftCacheService.class);
    private final LuckyGiftProbabilityService luckyGiftProbabilityService = mock(
        LuckyGiftProbabilityService.class);
    private final GameLuckyGiftRuleConfigService gameLuckyGiftRuleConfigService = mock(
        GameLuckyGiftRuleConfigService.class);
    private final LuckyGiftProbabilityDetailsService luckyGiftProbabilityDetailsService = mock(
        LuckyGiftProbabilityDetailsService.class);
    private final LuckyGiftApiConfig luckyGiftApiConfig = mock(LuckyGiftApiConfig.class);
    private final BaishunRuntimeConfigResolver baishunRuntimeConfigResolver = mock(
        BaishunRuntimeConfigResolver.class);
    private final RankingActivityService rankingActivityService = mock(RankingActivityService.class);
    private final GiftMqMessage giftMqMessage = mock(GiftMqMessage.class);
    private final GiftAppConvertor giftAppConvertor = mock(GiftAppConvertor.class);
    private final ActivityRechargeTicketService activityRechargeTicketService = mock(
        ActivityRechargeTicketService.class);
    private final RoomDailyTaskProgressService roomDailyTaskProgressService = mock(
        RoomDailyTaskProgressService.class);
    private final RoomMemberService roomMemberService = mock(RoomMemberService.class);
    private final RedisService redisService = mock(RedisService.class);
    private final RoomProfileManagerService roomProfileManagerService = mock(
        RoomProfileManagerService.class);
    private final LuckyGiftSendMetricsService luckyGiftSendMetricsService = mock(
        LuckyGiftSendMetricsService.class);

    private final GameLuckyGiftCommon common = new GameLuckyGiftCommon(
        senderService,
        imGroupClient,
        walletGoldClient,
        giftCacheService,
        enumConfigService,
        userProfileGateway,
        enumConfigCacheService,
        userProfileAppConvertor,
        gameLuckyGiftCountService,
        gameLuckyGiftCacheService,
        luckyGiftProbabilityService,
        gameLuckyGiftRuleConfigService,
        luckyGiftProbabilityDetailsService,
        luckyGiftApiConfig,
        baishunRuntimeConfigResolver,
        rankingActivityService,
        giftMqMessage,
        giftAppConvertor,
        activityRechargeTicketService,
        roomDailyTaskProgressService,
        roomMemberService,
        redisService,
        roomProfileManagerService,
        luckyGiftSendMetricsService
    );

    private void mockGiftAndSender() {
      GiftConfigDTO giftConfig = new GiftConfigDTO()
          .setId(11L)
          .setStandardId(99L)
          .setGiftCandy(BigDecimal.valueOf(100))
          .setGiftPhoto("gift.png");
      when(giftCacheService.getById(11L)).thenReturn(giftConfig);

      LuckyGiftInventoryTemplateCache template = new LuckyGiftInventoryTemplateCache()
          .setGiftGiveTotal(0)
          .setComboLoss(0)
          .setCaches(List.of(new GameLuckyGiftInventoryCache().setMultiple(1).setQuantity(1)));
      when(gameLuckyGiftCacheService.getInventoryTemplate(99L, 2)).thenReturn(template);

      UserProfile senderProfile = new UserProfile();
      senderProfile.setId(2001L);
      senderProfile.setAccount("sender001");
      when(userProfileGateway.getByUserId(2001L)).thenReturn(senderProfile);

      UserProfileDTO senderProfileDTO = new UserProfileDTO();
      senderProfileDTO.setId(2001L);
      senderProfileDTO.setAccount("sender001");
      senderProfileDTO.setUserNickname("sender");
      senderProfileDTO.setUserAvatar("sender.png");
      when(userProfileAppConvertor.toUserProfileDTO(senderProfile)).thenReturn(senderProfileDTO);

      LuckyGiftApiConfig.ApiAccount apiAccount = new LuckyGiftApiConfig.ApiAccount();
      apiAccount.setUrl("http://127.0.0.1:1");
      apiAccount.setAppId("test-app");
      apiAccount.setAppChannel("test-channel");
      apiAccount.setAppKey("test-key");
      when(baishunRuntimeConfigResolver.resolveLuckyGiftApiAccount("LIKEI", 99L))
          .thenReturn(apiAccount);
    }

    private GameLuckyGiftParamCmd newCmd() {
      return new GameLuckyGiftParamCmd()
          .setId(9001L)
          .setUserId(2001L)
          .setRoomId(1001L)
          .setRoomAccount("room-account")
          .setSysOrigin("LIKEI")
          .setGiftId(11L)
          .setQuantity(2)
          .setGiftCombos(0)
          .setRegionCode("SA")
          .setGiftsCount(0)
          .setComboLossCount(0)
          .setOpenComboLoss(false)
          .setSysComboLoss(0)
          .setOpenGiftGiveTotal(false)
          .setSysGiftGiveTotal(0)
          .setStandardId(99L);
    }
  }
}
