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

import com.red.circle.common.business.core.enums.ApprovalStatusEnum;
import com.red.circle.console.app.convertor.bank.BankAppConvertor;
import com.red.circle.console.app.dto.clienobject.user.UserWithdrawInfoCO;
import com.red.circle.console.inner.error.ConsoleErrorCode;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.wallet.inner.endpoint.bank.UserWithdrawInfoClient;
import com.red.circle.wallet.inner.error.BankErrorCode;
import com.red.circle.wallet.inner.model.cmd.UserWithdrawInfoBackQryCmd;
import com.red.circle.wallet.inner.model.cmd.UserWithdrawInfoCmd;
import com.red.circle.wallet.inner.model.cmd.UserWithdrawInfoPassCmd;
import com.red.circle.wallet.inner.model.dto.UserWithdrawInfoDTO;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * 用户提现信息.
 *
 * @author tf
 */
@Service
@RequiredArgsConstructor
public class UserWithdrawInfoBackServiceImpl implements UserWithdrawInfoBackService {

  private final UserWithdrawInfoClient withdrawInfoClient;
  private final BankAppConvertor bankAppConvertor;
  private final UserProfileClient userProfileClient;

  @Override
  public void add(UserWithdrawInfoCmd param) {
    ResponseAssert.isFalse(BankErrorCode.REPEAT_WITHDRAW_INFO_ERROR,
        ResponseAssert.requiredSuccess(
            withdrawInfoClient.existWithdrawInfo(param.getUserId(), param.getCategory())));

    param.setId(IdWorkerUtils.getId());
    param.setDel(Boolean.FALSE);
    param.setStatus(ApprovalStatusEnum.PASS.name());
    param.setSysOrigin(param.getSysOrigin());
    withdrawInfoClient.addWithdrawInfo(param);
  }

  @Override
  public void update(UserWithdrawInfoCmd param) {
    withdrawInfoClient.updateWithdrawInfo(param);
  }

  @Override
  public List<UserWithdrawInfoCO> listByUserId(Long userId) {
    return bankAppConvertor.toListUserWithdrawInfoCO(
        ResponseAssert.requiredSuccess(withdrawInfoClient.listByUserId(userId)));
  }

  @Override
  public List<UserWithdrawInfoDTO> listPassWithdrawInfo(Long userId) {
    return ResponseAssert.requiredSuccess(withdrawInfoClient.listPassByUserId(userId));
  }

  @Override
  public void use(Long id, Long currentUidLong) {
    UserWithdrawInfoDTO withdrawInfo = ResponseAssert.requiredSuccess(
        withdrawInfoClient.getById(id));
    ResponseAssert.notNull(ConsoleErrorCode.NOT_FOUND_RECORD, withdrawInfo);
    ResponseAssert.isFalse(ConsoleErrorCode.NOT_FOUND_RECORD, withdrawInfo.getDel());
    ResponseAssert.isTrue(BankErrorCode.NOT_APPROVED_ERROR,
        Objects.equals(ApprovalStatusEnum.PASS.name(), withdrawInfo.getStatus()));
    ResponseAssert.requiredSuccess(
        withdrawInfoClient.useWithdrawInfo(id, withdrawInfo.getUserId(), currentUidLong));
  }

  @Override
  public void deleteById(Long id, Long currentUidLong) {
    UserWithdrawInfoDTO withdrawInfo = ResponseAssert.requiredSuccess(
        withdrawInfoClient.getById(id));
    ResponseAssert.notNull(ConsoleErrorCode.NOT_FOUND_RECORD, withdrawInfo);
    ResponseAssert.isFalse(ConsoleErrorCode.NOT_FOUND_RECORD, withdrawInfo.getDel());
    withdrawInfoClient.deleteByIdByUserId(id, withdrawInfo.getUserId(), currentUidLong);
  }

  @Override
  public void pass(Set<Long> ids, Long currentUidLong) {
    withdrawInfoClient.pass(
        new UserWithdrawInfoPassCmd().setCurrentUidLong(currentUidLong).setIds(ids));
  }

  @Override
  public void notPass(Set<Long> ids, Long currentUidLong) {
    withdrawInfoClient.notPass(
        new UserWithdrawInfoPassCmd().setCurrentUidLong(currentUidLong).setIds(ids));
  }

  @Override
  public PageResult<UserWithdrawInfoCO> pageQuery(UserWithdrawInfoBackQryCmd query) {
    PageResult<UserWithdrawInfoDTO> withdrawInfoDTOPageResult = ResponseAssert.requiredSuccess(
        withdrawInfoClient.pageQuery(query));
    PageResult<UserWithdrawInfoCO> pageResult = withdrawInfoDTOPageResult.convert(
        bankAppConvertor::toUserWithdrawInfoCO);

    if (pageResult.getTotal() <= 0) {
      return pageResult;
    }

    Map<Long, UserProfileDTO> userProfileMap = getUserProfileMap(
        pageResult.getRecords().stream().toList());
    if (CollectionUtils.isEmpty(userProfileMap)) {
      return pageResult;
    }

    pageResult.setRecords(pageResult.getRecords().stream().map(info -> {
      UserProfileDTO userProfile = userProfileMap.get(info.getUserId());
      if (Objects.isNull(userProfile)) {
        return null;
      }
      info.setUserProfile(userProfile);
      return info;
    }).filter(Objects::nonNull).collect(Collectors.toList()));

    return pageResult;
  }

  private Map<Long, UserProfileDTO> getUserProfileMap(List<UserWithdrawInfoCO> withdrawInfos) {
    return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(
        withdrawInfos.stream().map(UserWithdrawInfoCO::getUserId).collect(Collectors.toSet())));
  }

}
