package com.red.circle.other.app.command.family;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.clientobject.family.FamilyLevelCO;
import com.red.circle.other.app.dto.clientobject.family.FamilyLevelParentCacheCO;
import com.red.circle.other.infra.database.cache.service.other.FamilyLevelCacheService;
import com.red.circle.other.infra.database.rds.entity.badge.BadgePictureConfig;
import com.red.circle.other.infra.database.rds.entity.family.FamilyLevelConfig;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.entity.props.PropsSourceRecord;
import com.red.circle.other.infra.database.rds.service.badge.BadgePictureConfigService;
import com.red.circle.other.infra.database.rds.service.family.FamilyLevelConfigService;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.infra.database.rds.service.props.PropsSourceRecordService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.util.Comparator;
import java.util.HashMap;
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 lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 全部等级配置集合.
 * </p>
 *
 * @author pengshigang
 * @since 2021-07-20
 */
@Component
@RequiredArgsConstructor
public class FamilyLevelListExe {

  private final GiftConfigService giftConfigService;
  private final FamilyLevelCacheService familyLevelCacheService;
  private final PropsSourceRecordService propsSourceRecordService;
  private final FamilyLevelConfigService familyLevelConfigService;
  private final BadgePictureConfigService badgePictureConfigService;

  private final Map<String, Integer> familyLevelSortMapping = new HashMap<>() {{
    put("BLACK_IRON", 0);
    put("BRONZE", 1);
    put("SILVER", 2);
    put("GOLD", 3);
    put("PLATINUM", 4);
  }};

  public List<FamilyLevelParentCacheCO> execute(AppExtCommand cmd) {

    String jsonStr = getCacheFamilyLevelParent(cmd);
    if (StringUtils.isBlank(jsonStr)) {

      List<FamilyLevelParentCacheCO> parents = getLevelCO(getLevelConfigs(cmd), cmd);
      familyLevelCache(cmd, parents);
      return parents;
    }
    return Optional
        .ofNullable(JacksonUtils
            .readValue(jsonStr, new TypeReference<List<FamilyLevelParentCacheCO>>() {
            }))
        .orElse(Lists.newArrayList());
  }

  private String getCacheFamilyLevelParent(AppExtCommand cmd) {
    return familyLevelCacheService.getFamilyLevelParent(cmd.getReqSysOrigin().getOrigin());
  }

  private void familyLevelCache(AppExtCommand cmd, List<FamilyLevelParentCacheCO> parents) {
    familyLevelCacheService.setFamilyLevelParent(
        cmd.getReqSysOrigin().getOrigin(), JacksonUtils.toJson(parents));
  }

  private List<FamilyLevelParentCacheCO> getLevelCO(List<FamilyLevelConfig> levelConfigs,
      AppExtCommand cmd) {

    Map<Long, PropsSourceRecord> mapProp = mapProp(levelConfigs);
    Map<Long, GiftConfig> mapGift = mapGift(levelConfigs);
    Map<Long, BadgePictureConfig> mapBadge = mapBadge(cmd.getReqSysOrigin().getOrigin(),
        levelConfigs);

    List<FamilyLevelCO> levelList = levelConfigs.stream().map(
        familyLevelConfig -> setFamilyLevelCO(mapProp, mapBadge, mapGift, familyLevelConfig,
            getBuild(familyLevelConfig))).collect(Collectors.toList());

    if (CollectionUtils.isEmpty(levelList)) {
      return Lists.newArrayList();
    }
    List<FamilyLevelParentCacheCO> levelParents = Lists.newArrayList();

    getStringListMap(levelList).forEach((k, list) ->
        levelParents.add(new FamilyLevelParentCacheCO()
            .setLevelType(k)
            .setSort(Optional.ofNullable(familyLevelSortMapping.get(k)).orElse(1000))
            .setLevel(list)
        )
    );

    return levelParents.stream().sorted(Comparator.comparing(FamilyLevelParentCacheCO::getSort))
        .collect(Collectors.toList());
  }

