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

import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.app.AppUserIdCmd;
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.app.common.pet.PetCommon;
import com.red.circle.other.app.convertor.PetConvertor;
import com.red.circle.other.app.dto.clientobject.pet.PetCurrentFeedingCO;
import com.red.circle.other.app.dto.clientobject.pet.PetIncomeCO;
import com.red.circle.other.infra.database.cache.service.other.PetCacheService;
import com.red.circle.other.infra.database.rds.entity.pet.PetStage;
import com.red.circle.other.infra.database.rds.entity.pet.PetUserPetBag;
import com.red.circle.other.infra.database.rds.entity.pet.PetUserPetIncomeDetails;
import com.red.circle.other.infra.database.rds.service.pet.PetIncomeReceiveService;
import com.red.circle.other.infra.database.rds.service.pet.PetPoolService;
import com.red.circle.other.infra.database.rds.service.pet.PetStageService;
import com.red.circle.other.infra.database.rds.service.pet.PetUserPetBagService;
import com.red.circle.other.infra.database.rds.service.pet.PetUserPetIncomeDetailsService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 当前饲养宠物，如果不存在则激活第一只宠物.
 *
 * @author pengliang on 2021/10/14
 */
@Component
@RequiredArgsConstructor
public class PetCurrentFeedingQueryExe {

  private final PetConvertor petConvertor;
  private final RedisService redisService;
  private final PetCommon petCommon;
  private final PetPoolService petPoolService;
  private final PetCacheService petCacheService;
  private final PetStageService petStageService;
  private final PetUserPetBagService petUserPetBagService;
  private final PetIncomeReceiveService petIncomeReceiveService;
  private final PetUserPetIncomeDetailsService petUserPetIncomeDetailsService;

  public PetCurrentFeedingCO execute(AppUserIdCmd cmd) {
    PetUserPetBag petBag = petUserPetBagService.getLatest(cmd.getUid());

    if (Objects.isNull(petBag)) {
      return initFirstPet(cmd);
    }

    return getPetCurrentFeeding(cmd, petBag);
  }

  private PetCurrentFeedingCO getPetCurrentFeeding(AppUserIdCmd cmd, PetUserPetBag petBag) {
    PetStage petStage = petStageService.getByState(petBag.getPetId(), petBag.getPetStage());
    // 1033 记录不存在
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, petStage);
    Long freeFeedingNum = petCacheService
        .getTodayFreeFeedingNum(petBag.getUserId(), petStage.getPetId());
    return new PetCurrentFeedingCO()
        .setPetBag(petConvertor.toPetBagCO(petBag))
        .setPetStage(petConvertor.toPetStageCO(petStage))
        .setFreeFeeding(
            Objects.isNull(freeFeedingNum) || freeFeedingNum < petStage.getFreeFeedingNum())
        .setIncomes(listPetIncome(cmd))
        .setFinish(petCommon.checkFinish(petBag, petStage))
        .calculate();
  }

  private List<PetIncomeCO> listPetIncome(AppUserIdCmd cmd) {

    List<PetUserPetIncomeDetails> incomes = petUserPetIncomeDetailsService
        .listDetailsTwoSize(cmd.getUid());

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

    if (Objects.equals(cmd.getReqUserId(), cmd.getUid())) {
      return petConvertor.toListPetIncomeCO(incomes);
    }

    Map<Long, Boolean> map = petIncomeReceiveService.mapNotStealableByIncomeDetailsIds(
        cmd.getReqUserId(),
        incomes.stream().map(PetUserPetIncomeDetails::getId).collect(Collectors.toSet())
    );

    return petConvertor.toListPetIncomeCO(
        incomes.stream().filter(income -> Objects.isNull(map.get(income.getId())))
            .collect(Collectors.toList()));
  }

  private PetCurrentFeedingCO initFirstPet(AppUserIdCmd cmd) {
    PetStage petStage = petStageService.getFirst(petPoolService.getFirstPetId(
        SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin())));
    // 1033 激活失败
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, petStage);
    PetUserPetBag petUserPetBag = new PetUserPetBag()
        .setId(IdWorkerUtils.getId())
        .setUserId(cmd.getUid())
        .setPetId(petStage.getPetId())
        .setFeedingNum(0)
        .setConsumeFood(BigDecimal.ZERO)
        .setPetStage(petStage.getStage())
        .setPetStageId(petStage.getId())
        .setLatestFeedingTime(
            TimestampUtils.nowMinusMinutes(petStage.getFeedingIntervalMinute()));

    // 1000 添加失败
    ResponseAssert.isTrue(CommonErrorCode.SAVE_FAILURE,
        redisService.setIfAbsent(petUserPetBag.getUserId() + ":" + petUserPetBag.getPetId(), 1,
            TimeUnit.MINUTES));

    petUserPetBagService.add(petUserPetBag);

    return new PetCurrentFeedingCO()
        .setPetBag(petConvertor.toPetBagCO(petUserPetBag))
        .setPetStage(petConvertor.toPetStageCO(petStage))
        .setFreeFeeding(petStage.getFreeFeedingNum() > 0)
        .setIncomes(handlePetIncome(petUserPetBag, petStage))
        .calculate();
  }

  private List<PetIncomeCO> handlePetIncome(PetUserPetBag petUserPetBag, PetStage petStage) {
    List<PetIncomeCO> incomes = petCommon.calculateIncome(petStage);
    if (CollectionUtils.isNotEmpty(incomes)) {
      petUserPetIncomeDetailsService
          .saveBatch(petCommon.toListPetUserPetIncomeDetails(incomes, petUserPetBag));
    }
    return incomes;
  }


}
