package com.red.circle.wallet.infra.database.mongo.service.bank.impl;

import com.google.common.collect.Maps;
import com.red.circle.common.business.core.enums.ApprovalStatusEnum;
import com.red.circle.component.mongodb.page.MongoPageHelper;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.infra.database.mongo.entity.bank.UserWithdrawInfo;
import com.red.circle.wallet.infra.database.mongo.service.bank.UserWithdrawInfoService;
import com.red.circle.wallet.inner.model.cmd.UserWithdrawInfoBackQryCmd;
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.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

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

  private final MongoTemplate mongoTemplate;
  private final MongoPageHelper mongoPageHelper;

  @Override
  public Boolean exist(Long userId, String category) {
    return mongoTemplate.exists(Query.query(Criteria.where("userId").is(userId)
        .and("category").is(category).and("del").is(Boolean.FALSE)), UserWithdrawInfo.class);
  }

  @Override
  public UserWithdrawInfo getById(Long id) {
    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(id));
    return mongoTemplate.findOne(query, UserWithdrawInfo.class);
  }

  @Override
  public UserWithdrawInfo getUseByUserId(Long userId) {
    return mongoTemplate.findOne(Query.query(Criteria.where("userId").is(userId)
        .and("use").is(Boolean.TRUE).and("del").is(Boolean.FALSE)), UserWithdrawInfo.class);
  }

  @Override
  public void add(UserWithdrawInfo info) {
    info.setUse(Boolean.FALSE);
    mongoTemplate.save(info);
  }

  @Override
  public void update(UserWithdrawInfo info) {
    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(info.getId())),
        new Update()
            .set("status", info.getStatus())
            .set("contactNumber", info.getContactNumber())
            .set("category", info.getCategory())
            .set("otherDescription", info.getOtherDescription())
            .set("passportFrontUrl", info.getPassportFrontUrl())
            .set("passportBackUrl", info.getPassportBackUrl())
            .set("updateTime", info.getUpdateTime())
            .set("updateUser", info.getUpdateUser()),
        UserWithdrawInfo.class);
  }

  @Override
  public List<UserWithdrawInfo> listByUserId(Long userId) {
    Query query = new Query();
    query.addCriteria(Criteria.where("userId").is(userId).and("del").is(Boolean.FALSE));
    query.with(Sort.by(Sort.Order.desc("createTime"), Sort.Order.desc("updateTime")));
    return mongoTemplate.find(query, UserWithdrawInfo.class);
  }

  @Override
  public List<UserWithdrawInfo> listPassByUserId(Long userId) {
    Query query = Query.query(Criteria.where("userId").is(userId)
            .and("status").is(ApprovalStatusEnum.PASS)
            .and("del").is(Boolean.FALSE))
        .with(Sort.by(Sort.Order.desc("createTime"), Sort.Order.desc("updateTime")));
    return mongoTemplate.find(query, UserWithdrawInfo.class);
  }

  @Override
  public void deleteByIdByUserId(Long id, Long userId, Long currentUidLong) {
    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id).and("userId").is(userId)),
        new Update()
            .set("del", Boolean.TRUE)
            .set("updateUser", currentUidLong)
            .set("updateTime", TimestampUtils.now()),
        UserWithdrawInfo.class);
  }

  @Override
  public void use(Long id, Long userId, Long currentUidLong) {
    Query query = new Query();
    query.addCriteria(
        Criteria.where("id").is(id).and("userId").is(userId).and("del").is(Boolean.FALSE));
    UserWithdrawInfo userWithdrawInfo = mongoTemplate.findOne(query, UserWithdrawInfo.class);
    if (Objects.isNull(userWithdrawInfo)) {
      return;
    }
    // 将该用户所有提现信息设置为未使用
    mongoTemplate.updateMulti(Query.query(Criteria.where("userId").is(userWithdrawInfo.getUserId())),
        new Update()
            .set("use", Boolean.FALSE)
            .set("updateUser", currentUidLong)
            .set("updateTime", TimestampUtils.now()),
        UserWithdrawInfo.class);

    // 将当前提现信息设置为使用
    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("updateUser", currentUidLong)
            .set("updateTime", TimestampUtils.now())
            .set("use", Boolean.TRUE),
        UserWithdrawInfo.class);
  }

  @Override
  public UserWithdrawInfo getOne(Long userId, String category) {
    Query query = new Query();
    query.addCriteria(Criteria.where("userId").is(userId)
        .and("category").is(category));
    return mongoTemplate.findOne(query, UserWithdrawInfo.class);
  }

  @Override
  public void removeBatchByUserId(List<Long> userIds) {
    mongoTemplate.remove(Query.query(Criteria.where("userId").in(userIds)), UserWithdrawInfo.class);
  }

  @Override
  public void pass(Set<Long> ids, Long currentUidLong) {
    mongoTemplate.updateMulti(Query.query(Criteria.where("id").in(ids)),
        new Update()
            .set("updateUser", currentUidLong)
            .set("updateTime", TimestampUtils.now())
            .set("status", ApprovalStatusEnum.PASS.name()),
        UserWithdrawInfo.class);
  }

  @Override
  public void notPass(Set<Long> ids, Long currentUidLong) {
    mongoTemplate.updateMulti(Query.query(Criteria.where("id").in(ids)),
        new Update()
            .set("use", Boolean.FALSE)
            .set("updateUser", currentUidLong)
            .set("updateTime", TimestampUtils.now())
            .set("status", ApprovalStatusEnum.NOT_PASS.name()),
        UserWithdrawInfo.class);
  }

  @Override
  public PageResult<UserWithdrawInfo> pageQuery(UserWithdrawInfoBackQryCmd query) {
    Criteria criteria = Criteria.where("sysOrigin").is(query.getSysOrigin())
        .and("status").is(query.getStatus()).and("del").is(Boolean.FALSE);

    if (Objects.nonNull(query.getUserId())) {
      criteria.and("userId").is(query.getUserId());
    }

    if (StringUtils.isNotBlank(query.getCategory())) {
      criteria.and("category").is(query.getCategory());
    }

    return mongoPageHelper.query(new Query(criteria),
        UserWithdrawInfo.class,
        query.getPageQuery().getLimit(),
        query.getPageQuery().getCursor(),
        Sort.Order.desc("createTime"));
  }

  @Override
  public Map<Long, UserWithdrawInfo> mapByIds(Set<Long> ids) {
    if (CollectionUtils.isEmpty(ids)) {
      return Maps.newHashMap();
    }

    List<UserWithdrawInfo> infos = mongoTemplate.find(Query.query(Criteria.where("id").in(ids)),
        UserWithdrawInfo.class);

    if (CollectionUtils.isEmpty(infos)) {
      return Maps.newHashMap();
    }

    return infos.stream().collect(Collectors.toMap(UserWithdrawInfo::getId, v -> v));
  }

}
