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

import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.other.app.convertor.sys.ActivityAppConvertor;
import com.red.circle.other.app.dto.clientobject.activity.GameWeeklyTaskCO;
import com.red.circle.other.domain.gateway.props.ActivitySourceGroupGateway;
import com.red.circle.other.infra.database.mongo.entity.activity.UserTasksCount;
import com.red.circle.other.infra.database.mongo.entity.sys.GameMatchModelConfig;
import com.red.circle.other.infra.database.mongo.service.activity.UserTasksCountService;
import com.red.circle.other.infra.database.mongo.service.sys.GameMatchModelConfigService;
import com.red.circle.other.infra.enums.task.DailyTaskStorageStatus;
import com.red.circle.other.inner.enums.activity.PropsActivityTypeEnum;
import com.red.circle.other.inner.model.dto.activity.props.ActivityResource;
import com.red.circle.other.inner.model.dto.activity.rule.GameWeeklyTasksContent;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 获取用户每周游戏情况.
 *
 * @author pengliang on 2022/7/14
 */
@Component
@RequiredArgsConstructor
public class GameWeeklyTaskQueryExe {

  private final ActivityAppConvertor activityAppConvertor;
  private final UserTasksCountService userTasksCountService;
  private final GameMatchModelConfigService gameMatchModelConfigService;
  private final ActivitySourceGroupGateway activitySourceGroupGateway;

  public List<GameWeeklyTaskCO> execute(AppExtCommand cmd) {

    List<ActivityResource> activityResources = activitySourceGroupGateway.listActivityResource(
        cmd.requireReqSysOriginEnum(),
        PropsActivityTypeEnum.WEEKLY_GAME_TASKS);

    if (CollectionUtils.isEmpty(activityResources)) {
      return Lists.newArrayList();
    }

    Set<Long> gameConfIds = activityResources.stream().filter(activityResource ->
            Objects.nonNull(activityResource.getRule()))
        .map(rule -> GameWeeklyTasksContent.serializable(rule.getRule().getJsonData()))
        .filter(Objects::nonNull)
        .map(GameWeeklyTasksContent::getGameConfId)
        .collect(Collectors.toSet());

    Map<String, UserTasksCount> userTaskCountMap = userTasksCountService.mapGameMatchWeekly(
        cmd.getReqUserId(),
        gameConfIds.stream().map(String::valueOf).collect(Collectors.toSet()));

    Map<Long, GameMatchModelConfig> configMap = gameMatchModelConfigService.mapByIds(
        gameConfIds);

    return activityResources.stream().map(resource -> {
      if (Objects.isNull(resource.getRule())) {
        return null;
      }
      var content = GameWeeklyTasksContent.serializable(resource.getRule().getJsonData());
      if (Objects.isNull(content)) {
        return null;
      }
      var config = configMap.get(content.getGameConfId());
      if (Objects.isNull(config)) {
        return null;
      }
      var gameUseCount = userTaskCountMap.get(content.getGameConfId().toString());
      long progress = getProgress(gameUseCount, content.getTarget());
      return new GameWeeklyTaskCO()
          .setRuleId(resource.getRule().getId())
          .setGameCode(config.getGameCode())
          .setGameCover(config.getCover())
          .setGameName(config.getName())
          .setTarget(content.getTarget())
          .setProgress(progress)
          .setReward(activityAppConvertor.toActivityPropsGroupCO(resource.getPropsGroup()))
          .setStatus(getStatus(progress, content.getTarget(), gameUseCount));
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }

  private String getStatus(Long progress, Long target, UserTasksCount userTasksCount) {
    if (Objects.isNull(progress) || Objects.isNull(target)) {
      return DailyTaskStorageStatus.UNDONE.name();
    }

    if (Objects.nonNull(userTasksCount) && Objects.equals(userTasksCount.getReceive(),
        Boolean.TRUE)) {
      return DailyTaskStorageStatus.RECEIVED.name();
    }

    if (progress >= target) {
      return DailyTaskStorageStatus.COMPLETED.name();
    }

    return DailyTaskStorageStatus.UNDONE.name();
  }

  private long getProgress(UserTasksCount gameTaskCount, Long target) {
    if (Objects.isNull(gameTaskCount) || Objects.isNull(gameTaskCount.getQuantity())
        || target <= 0) {
      return 0;
    }
    return gameTaskCount.getQuantity() > target ? target : gameTaskCount.getQuantity();
  }

}
