package com.red.circle.other.app.command.room.query;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anySet;
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.dto.cmd.AppExtCommand;
import com.red.circle.common.business.enums.SVIPLevelEnum;
import com.red.circle.framework.core.dto.ReqSysOrigin;
import com.red.circle.live.inner.endpoint.LiveMicClient;
import com.red.circle.other.app.common.room.RoomRegionFilterCommon;
import com.red.circle.other.app.common.room.RoomVoiceProfileCommon;
import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO;
import com.red.circle.other.app.service.game.GameLudoService;
import com.red.circle.other.app.service.room.RocketStatusCacheService;
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.gateway.user.ability.UserSVipGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.domain.model.user.ability.RegionConfig;
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
import com.red.circle.other.infra.database.cache.service.user.RegionRoomCacheService;
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.live.RoomUserBlacklistService;
import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.data.redis.core.RedisTemplate;

class RoomVoiceDiscoverQryExeTest {

  private static final long ALL_REGION_WHITE_USER_ID = 2044700023064686594L;

  @Test
  void execute_shouldIgnoreAllRegionAndOnlyReturnCurrentRegionRooms() {
    UserSVipGateway userSVipGateway = mock(UserSVipGateway.class);
    UserRegionGateway userRegionGateway = mock(UserRegionGateway.class);
    RoomRegionFilterCommon roomRegionFilterCommon = mock(RoomRegionFilterCommon.class);
    RoomVoiceProfileCommon roomVoiceProfileCommon = mock(RoomVoiceProfileCommon.class);
    ActiveVoiceRoomService activeVoiceRoomService = mock(ActiveVoiceRoomService.class);
    RoomUserBlacklistService roomUserBlacklistService = mock(RoomUserBlacklistService.class);
    LatestMobileDeviceService latestMobileDeviceService = mock(LatestMobileDeviceService.class);
    RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
    RegionRoomCacheService regionRoomCacheService = mock(RegionRoomCacheService.class);
    LiveMicClient liveMicClient = mock(LiveMicClient.class);
    RedisTemplate<String, Object> redisTemplate = mock(RedisTemplate.class);
    RocketStatusCacheService rocketStatusCacheService = mock(RocketStatusCacheService.class);
    GameLudoService gameLudoService = mock(GameLudoService.class);
    UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
    CountryCodeAliasSupport countryCodeAliasSupport = mock(CountryCodeAliasSupport.class);
    RoomVoiceDiscoverQryExe exe = new RoomVoiceDiscoverQryExe(
        userSVipGateway,
        userRegionGateway,
        roomRegionFilterCommon,
        roomVoiceProfileCommon,
        activeVoiceRoomService,
        roomUserBlacklistService,
        latestMobileDeviceService,
        roomProfileManagerService,
        regionRoomCacheService,
        liveMicClient,
        redisTemplate,
        rocketStatusCacheService,
        gameLudoService,
        userProfileGateway,
        countryCodeAliasSupport
    );

    AppExtCommand cmd = new AppExtCommand();
    cmd.setReqUserId(1L);
    cmd.setReqSysOrigin(ReqSysOrigin.of("YOLO", "YOLO"));
    cmd.setAllRegion(true);

    RegionConfig currentRegion = new RegionConfig().setRegionCode("AE").setCountryCodes("AE,SA");
    UserProfile userProfile = new UserProfile();
    ActiveVoiceRoom activeVoiceRoom = new ActiveVoiceRoom().setId(101L).setUserId(201L);
    RoomProfileManager fallbackRoomManager = new RoomProfileManager();
    fallbackRoomManager.setId(102L);
    fallbackRoomManager.setUserId(202L);

    RoomVoiceProfileCO activeRoomCo = new RoomVoiceProfileCO().setId(101L).setUserId(201L)
        .putRoomMemberQuantity(0);
    RoomVoiceProfileCO fallbackRoomCo = new RoomVoiceProfileCO().setId(102L).setUserId(202L)
        .putRoomMemberQuantity(2);

    when(roomRegionFilterCommon.requireRegionConfig(1L)).thenReturn(currentRegion);
    when(userProfileGateway.getByUserId(1L)).thenReturn(userProfile);
    when(regionRoomCacheService.getRegionsRoom("YOLOAE")).thenReturn(null);
    when(activeVoiceRoomService.listByRegion("YOLO", "AE", 50)).thenReturn(List.of(activeVoiceRoom));
    when(roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(List.of(activeVoiceRoom), "AE"))
        .thenReturn(List.of(activeVoiceRoom));
    when(redisTemplate.keys("empty_room_cache:*")).thenReturn(Set.of());
    when(roomVoiceProfileCommon.toListRoomVoiceProfileCO(List.of(activeVoiceRoom))).thenReturn(
        List.of(activeRoomCo)
    );
    when(roomRegionFilterCommon.listCountryCodes(currentRegion)).thenReturn(List.of("AE", "SA"));
    when(roomProfileManagerService.listSelectiveLimitByCountryCodes(
        "YOLO", List.of("AE", "SA"), List.of(101L), 50
    )).thenReturn(List.of(fallbackRoomManager));
    when(roomRegionFilterCommon.filterRoomProfileManagersByRegion(
        List.of(fallbackRoomManager), "AE"
    )).thenReturn(List.of(fallbackRoomManager));
    when(roomVoiceProfileCommon.listRoomVoiceProfilesV2(List.of(fallbackRoomManager))).thenReturn(
        List.of(fallbackRoomCo)
    );
    when(userSVipGateway.checkSVipIdentity(anySet())).thenReturn(
        Map.of(201L, SVIPLevelEnum.NONE, 202L, SVIPLevelEnum.NONE)
    );
    when(rocketStatusCacheService.batchGetRocketStatus(List.of(102L, 101L))).thenReturn(Map.of());
    when(gameLudoService.listGameCoverByRoomIds(List.of(102L, 101L))).thenReturn(Map.of());

    List<RoomVoiceProfileCO> roomList = exe.execute(cmd);

    assertEquals(List.of(fallbackRoomCo, activeRoomCo), roomList);
    verify(activeVoiceRoomService).listByRegion("YOLO", "AE", 50);
    verify(activeVoiceRoomService, never()).listDiscover("YOLO", true, "AE", null, 50);
  }

