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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.red.circle.other.app.convertor.live.RoomProfileAppConvertor;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.family.RoomSettingCO;
import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
import com.red.circle.other.infra.database.mongo.entity.live.RoomCounter;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
import com.red.circle.other.infra.database.mongo.entity.live.RoomSetting;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.inner.enums.room.RoomEventEnum;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;

class RoomVoiceProfileCommonTest {

  @Test
  void toListRoomVoiceProfileCO_shouldUseActiveVoiceRoomOnlineQuantityAsMemberQuantity() {
    UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
    UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
    RoomProfileAppConvertor roomProfileAppConvertor = mock(RoomProfileAppConvertor.class);
    RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
    RoomVoiceProfileCommon roomVoiceProfileCommon = new RoomVoiceProfileCommon(
        userProfileGateway,
        userProfileAppConvertor,
        roomProfileAppConvertor,
        roomProfileManagerService
    );

    ActiveVoiceRoom activeVoiceRoom = new ActiveVoiceRoom()
        .setId(10001L)
        .setUserId(20001L)
        .setOnlineQuantity(6L)
        .setFixedWeights(88)
        .setSuperVipLevel("NONE");

    RoomProfileManager roomProfileManager = new RoomProfileManager();
    roomProfileManager.setId(10001L);
    roomProfileManager.setUserId(20001L);
    roomProfileManager.setDel(Boolean.FALSE);
    roomProfileManager.setEvent(RoomEventEnum.AVAILABLE.name());
    roomProfileManager.setSetting(RoomSetting.createDefaultRoomSetting());
    roomProfileManager.setCounter(new RoomCounter().setMemberCount(1).setAdminCount(0));

    UserProfileDTO userProfileDTO = new UserProfileDTO();
    userProfileDTO.setId(20001L);

    RoomVoiceProfileCO convertedProfile = new RoomVoiceProfileCO()
        .setId(10001L)
        .setUserId(20001L);

    when(roomProfileManagerService.mapByRoomIds(java.util.Set.of(10001L)))
        .thenReturn(Map.of(10001L, roomProfileManager));
    when(userProfileGateway.mapByUserIds(java.util.Set.of(20001L)))
        .thenReturn(Map.of());
    when(userProfileAppConvertor.toMapUserProfileDTO(anyMap()))
        .thenReturn(Map.of(20001L, userProfileDTO));
    when(roomProfileAppConvertor.toRoomVoiceProfileCO(roomProfileManager))
        .thenReturn(convertedProfile);
    when(roomProfileAppConvertor.toRoomSettingCO(roomProfileManager.getSetting()))
        .thenReturn(new RoomSettingCO());

    List<RoomVoiceProfileCO> roomProfiles = roomVoiceProfileCommon.toListRoomVoiceProfileCO(
        List.of(activeVoiceRoom));

    assertEquals(1, roomProfiles.size());
    assertEquals("6", getExtValue(roomProfiles.get(0), "memberQuantity"));
    assertEquals(88, getExtValue(roomProfiles.get(0), "fixedWeights"));
  }

  private Object getExtValue(RoomVoiceProfileCO roomVoiceProfileCO, String key) {
    Map<?, ?> extValues = findExtValues(roomVoiceProfileCO);
    assertNotNull(extValues, "extValues should exist on RoomVoiceProfileCO");
    return extValues.get(key);
  }

  private Map<?, ?> findExtValues(Object target) {
    Class<?> current = target.getClass();
    while (current != null) {
      try {
        Field field = current.getDeclaredField("extValues");
        field.setAccessible(true);
        Object value = field.get(target);
        if (value instanceof Map<?, ?> extValues) {
          return extValues;
        }
        return null;
      } catch (NoSuchFieldException ignored) {
        current = current.getSuperclass();
      } catch (IllegalAccessException e) {
        throw new IllegalStateException("read extValues failed", e);
      }
    }
    return null;
  }
}
