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

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.component.redis.service.RedisService;
import com.red.circle.other.domain.enums.VipBenefitType;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.ability.RegionConfig;
import com.red.circle.other.infra.common.team.TeamTargetCommon;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.rds.service.user.user.ConsumptionLevelService;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class LuckyGiftSendMetricsServiceTest {

  private static final long ROOM_ID = 1001L;
  private static final long SEND_USER_ID = 2001L;
  private static final long ACCEPT_ANCHOR_ID = 3001L;
  private static final long ACCEPT_OTHER_ANCHOR_ID = 3002L;

  private RedisService redisService;
  private TeamTargetCommon teamTargetCommon;
  private TeamMemberService teamMemberService;
  private UserRegionGateway userRegionGateway;
  private UserProfileGateway userProfileGateway;
  private ConsumptionLevelService consumptionLevelService;
  private RoomProfileManagerService roomProfileManagerService;
  private LuckyGiftSendMetricsService service;

  @BeforeEach
  void setUp() {
    redisService = mock(RedisService.class);
    teamTargetCommon = mock(TeamTargetCommon.class);
    teamMemberService = mock(TeamMemberService.class);
    userRegionGateway = mock(UserRegionGateway.class);
    userProfileGateway = mock(UserProfileGateway.class);
    consumptionLevelService = mock(ConsumptionLevelService.class);
    roomProfileManagerService = mock(RoomProfileManagerService.class);
    service = new LuckyGiftSendMetricsService(
        redisService,
        teamTargetCommon,
        teamMemberService,
        userRegionGateway,
        userProfileGateway,
        consumptionLevelService,
        roomProfileManagerService
    );
  }

  @Test
  void settle_shouldAddRoomValueCharmAndHostPointsWithTenPercent() {
    when(redisService.setIfAbsent("lucky_gift:send:metrics:processed:biz-1", "1", 7,
        TimeUnit.DAYS)).thenReturn(true);

    RoomProfile roomProfile = new RoomProfile();
    roomProfile.setId(ROOM_ID);
    roomProfile.setUserId(SEND_USER_ID);
    when(roomProfileManagerService.getProfileById(ROOM_ID)).thenReturn(roomProfile);
    when(teamMemberService.getByMemberId(SEND_USER_ID)).thenReturn(new TeamMember());
    when(teamMemberService.listMemberIds(Set.of(ACCEPT_ANCHOR_ID, ACCEPT_OTHER_ANCHOR_ID)))
        .thenReturn(List.of(ACCEPT_ANCHOR_ID, ACCEPT_OTHER_ANCHOR_ID));

    when(userProfileGateway.getUserVipBenefit(ACCEPT_ANCHOR_ID, VipBenefitType.XP_RATE))
        .thenReturn(new BigDecimal("1.25"));
    when(userProfileGateway.getUserVipBenefit(ACCEPT_OTHER_ANCHOR_ID, VipBenefitType.XP_RATE))
        .thenReturn(BigDecimal.ONE);

    RegionConfig sendRegion = new RegionConfig().setRegionCode("SA");
    RegionConfig sameRegion = new RegionConfig().setRegionCode("SA");
    RegionConfig diffRegion = new RegionConfig().setRegionCode("PK");
    when(userRegionGateway.getRegionConfigByUserId(SEND_USER_ID)).thenReturn(sendRegion);
    when(userRegionGateway.getRegionConfigByUserId(ACCEPT_ANCHOR_ID)).thenReturn(sameRegion);
    when(userRegionGateway.getRegionConfigByUserId(ACCEPT_OTHER_ANCHOR_ID)).thenReturn(diffRegion);
    when(userRegionGateway.checkBusinessRegionCode("SA", "SA")).thenReturn(true);
    when(userRegionGateway.checkBusinessRegionCode("SA", "PK")).thenReturn(false);

    service.settle(
        "biz-1",
        ROOM_ID,
        SEND_USER_ID,
        BigDecimal.valueOf(100),
        2,
        List.of(ACCEPT_ANCHOR_ID, ACCEPT_OTHER_ANCHOR_ID)
    );

    verify(teamTargetCommon).incrementRoomValue(SEND_USER_ID, BigDecimal.valueOf(40));
    verify(consumptionLevelService).incrConsumptionDiamond(ACCEPT_ANCHOR_ID,
        BigDecimal.valueOf(25));
    verify(consumptionLevelService).incrConsumptionDiamond(ACCEPT_OTHER_ANCHOR_ID,
        BigDecimal.valueOf(20));
    verify(teamTargetCommon).incrementGiftValue(ACCEPT_ANCHOR_ID, BigDecimal.valueOf(20));
    verify(teamTargetCommon, never()).incrementGiftValue(ACCEPT_OTHER_ANCHOR_ID,
        BigDecimal.valueOf(20));
  }

  @Test
  void settle_shouldSkipWhenAlreadyProcessed() {
    when(redisService.setIfAbsent("lucky_gift:send:metrics:processed:biz-2", "1", 7,
        TimeUnit.DAYS)).thenReturn(false);

    service.settle(
        "biz-2",
        ROOM_ID,
        SEND_USER_ID,
        BigDecimal.valueOf(100),
        1,
        List.of(ACCEPT_ANCHOR_ID)
    );

    verify(teamTargetCommon, never()).incrementRoomValue(SEND_USER_ID, BigDecimal.TEN);
    verify(consumptionLevelService, never()).incrConsumptionDiamond(ACCEPT_ANCHOR_ID,
        BigDecimal.TEN);
    verify(teamTargetCommon, never()).incrementGiftValue(ACCEPT_ANCHOR_ID, BigDecimal.TEN);
  }
}