  @Test
  void execute_shouldKeepTopRoomBeforeHigherMemberRoom() {
    UserSVipGateway userSVipGateway = mock(UserSVipGateway.class);
    UserRegionGateway userRegionGateway = mock(UserRegionGateway.class);
    RoomRegionFilterCommon roomRegionFilterCommon = mock(RoomRegionFilterCommon.class);
    RoomVoiceProfileCommon roomVoiceProfileCommon = mock(RoomVoiceProfileCommon.class);
    ActiveVoiceRoomService activeVoiceRoomService = mock(ActiveVoiceRoomService.class);
    RoomUserBlacklistService roomUserBlacklistService = mock(RoomUserBlacklistService.class);
    LatestMobileDeviceService latestMobileDeviceService = mock(LatestMobileDeviceService.class);
    RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
    RegionRoomCacheService regionRoomCacheService = mock(RegionRoomCacheService.class);
    LiveMicClient liveMicClient = mock(LiveMicClient.class);
    RedisTemplate<String, Object> redisTemplate = mock(RedisTemplate.class);
    RocketStatusCacheService rocketStatusCacheService = mock(RocketStatusCacheService.class);
    GameLudoService gameLudoService = mock(GameLudoService.class);
    UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
    CountryCodeAliasSupport countryCodeAliasSupport = mock(CountryCodeAliasSupport.class);
    RoomVoiceDiscoverQryExe exe = new RoomVoiceDiscoverQryExe(
        userSVipGateway,
        userRegionGateway,
        roomRegionFilterCommon,
        roomVoiceProfileCommon,
        activeVoiceRoomService,
        roomUserBlacklistService,
        latestMobileDeviceService,
        roomProfileManagerService,
        regionRoomCacheService,
        liveMicClient,
        redisTemplate,
        rocketStatusCacheService,
        gameLudoService,
        userProfileGateway,
        countryCodeAliasSupport
    );

    AppExtCommand cmd = new AppExtCommand();
    cmd.setReqUserId(1L);
    cmd.setReqSysOrigin(ReqSysOrigin.of("YOLO", "YOLO"));

    RegionConfig currentRegion = new RegionConfig().setRegionCode("AE").setCountryCodes("AE,SA");
    UserProfile userProfile = new UserProfile();
    ActiveVoiceRoom activeVoiceRoom = new ActiveVoiceRoom().setId(101L).setUserId(201L);
    RoomProfileManager fallbackRoomManager = new RoomProfileManager();
    fallbackRoomManager.setId(102L);
    fallbackRoomManager.setUserId(202L);

    RoomVoiceProfileCO topRoomCo = new RoomVoiceProfileCO().setId(101L).setUserId(201L)
        .putRoomMemberQuantity(0)
        .putFixedWeights(100);
    RoomVoiceProfileCO fallbackRoomCo = new RoomVoiceProfileCO().setId(102L).setUserId(202L)
        .putRoomMemberQuantity(2);

    when(roomRegionFilterCommon.requireRegionConfig(1L)).thenReturn(currentRegion);
    when(userProfileGateway.getByUserId(1L)).thenReturn(userProfile);
    when(regionRoomCacheService.getRegionsRoom("YOLOAE")).thenReturn(null);
    when(activeVoiceRoomService.listByRegion("YOLO", "AE", 50)).thenReturn(List.of(activeVoiceRoom));
    when(roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(List.of(activeVoiceRoom), "AE"))
        .thenReturn(List.of(activeVoiceRoom));
    when(roomVoiceProfileCommon.toListRoomVoiceProfileCO(List.of(activeVoiceRoom))).thenReturn(
        List.of(topRoomCo)
    );
    when(roomRegionFilterCommon.listCountryCodes(currentRegion)).thenReturn(List.of("AE", "SA"));
    when(roomProfileManagerService.listSelectiveLimitByCountryCodes(
        "YOLO", List.of("AE", "SA"), List.of(101L), 50
    )).thenReturn(List.of(fallbackRoomManager));
    when(roomRegionFilterCommon.filterRoomProfileManagersByRegion(
        List.of(fallbackRoomManager), "AE"
    )).thenReturn(List.of(fallbackRoomManager));
    when(roomVoiceProfileCommon.listRoomVoiceProfilesV2(List.of(fallbackRoomManager))).thenReturn(
        List.of(fallbackRoomCo)
    );
    when(userSVipGateway.checkSVipIdentity(anySet())).thenReturn(
        Map.of(201L, SVIPLevelEnum.NONE, 202L, SVIPLevelEnum.NONE)
    );
    when(rocketStatusCacheService.batchGetRocketStatus(List.of(101L, 102L))).thenReturn(Map.of());
    when(gameLudoService.listGameCoverByRoomIds(List.of(101L, 102L))).thenReturn(Map.of());

    List<RoomVoiceProfileCO> roomList = exe.execute(cmd);

    assertEquals(List.of(topRoomCo, fallbackRoomCo), roomList);
  }