  private Map<String, List<FamilyLevelCO>> getStringListMap(List<FamilyLevelCO> levelList) {
    return levelList.stream().collect(Collectors.groupingBy(FamilyLevelCO::getLevelType));
  }

  private FamilyLevelCO setFamilyLevelCO(Map<Long, PropsSourceRecord> mapProp,
      Map<Long, BadgePictureConfig> mapBadge,
      Map<Long, GiftConfig> mapGift,
      FamilyLevelConfig familyLevelConfig, FamilyLevelCO levelCO) {

    PropsSourceRecord avatarFrame = mapProp.get(familyLevelConfig.getAvatarFrameId());
    BadgePictureConfig badge = mapBadge.get(familyLevelConfig.getBadgeId());
    GiftConfig gift = mapGift.get(familyLevelConfig.getGiftId());

    levelCO.setLevelType(familyLevelConfig.getLevelType());

    if (Objects.nonNull(avatarFrame)) {
      levelCO.setAvatarFrameCover(avatarFrame.getCover());
      levelCO.setAvatarFrameSvg(avatarFrame.getSourceUrl());
    }

    if (Objects.nonNull(badge)) {
      levelCO.setBadgeCover(badge.getSelectUrl());
      levelCO.setBadgeSvg(badge.getAnimationUrl());
    }

    if (Objects.nonNull(gift)) {
      levelCO.setGiftCover(gift.getGiftPhoto());
      levelCO.setGiftSvg(gift.getGiftSourceUrl());
    }
    levelCO.setSort(familyLevelConfig.getSort());
    return levelCO;
  }

  private List<FamilyLevelConfig> getLevelConfigs(AppExtCommand cmd) {

    List<FamilyLevelConfig> levelConfigs = familyLevelConfigService
        .listLevelConfig(cmd.getReqSysOrigin().getOrigin());

    ResponseAssert.isFalse(CommonErrorCode.NOT_FOUND_RECORD_INFO,
        CollectionUtils.isEmpty(levelConfigs));

    return levelConfigs;

  }


  private Map<Long, GiftConfig> mapGift(List<FamilyLevelConfig> levelConfigs) {
    if (CollectionUtils.isEmpty(levelConfigs)) {
      return Maps.newHashMap();
    }
    return giftConfigService.mapByIds(getGiftIds(levelConfigs));
  }

  private Set<Long> getGiftIds(List<FamilyLevelConfig> levelConfigs) {
    return levelConfigs.stream().map(FamilyLevelConfig::getGiftId).collect(Collectors.toSet());
  }

  private Map<Long, PropsSourceRecord> mapProp(List<FamilyLevelConfig> levelConfigs) {

    if (CollectionUtils.isEmpty(levelConfigs)) {
      return Maps.newHashMap();
    }
    return propsSourceRecordService
        .mapByIds(levelConfigs.stream().map(FamilyLevelConfig::getAvatarFrameId).collect(
            Collectors.toSet()));
  }

  private Map<Long, BadgePictureConfig> mapBadge(String sysOrigin,
      List<FamilyLevelConfig> levelConfigs) {

    if (CollectionUtils.isEmpty(levelConfigs)) {
      return Maps.newHashMap();
    }
    return badgePictureConfigService
        .mapBadge(sysOrigin, levelConfigs.stream().map(FamilyLevelConfig::getBadgeId).collect(
            Collectors.toSet()));
  }

  private FamilyLevelCO getBuild(FamilyLevelConfig familyLevelConfig) {
    return new FamilyLevelCO()
        .setLevelKey(familyLevelConfig.getLevelKey())
        .setLevelExp(familyLevelConfig.getLevelExp())
        .setMaxMember(familyLevelConfig.getMaxMember())
        .setMaxManager(familyLevelConfig.getMaxManager())
        .setLevelBackgroundPicture(familyLevelConfig.getLevelBackgroundPicture());
  }

}
