package com.red.circle.other.infra.database.mongo.service.sys.impl;

import com.google.common.collect.Lists;
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.service.sys.ActivityConfigService;
import com.red.circle.other.inner.model.cmd.sys.ActivityConfigBackQryCmd;
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.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

/**
 * 活动配置实现.
 *
 * @author pengliang on 2022/8/12
 */
@Service
@RequiredArgsConstructor
public class ActivityConfigServiceImpl implements ActivityConfigService {

  private final MongoTemplate mongoTemplate;

  @Override
  public void add(ActivityConfig activityConfig) {

    if (Objects.isNull(activityConfig)) {
      return;
    }

    if (Objects.isNull(activityConfig.getAwardStatus())) {
      activityConfig.setAwardStatus(Boolean.FALSE);
    }

    activityConfig.setButOneRewards(fillRewardsDefaultVal(activityConfig.getButOneRewards()));
    activityConfig.setButTwoRewards(fillRewardsDefaultVal(activityConfig.getButTwoRewards()));
    if (Objects.isNull(activityConfig.getButTwoRewards())) {
      activityConfig.setButTwoRewards(Lists.newArrayList());
    }

    mongoTemplate.save(activityConfig);
  }

  private List<ActivityConfigRewards> fillRewardsDefaultVal(List<ActivityConfigRewards> rewards) {
    if (Objects.isNull(rewards)) {
      return Lists.newArrayList();
    }
    return rewards.stream().peek(reward -> {
      if (Objects.isNull(reward.getStatus())) {
        reward.setStatus(Boolean.FALSE);
      }
      if (Objects.isNull(reward.getRankUsers())) {
        reward.setRewards(Lists.newArrayList());
      }
    }).collect(Collectors.toList());
  }

  @Override
  public void updateSelectiveById(ActivityConfig activityConfig) {
    Update update = new Update()
        .set("updateTime", activityConfig.getUpdateTime())
        .set("updateUser", activityConfig.getUpdateUser());

    if (Objects.nonNull(activityConfig.getTemplateId())) {
      update.set("templateId", activityConfig.getTemplateId());
    }
    if (Objects.nonNull(activityConfig.getStartTime())) {
      update.set("startTime", activityConfig.getStartTime());
    }
    if (Objects.nonNull(activityConfig.getEndTime())) {
      update.set("endTime", activityConfig.getEndTime());
    }
    if (Objects.nonNull(activityConfig.getShowcase())) {
      update.set("showcase", activityConfig.getShowcase());
    }
    if (StringUtils.isNotBlank(activityConfig.getRemark())) {
      update.set("remark", activityConfig.getRemark());
    }
    if (Objects.nonNull(activityConfig.getButOneRewards())) {
      update.set("butOneRewards", fillRewardsDefaultVal(activityConfig.getButOneRewards()));
    }
    if (Objects.nonNull(activityConfig.getButTwoRewards())) {
      update.set("butTwoRewards", fillRewardsDefaultVal(activityConfig.getButTwoRewards()));
    }
    if (Objects.nonNull(activityConfig.getGiftIds())) {
      update.set("giftIds", activityConfig.getGiftIds());
    }
    mongoTemplate.updateFirst(
        Query.query(Criteria.where("id").is(activityConfig.getId())),
        update,
        ActivityConfig.class);
  }


