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

import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.dto.clientobject.family.FamilyRewardCO;
import com.red.circle.other.app.dto.clientobject.family.FamilyRewardRuleCO;
import com.red.circle.other.infra.database.cache.service.other.FamilyCacheService;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberWeekAwardRecord;
import com.red.circle.other.infra.database.rds.entity.family.FamilyRewardRule;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberWeekAwardRecordService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberWeekExpService;
import com.red.circle.other.infra.database.rds.service.family.FamilyRewardRuleService;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.NumUtils;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 我的家族奖励宝箱.
 * </p>
 *
 * @author pengshigang
 * @since 2021-08-06
 */
@Component
@RequiredArgsConstructor
public class FamilyRewardExe {

  private final FamilyCacheService familyCacheService;
  private final FamilyMemberInfoService familyMemberInfoService;
  private final FamilyRewardRuleService familyRewardRuleService;
  private final FamilyMemberWeekExpService familyMemberWeekExpService;
  private final FamilyMemberWeekAwardRecordService familyMemberWeekAwardRecordService;

  public FamilyRewardCO execute(AppExtCommand cmd) {

    FamilyMemberInfo memberInfo = getFamilyMemberByUserId(cmd);
    List<FamilyRewardRule> rules = getFamilyRewardRules(cmd);

    if (CollectionUtils.isEmpty(rules)) {
      return new FamilyRewardCO();
    }
    long memberExp = getExpCountByFamily(memberInfo);
    long memberLackExp = 0;
    long rewardQuantity = 0;
    List<FamilyMemberWeekAwardRecord> awardRecords = getAwardRecords(memberInfo);

    if (CollectionUtils.isNotEmpty(awardRecords)) {

      if (awardRecords.size() == rules.size()) {
        return getRewardCO(rules, memberExp, memberLackExp, rewardQuantity);
      }

      for (int i = 0; i < rules.size(); i++) {
        //根据最新的领取记录获得下一条规则
        if (Objects.equals(rules.get(i).getId(), awardRecords.get(0).getRewardRuleId())) {
          memberLackExp = rules.get(i + 1).getGoalExp() - memberExp;
          rewardQuantity = rules.get(i + 1).getRewardQuantity();
          break;
        }
      }
    } else {
      memberLackExp = rules.get(0).getGoalExp() - memberExp;
      rewardQuantity = rules.get(0).getRewardQuantity();
    }
    return getRewardCO(rules, memberExp, memberLackExp, rewardQuantity);
  }

  private FamilyRewardCO getRewardCO(List<FamilyRewardRule> rules, Long memberExp,
      Long memberLackExp, Long rewardQuantity) {

    return new FamilyRewardCO()
        .setRewardRuleList(getFamilyRewardRules(rules, (double) memberExp))
        .setMemberExp(memberExp)
        .setMemberLackExp(Math.max(memberLackExp, 0L))
        .setRewardQuantity(Math.max(rewardQuantity, 0L))
        .setWeekStartEnd(familyCacheService.getFamilyWeekRewardTime());
  }

  private List<FamilyMemberWeekAwardRecord> getAwardRecords(FamilyMemberInfo memberInfo) {
    return familyMemberWeekAwardRecordService
        .listByFamily(memberInfo.getFamilyId(), memberInfo.getId());
  }

  private List<FamilyRewardRuleCO> getFamilyRewardRules(List<FamilyRewardRule> rules,
      Double memberExp) {

    List<FamilyRewardRuleCO> familyRewardRules = Lists.newArrayList();
    boolean isContinue = Boolean.TRUE;

    for (FamilyRewardRule rule : rules) {

      double percentage = 0.0;
      double goalExp = (double) rule.getGoalExp();

      if (memberExp >= rule.getGoalExp() && isContinue) {
        percentage = 100;
        isContinue = memberExp > goalExp ? Boolean.TRUE : Boolean.FALSE;
      }

      if (memberExp < goalExp && isContinue) {
        percentage = memberExp / goalExp * 100;
        isContinue = Boolean.FALSE;
      }
      rewardRuleAdd(familyRewardRules, rule, percentage);
    }
    return familyRewardRules;
  }

  private void rewardRuleAdd(List<FamilyRewardRuleCO> familyRewardRules, FamilyRewardRule rule,
      Double percentage) {
    familyRewardRules.add(new FamilyRewardRuleCO()
        .setId(rule.getId())
        .setRewardQuantity(rule.getRewardQuantity())
        .setRewardQuantityStr(NumUtils.formatInt(rule.getRewardQuantity()))
        .setGoalExp(rule.getGoalExp())
        .setGoalExpStr(NumUtils.formatInt(rule.getGoalExp()))
        .setPercentageExp(percentage)
    );
  }


  private Long getExpCountByFamily(FamilyMemberInfo memberInfo) {
    return Optional.ofNullable(familyMemberWeekExpService
            .getFamilyMemberWeekExp(memberInfo.getFamilyId(), memberInfo.getMemberUserId()))
        .map(weekExp -> Objects.isNull(weekExp.getExp()) ? 0 : weekExp.getExp()).orElse(0L);
  }

  private List<FamilyRewardRule> getFamilyRewardRules(AppExtCommand cmd) {
    return familyRewardRuleService.listBySysOrigin(cmd.getReqSysOrigin().getOrigin());
  }

  private FamilyMemberInfo getFamilyMemberByUserId(AppExtCommand cmd) {
    FamilyMemberInfo memberInfo = familyMemberInfoService
        .getFamilyMemberByUserId(cmd.getReqUserId());
    ResponseAssert.notNull(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA, memberInfo);
    return memberInfo;
  }


}
