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

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.convertor.material.GiftAppConvertor;
import com.red.circle.other.app.convertor.sys.ActivityAppConvertor;
import com.red.circle.other.app.convertor.sys.SysConfigAppConvertor;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.sys.ActivityConfigRewardsCO;
import com.red.circle.other.app.dto.clientobject.sys.ActivityIndexCO;
import com.red.circle.other.domain.gateway.props.ActivitySourceGroupGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.mongo.dto.ActivityAwardRankUser;
import com.red.circle.other.infra.database.mongo.dto.ActivityConfigRewards;
import com.red.circle.other.infra.database.mongo.entity.sys.ActivityConfig;
import com.red.circle.other.infra.database.mongo.entity.sys.ActivityTemplate;
import com.red.circle.other.infra.database.mongo.service.sys.ActivityConfigService;
import com.red.circle.other.infra.database.mongo.service.sys.ActivityTemplateService;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.inner.model.dto.activity.props.ActivityPropsGroup;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 活动配置-获取.
 *
 * @author pengliang on 2022/8/16
 */
@Component
@RequiredArgsConstructor
public class SysActivityConfQryExe {

  private final GiftAppConvertor giftAppConvertor;
  private final GiftConfigService giftConfigService;
  private final UserProfileGateway userProfileGateway;
  private final ActivityAppConvertor activityAppConvertor;
  private final SysConfigAppConvertor sysConfigAppConvertor;
  private final ActivityConfigService activityConfigService;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final ActivityTemplateService activityTemplateService;
  private final ActivitySourceGroupGateway activitySourceGroupGateway;

  public ActivityIndexCO execute(AppIdLongCmd cmd) {
    ActivityConfig activityConfig = activityConfigService.getById(cmd.getId());
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, activityConfig);
    ActivityTemplate template = activityTemplateService.getById(activityConfig.getTemplateId());
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, template);

    Map<Long, ActivityPropsGroup> activityPropsGroupMap = activitySourceGroupGateway.mapActivityPropsGroup(
        cmd.getReqSysOrigin().getOrigin(), getRewardGroupIds(activityConfig));

    Map<Long, GiftConfig> giftConfigMap = giftConfigService.mapByIds(
        Optional.ofNullable(activityConfig.getGiftIds())
            .map(giftIds -> giftIds.stream().map(Long::parseLong).collect(Collectors.toSet()))
            .orElse(null));

    Map<Long, UserProfileDTO> userProfileMap = userProfileAppConvertor.toMapUserProfileDTO(
        userProfileGateway.mapByUserIds(getAllRewardUserIds(activityConfig)));

    return new ActivityIndexCO().setConfig(sysConfigAppConvertor.toActivityConfigCO(activityConfig))
        .setTemplate(sysConfigAppConvertor.toActivityTemplateCO(template)).setButOneRewards(
            getRewards(activityConfig.getButOneRewards(), activityPropsGroupMap, userProfileMap))
        .setButTwoRewards(
            getRewards(activityConfig.getButTwoRewards(), activityPropsGroupMap, userProfileMap))
        .setCountDown(activityConfig.countDown()).setStatus(activityConfig.status())
        .setActivityGifts(Optional.ofNullable(activityConfig.getGiftIds()).map(
                giftIds -> giftIds.stream().map(giftId -> giftAppConvertor.toGiftConfigDTO(
                    giftConfigMap.get(Long.parseLong(giftId)))).collect(Collectors.toList()))
            .orElseGet(Lists::newArrayList));
  }

  private Set<Long> getAllRewardUserIds(ActivityConfig activityConfig) {
    return Stream.of(getRewardUserIds(activityConfig.getButOneRewards()),
            getRewardUserIds(activityConfig.getButTwoRewards())).flatMap(Collection::stream)
        .collect(Collectors.toSet());
  }

  private List<Long> getRewardUserIds(List<ActivityConfigRewards> confRewards) {
    return Optional.ofNullable(confRewards).map(
        rewards -> rewards.stream().map(ActivityConfigRewards::getRankUsers)
            .filter(CollectionUtils::isNotEmpty).flatMap(Collection::stream)
            .map(ActivityAwardRankUser::getUserId).filter(Objects::nonNull)
            .collect(Collectors.toList())).orElseGet(Lists::newArrayList);
  }

  private List<ActivityConfigRewardsCO> getRewards(List<ActivityConfigRewards> rewardGroup,
      Map<Long, ActivityPropsGroup> activityPropsGroupMap,
      Map<Long, UserProfileDTO> userProfileMap) {

    return Optional.ofNullable(rewardGroup).map(rewards -> rewards.stream().map(
            reward -> new ActivityConfigRewardsCO().setRankRange(reward.getRankRange())
                .setResourceGroupId(reward.getResourceGroupId()).setReward(
                    activityAppConvertor.toActivityPropsGroupCO(
                        activityPropsGroupMap.get(reward.getResourceGroupId()))).setAwardUsers(
                    Optional.ofNullable(reward.getRankUsers()).map(rankUsers -> rankUsers.stream()
                        .map(rankUser -> userProfileMap.get(rankUser.getUserId()))
                        .collect(Collectors.toList())).orElseGet(Lists::newArrayList)))
        .collect(Collectors.toList())).orElseGet(Lists::newArrayList);
  }

  private Set<Long> getRewardGroupIds(ActivityConfig activityConfig) {
    return Stream.of(Optional.ofNullable(activityConfig.getButOneRewards()).map(
            activityConfigRewards -> activityConfigRewards.stream()
                .map(ActivityConfigRewards::getResourceGroupId).collect(Collectors.toSet()))
        .orElse(Sets.newHashSet()), Optional.ofNullable(activityConfig.getButTwoRewards()).map(
            activityConfigRewards -> activityConfigRewards.stream()
                .map(ActivityConfigRewards::getResourceGroupId).collect(Collectors.toSet()))
        .orElse(Sets.newHashSet())).flatMap(Collection::stream).collect(Collectors.toSet());
  }

}
