package com.red.circle.other.app.inner.service.material.props.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.red.circle.common.business.enums.PropsActivityRewardEnum;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.inner.convertor.material.PropsInnerConvertor;
import com.red.circle.other.app.inner.service.material.props.PropsActivityRewardGroupClientService;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardConfig;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardGroup;
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.entity.emoji.EmojiGroup;
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.activity.PropsActivityRewardConfigService;
import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRewardGroupService;
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.infra.database.rds.service.emoji.EmojiGroupService;
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.other.inner.model.cmd.material.PropsActivityRewardGroupParamCmd;
import com.red.circle.other.inner.model.cmd.material.PropsActivityRewardGroupQryCmd;
import com.red.circle.other.inner.model.dto.material.ActivityGroupKeyValueDTO;
import com.red.circle.other.inner.model.dto.material.PropsActivityRewardConfigInfoDTO;
import com.red.circle.other.inner.model.dto.material.PropsActivityRewardGroupDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.parse.DataTypeUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 道具活动配置分组
 *
 * @author zongpubin on 2023/10/23
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PropsActivityRewardGroupClientServiceImpl implements
    PropsActivityRewardGroupClientService {

  private final EmojiGroupService emojiGroupService;
  private final GiftConfigService giftConfigService;
  private final BadgeConfigService badgeConfigService;
  private final PropsInnerConvertor propsInnerConvertor;
  private final PropsSourceRecordService propsSourceRecordService;
  private final BadgePictureConfigService badgePictureConfigService;
  private final PropsActivityRewardGroupService propsActivityRewardGroupService;
  private final PropsActivityRewardConfigService propsActivityRewardConfigService;

  @Override
  public PageResult<PropsActivityRewardGroupDTO> pagePropsActivityRewardGroup(PropsActivityRewardGroupQryCmd query) {

    PageResult<PropsActivityRewardGroup> rewardGroupPageResult = propsActivityRewardGroupService.pagePropsActivityRewardGroup(query);

    PageResult<PropsActivityRewardGroupDTO> pageResult = rewardGroupPageResult.convert(propsInnerConvertor::toPropsActivityRewardGroupDTO);

    if (CollectionUtils.isEmpty(pageResult.getRecords())) {
      return pageResult;
    }

    Map<Long, List<PropsActivityRewardConfigInfoDTO>> configMap = mapPropsActivityRewardConfig(
        query.getSysOrigin(), pageResult.getRecords().stream().toList());

    return pageResult.convert(group -> {
      group.setRewardConfigList(configMap.get(group.getId()));
      return group;
    });
  }

  @Override
  public PropsActivityRewardGroupDTO getByGroupId(Long id) {
    PropsActivityRewardGroup group = propsActivityRewardGroupService.getById(id);
    if (Objects.isNull(group)) {
      return new PropsActivityRewardGroupDTO();
    }

    List<PropsActivityRewardConfigInfoDTO> propsActivityRewards = listGroupDTO(
        List.of(group.getId()));

    if (CollectionUtils.isEmpty(propsActivityRewards)) {
      return new PropsActivityRewardGroupDTO();
    }

    Map<Long, BadgePictureConfig> badgePictureMap = badgePictureConfigService
        .mapBadge(group.getSysOrigin(), getBadgeContentList(propsActivityRewards));

    handlePropsAssemble(propsActivityRewards, badgePictureMap);

    PropsActivityRewardGroupDTO groupDTO = propsInnerConvertor.toPropsActivityRewardGroupDTO(group);
    groupDTO.setRewardConfigList(propsActivityRewards);
    return groupDTO;
  }

  @Override
  public String saveOrUpdate(PropsActivityRewardGroupParamCmd rewardGroupParam) {
    Long groupId = saveOrUpdateGroup(rewardGroupParam);
    propsActivityRewardConfigService.deleteByGroupId(groupId);
    propsActivityRewardConfigService
        .saveBatch(rewardGroupParam.getRewardConfigList().stream().map(config -> {
          PropsActivityRewardConfig rewardConfig = propsInnerConvertor.toPropsActivityRewardConfig(
              config);
          rewardConfig
              .setQuantity(Objects.nonNull(config.getQuantity()) ? config.getQuantity() : 0);
          rewardConfig.setGroupId(groupId);
          rewardConfig.setDetailType(config.getDetailType());
          rewardConfig.setCreateTime(TimestampUtils.now());
          rewardConfig.setUpdateTime(TimestampUtils.now());
          return rewardConfig;
        }).collect(Collectors.toList()));
    return groupId.toString();
  }

  @Override
  public void offShelf(Long id, Boolean offShelf) {
    propsActivityRewardGroupService.offShelf(id, offShelf);
  }

  @Override
  public List<ActivityGroupKeyValueDTO> getActivityGroupKeyValueList() {
    return propsActivityRewardGroupService.getActivityGroupKeyValueList();
  }

  private Long saveOrUpdateGroup(PropsActivityRewardGroupParamCmd rewardGroupParam) {
    return Objects.isNull(rewardGroupParam.getId()) ? addRewardGroup(rewardGroupParam)
        : updateRewardGroup(rewardGroupParam);
  }

  private Long updateRewardGroup(PropsActivityRewardGroupParamCmd rewardGroupParam) {
    propsActivityRewardGroupService.updateSelectiveById(
        propsInnerConvertor.toPropsActivityRewardGroup(
            rewardGroupParam));
    return rewardGroupParam.getId();
  }

  private Long addRewardGroup(PropsActivityRewardGroupParamCmd rewardGroupParam) {
    PropsActivityRewardGroup propsActivityRewardGroup = propsInnerConvertor.toPropsActivityRewardGroup(
        rewardGroupParam);
    propsActivityRewardGroupService.save(propsActivityRewardGroup);
    return propsActivityRewardGroup.getId();
  }

  private Map<Long, List<PropsActivityRewardConfigInfoDTO>> mapPropsActivityRewardConfig(
      String sysOrigin, List<PropsActivityRewardGroupDTO> propsActivityRewardGroups) {
    if (StringUtils.isBlank(sysOrigin)) {
      return mapByGroupIds(
          propsActivityRewardGroups.stream().map(PropsActivityRewardGroupDTO::getId)
              .collect(Collectors.toSet()));
    }
    List<PropsActivityRewardConfigInfoDTO> propsActivityRewards = listGroupDTO(
        propsActivityRewardGroups.stream().map(PropsActivityRewardGroupDTO::getId)
            .collect(Collectors.toList()));

    Map<Long, BadgePictureConfig> badgePictureMap = badgePictureConfigService
        .mapBadge(sysOrigin, getBadgeContentList(propsActivityRewards));

    handlePropsAssemble(propsActivityRewards, badgePictureMap);
    return propsActivityRewards.stream()
        .collect(Collectors.groupingBy(PropsActivityRewardConfigInfoDTO::getGroupId));
  }

  private void handlePropsAssemble(List<PropsActivityRewardConfigInfoDTO> propsActivityRewards,
      Map<Long, BadgePictureConfig> badgePictureMap) {
    propsActivityRewards.stream()
        .filter(props -> Objects.equals(props.getType(), PropsActivityRewardEnum.BADGE.name()) || Objects.equals(props.getType(), PropsActivityRewardEnum.PROP_COUPON.name()))
        .forEach(props -> {
          BadgePictureConfig picture = badgePictureMap.get(Long.valueOf(props.getContent()));
          if (Objects.isNull(picture)) {
            return;
          }
          props.setCover(picture.getSelectUrl());
          props.setSourceUrl(picture.getAnimationUrl());
        });
  }

  private Set<Long> getBadgeContentList(List<PropsActivityRewardConfigInfoDTO> list) {
    return list.stream().filter(props -> Objects.equals(props.getType(),PropsActivityRewardEnum.BADGE.name()) ||
                    Objects.equals(props.getType(),PropsActivityRewardEnum.PROP_COUPON.name()))
        .map(props -> Long.valueOf(props.getContent()))
        .collect(Collectors.toSet());
  }

  public Map<Long, List<PropsActivityRewardConfigInfoDTO>> mapByGroupIds(Set<Long> groupIds) {
    if (CollectionUtils.isEmpty(groupIds)) {
      return Maps.newHashMap();
    }

    return Optional.ofNullable(listGroupDTO(new ArrayList<>(groupIds)))
        .map(config -> config.stream()
            .collect(Collectors.groupingBy(PropsActivityRewardConfigInfoDTO::getGroupId)))
        .orElseGet(Maps::newHashMap);
  }

  public List<PropsActivityRewardConfigInfoDTO> listGroupDTO(List<Long> groupIds) {

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

    List<PropsActivityRewardConfig> propsActivityRewardConfigs = propsActivityRewardConfigService.listByGroupIds(
        groupIds);

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

    Set<Long> sourceIds = propsActivityRewardConfigs.stream().filter(config ->
            Objects.equals(config.getType(), PropsActivityRewardEnum.PROPS.name()) || Objects.equals(config.getType(), PropsActivityRewardEnum.PROP_COUPON.name()))
        .map(config -> Long.valueOf(config.getContent()))
        .collect(Collectors.toSet());

    Set<Long> fragmentsIds = propsActivityRewardConfigs.stream().filter(config ->
            Objects.equals(config.getType(), PropsActivityRewardEnum.FRAGMENTS.name()))
        .map(config -> Long.valueOf(config.getContent()))
        .collect(Collectors.toSet());

    Set<Long> customizeSourceIds = propsActivityRewardConfigs.stream().filter(config ->
            Objects.equals(config.getType(), PropsActivityRewardEnum.CUSTOMIZE.name()))
        .map(config -> Long.valueOf(config.getContent()))
        .collect(Collectors.toSet());

    Set<Long> gifts = propsActivityRewardConfigs.stream().filter(config ->
            Objects.equals(config.getType(), PropsActivityRewardEnum.GIFT.name()))
        .map(config -> Long.valueOf(config.getContent()))
        .collect(Collectors.toSet());

    Map<Long, PropsSourceRecord> sourceRecordMap = propsSourceRecordService.mapByIds(sourceIds);

    Map<Long, PropsSourceRecord> customizeSourceMap = propsSourceRecordService
        .mapByIds(customizeSourceIds);

    Map<Long, PropsSourceRecord> fragmentsSourceMap = propsSourceRecordService
        .mapByIds(fragmentsIds);

    Map<Long, GiftConfig> giftMap = giftConfigService.mapByIds(gifts);

    Map<Long, BadgeConfig> sysBadgeConfigMap = badgeConfigService
        .mapByIds(propsActivityRewardConfigs.stream().filter(config ->
                Objects.equals(config.getType(), PropsActivityRewardEnum.BADGE.name()) || Objects.equals(config.getType(), PropsActivityRewardEnum.PROP_COUPON.name()))
            .map(config -> Long.valueOf(config.getContent()))
            .collect(Collectors.toSet()));

    Map<Long, EmojiGroup> emojiGroupMap = emojiGroupService
        .mapByIds(propsActivityRewardConfigs.stream().filter(config ->
                Objects.equals(config.getType(), PropsActivityRewardEnum.EMOJI.name()))
            .map(config -> Long.valueOf(config.getContent()))
            .collect(Collectors.toSet()));

    return propsActivityRewardConfigs.stream().map(config -> {
          PropsActivityRewardConfigInfoDTO propsActivity = propsInnerConvertor.toPropsActivityRewardConfigInfoDTO(
              config);
          propsActivity.setSort(Objects.isNull(propsActivity.getSort()) ? 0 : propsActivity.getSort());
          if (Objects.equals(config.getType(), PropsActivityRewardEnum.PROPS.name()) || Objects.equals(config.getType(), PropsActivityRewardEnum.PROP_COUPON.name())) {
            PropsSourceRecord sourceRecord = sourceRecordMap
                .get(Long.valueOf(config.getContent()));
            if (Objects.nonNull(sourceRecord)) {
                propsActivity.setCover(sourceRecord.getCover());
                propsActivity.setSourceUrl(sourceRecord.getSourceUrl());
                propsActivity.setAmount(sourceRecord.getAmount());
                propsActivity.setName(sourceRecord.getName());
            }
          }

          if (Objects.equals(config.getType(), PropsActivityRewardEnum.FRAGMENTS.name())) {
            PropsSourceRecord sourceRecord = fragmentsSourceMap
                .get(Long.valueOf(config.getContent()));
            propsActivity.setCover(sourceRecord.getCover());
            propsActivity.setSourceUrl(sourceRecord.getSourceUrl());
            propsActivity.setAmount(sourceRecord.getAmount());
            propsActivity.setName(sourceRecord.getName());
          }

          if (Objects.equals(config.getType(), PropsActivityRewardEnum.CUSTOMIZE.name())) {
            PropsSourceRecord sourceRecord = customizeSourceMap
                .get(Long.valueOf(config.getContent()));
            propsActivity.setCover(sourceRecord.getCover());
            propsActivity.setSourceUrl(sourceRecord.getSourceUrl());
            propsActivity.setRemark(config.getRemark());
            propsActivity.setName(sourceRecord.getName());
          }

          if (Objects.equals(config.getType(), PropsActivityRewardEnum.EMOJI.name())) {
            EmojiGroup sysEmojiGroupVO = emojiGroupMap.get(Long.valueOf(config.getContent()));
            propsActivity.setCover(sysEmojiGroupVO.getCover());
            propsActivity.setName(sysEmojiGroupVO.getGroupName());
          }

          if (Objects.equals(config.getType(), PropsActivityRewardEnum.GIFT.name())) {
            GiftConfig giftConfig = giftMap.get(Long.valueOf(config.getContent()));
            setGift(config, propsActivity, giftConfig);
            propsActivity.setName(giftConfig.getGiftName());
          }

          if (Objects.equals(config.getType(), PropsActivityRewardEnum.BADGE.name()) ||  Objects.equals(config.getType(), PropsActivityRewardEnum.PROP_COUPON.name())) {
            BadgeConfig sysBadgeConfig = sysBadgeConfigMap.get(DataTypeUtils.toLong(config.getContent()));
            if (Objects.nonNull(sysBadgeConfig)) {
                propsActivity.setBadgeName(sysBadgeConfig.getBadgeName());
                propsActivity.setName(sysBadgeConfig.getBadgeName());
            }
          }

          if (!Objects.equals(config.getType(), PropsActivityRewardEnum.SPECIAL_ID.name())) {
            propsActivity.setAmount(new BigDecimal(config.getContent()));
          }
          return propsActivity;
        }).sorted(Comparator.comparing(PropsActivityRewardConfigInfoDTO::getSort))
        .collect(Collectors.toList());
  }

  private void setGift(PropsActivityRewardConfig config,
      PropsActivityRewardConfigInfoDTO propsActivity, GiftConfig giftConfig) {
    if (Objects.nonNull(giftConfig)) {
      propsActivity.setCover(giftConfig.getGiftPhoto());
      propsActivity.setSourceUrl(giftConfig.getGiftSourceUrl());
      propsActivity.setAmount(giftConfig.getGiftCandy());
      return;
    }
    log.error("礼物数据错误:{}", config);
  }
}