  @Test
  void execute_shouldReturnAllRegionRoomsForWhiteListUser() {
    UserSVipGateway userSVipGateway = mock(UserSVipGateway.class);
    UserRegionGateway userRegionGateway = mock(UserRegionGateway.class);
    RoomRegionFilterCommon roomRegionFilterCommon = mock(RoomRegionFilterCommon.class);
    RoomVoiceProfileCommon roomVoiceProfileCommon = mock(RoomVoiceProfileCommon.class);
    ActiveVoiceRoomService activeVoiceRoomService = mock(ActiveVoiceRoomService.class);
    RoomUserBlacklistService roomUserBlacklistService = mock(RoomUserBlacklistService.class);
    LatestMobileDeviceService latestMobileDeviceService = mock(LatestMobileDeviceService.class);
    RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
    RegionRoomCacheService regionRoomCacheService = mock(RegionRoomCacheService.class);
    LiveMicClient liveMicClient = mock(LiveMicClient.class);
    RedisTemplate<String, Object> redisTemplate = mock(RedisTemplate.class);
    RocketStatusCacheService rocketStatusCacheService = mock(RocketStatusCacheService.class);
    GameLudoService gameLudoService = mock(GameLudoService.class);
    UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
    CountryCodeAliasSupport countryCodeAliasSupport = mock(CountryCodeAliasSupport.class);
    RoomVoiceDiscoverQryExe exe = new RoomVoiceDiscoverQryExe(
        userSVipGateway,
        userRegionGateway,
        roomRegionFilterCommon,
        roomVoiceProfileCommon,
        activeVoiceRoomService,
        roomUserBlacklistService,
        latestMobileDeviceService,
        roomProfileManagerService,
        regionRoomCacheService,
        liveMicClient,
        redisTemplate,
        rocketStatusCacheService,
        gameLudoService,
        userProfileGateway,
        countryCodeAliasSupport
    );

    AppExtCommand cmd = new AppExtCommand();
    cmd.setReqUserId(ALL_REGION_WHITE_USER_ID);
    cmd.setReqSysOrigin(ReqSysOrigin.of("YOLO", "YOLO"));

    RegionConfig currentRegion = new RegionConfig().setRegionCode("AE").setCountryCodes("AE,SA");
    UserProfile userProfile = new UserProfile();
    userProfile.setCountryCode("AE");
    ActiveVoiceRoom activeVoiceRoom = new ActiveVoiceRoom().setId(101L).setUserId(201L);
    RoomProfileManager fallbackRoomManager = new RoomProfileManager();
    fallbackRoomManager.setId(102L);
    fallbackRoomManager.setUserId(202L);

    RoomVoiceProfileCO activeRoomCo = new RoomVoiceProfileCO().setId(101L).setUserId(201L);
    RoomVoiceProfileCO fallbackRoomCo = new RoomVoiceProfileCO().setId(102L).setUserId(202L);

    when(roomRegionFilterCommon.canViewAllRegions(ALL_REGION_WHITE_USER_ID)).thenReturn(true);
    when(roomRegionFilterCommon.requireRegionConfig(ALL_REGION_WHITE_USER_ID)).thenReturn(currentRegion);
    when(userProfileGateway.getByUserId(ALL_REGION_WHITE_USER_ID)).thenReturn(userProfile);
    when(regionRoomCacheService.getRegionsRoom("YOLOAE:ALL_REGION")).thenReturn(null);
    when(activeVoiceRoomService.listDiscover("YOLO", true, "AE", "AE", 50))
        .thenReturn(List.of(activeVoiceRoom));
    when(redisTemplate.keys("empty_room_cache:*")).thenReturn(Set.of());
    when(roomVoiceProfileCommon.toListRoomVoiceProfileCO(List.of(activeVoiceRoom))).thenReturn(
        List.of(activeRoomCo)
    );
    when(roomProfileManagerService.listSelectiveLimitByCountryCodes(
        "YOLO", List.of(), List.of(101L), 50
    )).thenReturn(List.of(fallbackRoomManager));
    when(roomVoiceProfileCommon.listRoomVoiceProfilesV2(List.of(fallbackRoomManager))).thenReturn(
        List.of(fallbackRoomCo)
    );
    when(userSVipGateway.checkSVipIdentity(anySet())).thenReturn(
        Map.of(201L, SVIPLevelEnum.NONE, 202L, SVIPLevelEnum.NONE)
    );
    when(rocketStatusCacheService.batchGetRocketStatus(List.of(101L, 102L))).thenReturn(Map.of());
    when(gameLudoService.listGameCoverByRoomIds(List.of(101L, 102L))).thenReturn(Map.of());

    List<RoomVoiceProfileCO> roomList = exe.execute(cmd);

    assertEquals(List.of(activeRoomCo, fallbackRoomCo), roomList);
    verify(activeVoiceRoomService, never()).listByRegion("YOLO", "AE", 50);
    verify(roomRegionFilterCommon, never()).filterActiveVoiceRoomsByRegion(List.of(activeVoiceRoom), "AE");
    verify(roomRegionFilterCommon, never()).filterRoomProfileManagersByRegion(List.of(fallbackRoomManager), "AE");
  }
}
