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

import com.google.common.collect.Lists;
import com.red.circle.other.app.convertor.material.BadgeAppConvertor;
import com.red.circle.other.app.dto.clientobject.material.BadgeConfigCO;
import com.red.circle.other.app.dto.clientobject.material.BadgeGroupTableCO;
import com.red.circle.other.app.dto.clientobject.material.BadgeTableCO;
import com.red.circle.other.app.dto.cmd.material.UserBadgeQueryCmd;
import com.red.circle.other.infra.database.rds.entity.badge.BadgeBackpack;
import com.red.circle.other.infra.database.rds.entity.badge.BadgeConfig;
import com.red.circle.other.infra.database.rds.entity.badge.BadgePictureConfig;
import com.red.circle.other.infra.database.rds.service.badge.BadgeBackpackService;
import com.red.circle.other.infra.database.rds.service.badge.BadgeConfigService;
import com.red.circle.other.infra.database.rds.service.badge.BadgePictureConfigService;
import com.red.circle.other.inner.enums.material.BadgeBackpackExpireType;
import com.red.circle.other.inner.enums.material.BadgeConfigTypeEnum;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.text.StringUtils;

import java.sql.Timestamp;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 用户徽章表格.
 *
 * @author pengliang on 2021/3/12
 */
@Component
@RequiredArgsConstructor
public class UserBadgeTableQryExe {

  private final BadgeAppConvertor badgeAppConvertor;
  private final BadgeConfigService badgeConfigService;
  private final BadgeBackpackService badgeBackpackService;
  private final BadgePictureConfigService badgePictureConfigService;

  public List<BadgeGroupTableCO> execute(UserBadgeQueryCmd cmd) {
    List<BadgeConfig> badgeConfigs = badgeConfigService
        .listBadgeConfig(Objects.isNull(cmd.getType())
            ? BadgeConfigTypeEnum.ACHIEVEMENT : cmd.getType());

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

    Map<Long, BadgeBackpack> badgeBackpackMap = badgeBackpackService
        .mapBadge(cmd.requiredReqUserId(), getSourceId(badgeConfigs));

    Map<Long, BadgePictureConfig> badgePictureConfigMap = badgePictureConfigService
        .mapBadge(cmd.requireReqSysOrigin(), getSourceId(badgeConfigs));

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

    return toBadgeGroupTable(
        badgeConfigs.stream().map(assemblyResult(badgeBackpackMap, badgePictureConfigMap))
            .filter(Objects::nonNull).collect(Collectors.toList()));
  }

  private Set<Long> getSourceId(List<BadgeConfig> badgeConfigs) {
    return badgeConfigs.stream().map(BadgeConfig::getId).collect(Collectors.toSet());
  }

  private List<BadgeGroupTableCO> toBadgeGroupTable(List<BadgeTableCO> badgeTables) {
    return badgeTables.stream()
        .collect(Collectors.groupingBy(badgeTable -> badgeTable.getBadgeConfig().getBadgeKey()))
        .entrySet().stream().map(entry -> new BadgeGroupTableCO()
            .setBadgeKey(entry.getKey())
            .setBadgeTables(orderByAes(entry.getValue()))
        ).sorted(Comparator.comparing(BadgeGroupTableCO::displayBadgeSort))
        .collect(Collectors.toList());
  }

  private List<BadgeTableCO> orderByAes(List<BadgeTableCO> badgeTables) {
    if (CollectionUtils.isEmpty(badgeTables)) {
      return Lists.newArrayList();
    }
    return badgeTables.stream().sorted(Comparator.comparing(
        badgeTable -> badgeTable.getBadgeConfig().getBadgeLevel()
            .longValue())).collect(Collectors.toList());
  }

  private Function<BadgeConfig, BadgeTableCO> assemblyResult(
      Map<Long, BadgeBackpack> badgeBackpackMap,
      Map<Long, BadgePictureConfig> badgePictureConfigMap) {
    return badgeConfig -> {
      BadgePictureConfig badgePictureConfig = badgePictureConfigMap.get(badgeConfig.getId());
      if (Objects.isNull(badgePictureConfig)
          || StringUtils.isBlank(badgePictureConfig.getNotSelectUrl())) {
        return null;
      }
      BadgeConfigCO badgeConfigCO = badgeAppConvertor.toBadgeConfigCO(badgeConfig);
      badgeConfigCO.setAnimationUrl(badgePictureConfig.getAnimationUrl());
      badgeConfigCO.setSelectUrl(badgePictureConfig.getSelectUrl());
      badgeConfigCO.setNotSelectUrl(badgePictureConfig.getNotSelectUrl());
      return new BadgeTableCO()
          .setBadgeConfig(badgeConfigCO)
          .setActivation(Objects.nonNull(badgeBackpackMap.get(badgeConfig.getId())))
          .setExpireTime(getBadgeExpireTime(badgeBackpackMap.get(badgeConfig.getId())));
    };
  }

  private Long getBadgeExpireTime(BadgeBackpack badgeBackpack) {
      if (Objects.isNull(badgeBackpack)) {
          return null;
      }

      return Objects.equals(badgeBackpack.getExpireType(), BadgeBackpackExpireType.PERMANENT.name())
              ? TimestampUtils.nowPlusYear(10).getTime()
              : badgeBackpack.getExpireTime().getTime();

  }

}
