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

import com.google.common.collect.Lists;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.pet.PetOperationLogCO;
import com.red.circle.other.app.dto.cmd.pet.PetOperationLogQueryCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.rds.entity.pet.PetFeedingRecord;
import com.red.circle.other.infra.database.rds.entity.pet.PetIncomeReceive;
import com.red.circle.other.infra.database.rds.service.pet.PetFeedingRecordService;
import com.red.circle.other.infra.database.rds.service.pet.PetIncomeReceiveService;
import com.red.circle.other.inner.enums.sys.appmanager.PetOperationType;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 收益流水.
 *
 * @author pengliang on 2021/10/14
 */
@Component
@RequiredArgsConstructor
public class PetOperationRunningWaterQueryExe {

  private final UserProfileGateway userProfileGateway;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final PetIncomeReceiveService petIncomeReceiveService;
  private final PetFeedingRecordService petFeedingRecordService;

  public List<PetOperationLogCO> execute(PetOperationLogQueryCmd cmd) {

    if (Objects.equals(cmd.getType(), PetOperationType.FEED)) {
      return listFeed(cmd);
    }

    return listPetIncomeReceive(cmd);
  }

  private List<PetOperationLogCO> listFeed(PetOperationLogQueryCmd cmd) {
    List<PetFeedingRecord> petFeedingRecords = petFeedingRecordService
        .flow(cmd.getReqUserId(), cmd.getLastId());

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

    Map<Long, UserProfileDTO> baseInfoMap = userProfileAppConvertor.toMapUserProfileDTO(
        userProfileGateway.mapByUserIds(
            petFeedingRecords.stream().map(PetFeedingRecord::getCreateUser)
                .collect(Collectors.toSet())));

    return petFeedingRecords.stream().map(feedingRecord -> new PetOperationLogCO()
        .setId(feedingRecord.getId())
        .setType(PetOperationType.FEED.name())
        .setQuantity(feedingRecord.getFeedingNum())
        .setFeedType(feedingRecord.getFeedType())
        .setUserProfile(
            baseInfoMap.get(feedingRecord.getCreateUser()))
        .setCreateTime(feedingRecord.getCreateTime())
        .setSelf(Objects.equals(feedingRecord.getUserId(), feedingRecord.getCreateUser()))
    ).toList();
  }

  private List<PetOperationLogCO> listPetIncomeReceive(PetOperationLogQueryCmd cmd) {

    List<PetIncomeReceive> receives = flowPetIncomeReceive(cmd);

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

    Map<Long, UserProfileDTO> baseInfoMap = userProfileAppConvertor.toMapUserProfileDTO(
        userProfileGateway.mapByUserIds(
            receives.stream().map(PetIncomeReceive::getIncomeUserId)
                .collect(Collectors.toSet())));

    return receives.stream().map(receive -> new PetOperationLogCO()
        .setId(receive.getId())
        .setType(receive.getType())
        .setQuantity(receive.getIncomeQuantity())
        .setUserProfile(
            baseInfoMap.get(receive.getIncomeUserId()))
        .setCreateTime(receive.getCreateTime())
        .setSelf(Objects.equals(receive.getPetUserId(), receive.getIncomeUserId()))
    ).toList();
  }


  private List<PetIncomeReceive> flowPetIncomeReceive(PetOperationLogQueryCmd cmd) {

    if (Objects.equals(cmd.getType(), PetOperationType.CHARGE)) {
      return petIncomeReceiveService
          .flowIncome(cmd.getReqUserId(), cmd.getLastId());
    }

    if (Objects.equals(cmd.getType(), PetOperationType.STEAL)) {
      return petIncomeReceiveService
          .flowStolen(cmd.getReqUserId(), cmd.getLastId());
    }

    return Lists.newArrayList();
  }
}
