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

import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd;
import com.red.circle.common.business.enums.SendPropsOrigin;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.common.activity.PropsActivitySendCommon;
import com.red.circle.other.infra.common.activity.send.SendRewardGroup;
import com.red.circle.other.infra.database.mongo.entity.activity.ConsumeActivityCount;
import com.red.circle.other.infra.database.mongo.service.activity.ConsumeActivityCountService;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRuleConfig;
import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRuleConfigService;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.other.inner.asserts.PropsErrorCode;
import com.red.circle.other.inner.enums.activity.PropsActivityTypeEnum;
import com.red.circle.other.inner.model.dto.activity.rule.CumulativeRechargeContent;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 消耗活动领取奖励.
 *
 * @author pengshigang on 2023/5/29
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ActivityConsumeRewardReceiveCmdExe {

  private final RedisService redisService;
  private final UserRegionGateway userRegionGateway;
  private final PropsActivitySendCommon propsActivitySendCommon;
  private final ConsumeActivityCountService consumeActivityCountService;
  private final PropsActivityRuleConfigService propsActivityRuleConfigService;

  public void execute(AppIdLongCmd cmd) {

    String regionId = userRegionGateway.getRegionId(cmd.getReqUserId());
    ResponseAssert.isTrue(CommonErrorCode.REGION_NOT_SUPPORTED_ERROR,
        StringUtils.isNotBlank(regionId));

    ConsumeActivityCount count = consumeActivityCountService
        .getById(cmd.getReqUserId() + "_" + regionId);
    ResponseAssert.notNull(PropsErrorCode.UNCLAIMABLE, count);
    ResponseAssert.isFalse(CommonErrorCode.NON_REPEATABLE,
        count.getReceivedIds().contains(cmd.getId().toString()));

    PropsActivityRuleConfig ruleConfig = propsActivityRuleConfigService.getById(cmd.getId());
    // 1034 没有找到映射信息
    ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, ruleConfig);
    ResponseAssert.isTrue(CommonErrorCode.CONFIGURATION_ERROR, Objects.equals(
        ruleConfig.getActivityType(), PropsActivityTypeEnum.CONSUMPTION_ACTIVITY.name()));

    CumulativeRechargeContent consumeActivityContent = CumulativeRechargeContent
        .serializable(ruleConfig.getJsonData());

    // 2040 配置错误
    ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, consumeActivityContent);
    ResponseAssert.isTrue(CommonErrorCode.CONFIGURATION_ERROR, ArithmeticUtils
        .gt(consumeActivityContent.getQuantity(), BigDecimal.ZERO));

    // 2046 不可领取
    ResponseAssert.isTrue(PropsErrorCode.UNCLAIMABLE,
        count.getTarget() >= consumeActivityContent.getQuantity().longValue());

    // 防止重复触发领取 3分钟后可重试领取
    ResponseAssert.isTrue(DynamicErrorCode.REPEATED_SUBMIT, redisService.setIfAbsent(
        PropsActivityTypeEnum.CONSUMPTION_ACTIVITY + ":" + cmd.getReqUserId() + ":" + cmd.getId(),
        3, TimeUnit.MINUTES));

    // 发送奖励
    propsActivitySendCommon.sendActivityGroup(SendRewardGroup.builder()
        .trackId(ruleConfig.getId())
        .sysOrigin(cmd.requireReqSysOriginEnum())
        .acceptUserId(cmd.getReqUserId())
        .resourceGroupId(ruleConfig.getResourceGroupId())
        .origin(SendPropsOrigin.CONSUMPTION_ACTIVITY)
        .build());

    // 保存已领取记录
    consumeActivityCountService.received(count.getId(), ruleConfig.getId().toString());

  }

}
