package com.red.circle.console.app.service.app.order;

import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
import com.red.circle.console.infra.database.rds.entity.admin.User;
import com.red.circle.console.infra.database.rds.service.admin.UserService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.order.inner.asserts.OrderErrorCode;
import com.red.circle.order.inner.endpoint.InAppPurchaseDetailsClient;
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * 内购详情 实现.
 *
 * @author pengliang on 2022/10/31
 */
@Service
@RequiredArgsConstructor
public class InAppPurchaseBackServiceImpl implements InAppPurchaseBackService {

  private final UserService userService;
  private final UserProfileClient userProfileClient;
  private final InAppPurchaseDetailsClient inAppPurchaseDetailsClient;

  @Override
  public InAppPurchaseDetailsCO getDetails(String id) {
    InAppPurchaseDetailsDTO details = ResponseAssert.requiredSuccess(
        inAppPurchaseDetailsClient.getById(id)
    );

    ResponseAssert.notNull(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, details);

    InAppPurchaseDetailsCO co = new InAppPurchaseDetailsCO()
        .setDetails(details);

    if (details.receiptTypeEqReceipt()) {
      co.setAcceptUserProfile(
          ResponseAssert.requiredSuccess(userProfileClient.getByUserId(details.getAcceptUserId())));
      co.setCreateNickname(Optional.ofNullable(userService.getById(details.getCreateUser()))
          .map(User::getNickname)
          .orElse(""));
    }

    if (details.receiptTypeEqPayment()) {
      if (Objects.equals(details.getCreateUser(), details.getAcceptUserId())) {
        co.setAcceptUserProfile(
            ResponseAssert.requiredSuccess(
                userProfileClient.getByUserId(details.getAcceptUserId())));
      } else {
        Map<Long, UserProfileDTO> userProfileMap = ResponseAssert.requiredSuccess(
            userProfileClient.mapByUserIds(
                Set.of(details.getCreateUser(), details.getAcceptUserId()))
        );
        co.setAcceptUserProfile(userProfileMap.get(details.getAcceptUserId()));
        co.setCreateUserProfile(userProfileMap.get(details.getCreateUser()));
      }
    }

    return co;
  }

  @Override
  public List<InAppPurchaseDetailsCO> listDetails(InAppPurchaseDetailsQryCmd query) {
    List<InAppPurchaseDetailsDTO> inAppPurchaseDetails = ResponseAssert.requiredSuccess(
        inAppPurchaseDetailsClient.list(query)
    );

    if (CollectionUtils.isEmpty(inAppPurchaseDetails)) {
      return CollectionUtils.newArrayList();
    }

    Set<Long> backUserIds = inAppPurchaseDetails.stream().filter(
            receipt -> receipt.receiptTypeEqReceipt() && Objects.nonNull(receipt.getCreateUser()))
        .map(InAppPurchaseDetailsDTO::getCreateUser)
        .collect(Collectors.toSet());

    Set<Long> appUserIds = Stream.of(inAppPurchaseDetails.stream().filter(
                    receipt -> receipt.receiptTypeEqPayment() && Objects.nonNull(receipt.getCreateUser()))
                .map(InAppPurchaseDetailsDTO::getCreateUser)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet()),
            inAppPurchaseDetails.stream().map(InAppPurchaseDetailsDTO::getAcceptUserId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet()))
        .flatMap(Collection::stream)
        .collect(Collectors.toSet());

    Map<Long, User> userMap = userService.mapBackUser(backUserIds);
    Map<Long, UserProfileDTO> userProfileMap = ResponseAssert.requiredSuccess(
        userProfileClient.mapByUserIds(appUserIds)
    );

    return inAppPurchaseDetails.stream().map(details -> {
      InAppPurchaseDetailsCO co = new InAppPurchaseDetailsCO()
          .setDetails(details);

      if (details.receiptTypeEqReceipt()) {
        co.setAcceptUserProfile((userProfileMap.get(details.getAcceptUserId())));
        co.setCreateNickname(Optional.ofNullable(userMap.get(details.getCreateUser()))
            .map(User::getNickname)
            .orElse(""));
      }

      if (details.receiptTypeEqPayment()) {
        if (Objects.equals(details.getCreateUser(), details.getAcceptUserId())) {
          co.setAcceptUserProfile(userProfileMap.get(details.getAcceptUserId()));
        } else {
          co.setAcceptUserProfile(userProfileMap.get(details.getAcceptUserId()));
          co.setCreateUserProfile(userProfileMap.get(details.getCreateUser()));
        }
      }
      return co;
    }).collect(Collectors.toList());
  }

  @Override
  public Map<String, Object> statistics(InAppPurchaseDetailsQryCmd query) {
    return ResponseAssert.requiredSuccess(
        inAppPurchaseDetailsClient.statistics(query)
    );
  }

}