  @Override
  public ActivityConfig getById(Long id) {
    return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id))
        , ActivityConfig.class);
  }

  @Override
  public List<ActivityConfig> listProcessing(String sysOrigin, Long giftId) {
    if (StringUtils.isBlank(sysOrigin) || Objects.isNull(giftId)) {
      return Lists.newArrayList();
    }
    return mongoTemplate.find(Query.query(Criteria.where("sysOrigin").is(sysOrigin)
            .and("startTime").lte(TimestampUtils.now())
            .and("endTime").gte(TimestampUtils.now())
            .and("showcase").is(Boolean.TRUE)
            .and("giftIds").elemMatch(Criteria.where("$eq").is(giftId.toString())))
        , ActivityConfig.class);
  }

  @Override
  public List<Long> listProcessingGiftIds(List<Long> activityIds) {
    if (CollectionUtils.isEmpty(activityIds)) {
      return Lists.newArrayList();
    }
    List<ActivityConfig> activityConfigs = mongoTemplate.find(
        Query.query(Criteria.where("id").in(activityIds)
            .and("startTime").lte(TimestampUtils.now())
            .and("endTime").gte(TimestampUtils.now())
            .and("showcase").is(Boolean.TRUE))
        , ActivityConfig.class);

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

    return activityConfigs.stream().map(ActivityConfig::getGiftIds)
        .flatMap(Collection::stream)
        .filter(StringUtils::isNotBlank)
        .map(Long::valueOf)
        .distinct()
        .collect(Collectors.toList());
  }

  @Override
  public void updateButOneRewardsStatusTrue(Long id, Long rewardId) {
    mongoTemplate.updateFirst(
        Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("butOneRewards.$[i].status", Boolean.TRUE)
            .set("updateTime", TimestampUtils.now())
            .filterArray(Criteria.where("i.rewardId").is(rewardId)),
        ActivityConfig.class);
  }

  @Override
  public void updateButTwoRewardsStatusTrue(Long id, Long rewardId) {
    mongoTemplate.updateFirst(
        Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("butTwoRewards.$[i].status", Boolean.TRUE)
            .set("updateTime", TimestampUtils.now())
            .filterArray(Criteria.where("i.rewardId").is(rewardId)),
        ActivityConfig.class);
  }

  @Override
  public void updateRewards(Long id, List<ActivityConfigRewards> butOneRewards,
      List<ActivityConfigRewards> butTwoRewards) {
    mongoTemplate.updateFirst(
        Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("butOneRewards", butOneRewards)
            .set("butTwoRewards", butTwoRewards)
            .set("updateTime", TimestampUtils.now()),
        ActivityConfig.class);
  }

  @Override
  public void updateAwardStatusTrue(Long id) {
    mongoTemplate.updateFirst(
        Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("awardStatus", Boolean.TRUE)
            .set("updateTime", TimestampUtils.now()),
        ActivityConfig.class);
  }

  @Override
  public List<ActivityConfig> list(ActivityConfigBackQryCmd query) {
    Criteria criteria = Criteria.where("sysOrigin").is(query.getSysOrigin());

    if (Objects.nonNull(query.getId())) {
      query.setLastId(null);
      criteria.and("id").is(query.getId());
    }
    if (Objects.nonNull(query.getLastId())) {
      criteria.and("id").lt(query.getLastId());
    }
    if (Objects.nonNull(query.getTemplateId())) {
      criteria.and("templateId").lt(query.getTemplateId());
    }
    if (Objects.equals(query.getShowcase(), 1)) {
      criteria.and("endTime").gt(TimestampUtils.now());
    }
    if (Objects.equals(query.getShowcase(), 2)) {
      criteria.and("endTime").lt(TimestampUtils.now());
    }
    if (Objects.equals(query.getShowcase(), 3)) {
      criteria.and("showcase").is(Boolean.TRUE);
    }
    if (Objects.equals(query.getShowcase(), 4)) {
      criteria.and("showcase").is(Boolean.FALSE);
    }

    return mongoTemplate.find(Query.query(criteria)
            .with(Sort.by(Sort.Order.desc("id")))
            .limit(query.getLimit())
        , ActivityConfig.class);
  }

  @Override
  public ActivityConfig getEffectiveActivityConf(ActivityConfigBackQryCmd query) {
    Criteria criteria = Criteria.where("sysOrigin").is(query.getSysOrigin());
    criteria.and("showcase").is(true);
    criteria.and("endTime").gt(TimestampUtils.now());
    if (query.getTemplateId() != null) {
      criteria.and("templateId").is(query.getTemplateId());
    }

    return mongoTemplate.findOne(Query.query(criteria)
            .with(Sort.by(Sort.Order.desc("id")))
            .limit(1)
        , ActivityConfig.class);
  }

  public ActivityConfig getShowcaseActivityConf(Long templateId, String activityType) {
    Criteria criteria = Criteria.where("showcase").is(true);
    criteria.and("templateId").is(templateId);
    criteria.and("activityType").is(activityType);

    return mongoTemplate.findOne(Query.query(criteria)
                    .with(Sort.by(Sort.Order.desc("id")))
                    .limit(1)
            , ActivityConfig.class);
  }

  @Override
  public List<ActivityConfig> listRecentlyEndedActivities(String sysOrigin, Integer limit) {
    Date now = TimestampUtils.now();

    Criteria criteria = Criteria.where("sysOrigin").is(sysOrigin)
//        .and("showcase").is(true)
        .and("startTime").lte(now);

    return mongoTemplate.find(
        Query.query(criteria)
            .with(Sort.by(Sort.Order.desc("id")))
            .limit(limit != null ? limit : 100),
        ActivityConfig.class
    );
  }

  @Override
  public List<ActivityConfig> listOngoingActivities(String sysOrigin) {
    if (StringUtils.isBlank(sysOrigin)) {
      return Lists.newArrayList();
    }
    Date now = TimestampUtils.now();
    return mongoTemplate.find(
        Query.query(Criteria.where("sysOrigin").is(sysOrigin)
            .and("showcase").is(Boolean.TRUE)
            .and("startTime").lte(now)
            .and("endTime").gte(now)),
        ActivityConfig.class);
  }

}
