package com.red.circle.wallet.infra.database.rds.service.freight.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.framework.mybatis.mybatisplus.LambdaQueryWrapperChain;
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
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.rds.dao.FreightBalanceRunningWaterDAO;
import com.red.circle.wallet.infra.database.rds.entity.freight.FreightBalanceRunningWater;
import com.red.circle.wallet.infra.database.rds.service.freight.FreightBalanceRunningWaterService;
import com.red.circle.wallet.inner.model.cmd.UserFreightBalanceRunningWaterExportQryCmd;
import com.red.circle.wallet.inner.model.cmd.UserFreightBalanceRunningWaterPageQryCmd;
import com.red.circle.wallet.inner.model.cmd.UserFreightSellerRunningWaterPageQryCmd;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

/**
 * <p>
 * 用户货运账户流水 服务实现类.
 * </p>
 *
 * @author pengshigang
 * @since 2021-07-06
 */
@Service
public class FreightBalanceRunningWaterServiceImpl extends
    BaseServiceImpl<FreightBalanceRunningWaterDAO, FreightBalanceRunningWater> implements
    FreightBalanceRunningWaterService {

  @Override
  public List<FreightBalanceRunningWater> flowByUserId(Long userId, Long acceptUserId, Integer type, Long lastId) {
      LambdaQueryWrapperChain<FreightBalanceRunningWater> query = query();
      if (type == null || type == 0) {
          query.eq(FreightBalanceRunningWater::getType, 0);
          query.and(e -> {
             e.eq(FreightBalanceRunningWater::getAcceptUserId, userId)
                     .eq(Objects.nonNull(acceptUserId), FreightBalanceRunningWater::getUserId, acceptUserId);
          });
      } else {
          query.eq(FreightBalanceRunningWater::getType, 1);
          query.and(e -> {
              e.eq(FreightBalanceRunningWater::getUserId, userId)
                      .eq(Objects.nonNull(acceptUserId), FreightBalanceRunningWater::getAcceptUserId, acceptUserId);
          });
      }
      return query.lt(Objects.nonNull(lastId), FreightBalanceRunningWater::getId, lastId)
              .orderByDesc(FreightBalanceRunningWater::getId)
              .last(PageConstant.DEFAULT_LIMIT)
              .list();
  }

  @Override
  public List<FreightBalanceRunningWater> flowBySellerId(Long sellerId, Long lastId) {
    return query()
        .eq(FreightBalanceRunningWater::getSellerId, sellerId)
        .lt(Objects.nonNull(lastId), FreightBalanceRunningWater::getId, lastId)
        .orderByDesc(FreightBalanceRunningWater::getId)
        .last(PageConstant.DEFAULT_LIMIT)
        .list();
  }


  @Override
  public void deleteByUserId(Long userId) {
    delete().eq(FreightBalanceRunningWater::getUserId, userId).execute();
  }

  @Override
  public List<FreightBalanceRunningWater> flowByUserIdAndDate(Long userId, Long lastId,
      String currentDate) {
    Timestamp starTime = TimestampUtils.now();
    Timestamp endTime = TimestampUtils.now();
    if (StringUtils.isNotBlank(currentDate)) {
      starTime = Timestamp.valueOf(currentDate + "-01 00:00:00");
      endTime = TimestampUtils.dateTimePlusDays(starTime, 30L);
    }
    return query()
        .eq(FreightBalanceRunningWater::getUserId, userId)
        .lt(Objects.nonNull(lastId), FreightBalanceRunningWater::getId, lastId)
        .between(StringUtils.isNotBlank(currentDate), FreightBalanceRunningWater::getCreateTime,
            starTime, endTime)
        .orderByDesc(FreightBalanceRunningWater::getId)
        .last(PageConstant.DEFAULT_LIMIT)
        .list();
  }

  @Override
  public PageResult<FreightBalanceRunningWater> pageRunningWater(
      UserFreightBalanceRunningWaterPageQryCmd query) {
    return query()
        .eq(StringUtils.isNotBlank(query.getSysOrigin()),
            FreightBalanceRunningWater::getSysOrigin, query.getSysOrigin())
        .and(Objects.nonNull(query.getUserId()),e -> {
          e.eq(FreightBalanceRunningWater::getUserId, query.getUserId())
              .or()
              .eq(FreightBalanceRunningWater::getAcceptUserId, query.getUserId());
        })
        .eq(Objects.nonNull(query.getAcceptUserId()),
            FreightBalanceRunningWater::getAcceptUserId, query.getAcceptUserId())
        .eq(StringUtils.isNotBlank(query.getOrigin()),
            FreightBalanceRunningWater::getOrigin, query.getOrigin())
        .ge(Objects.nonNull(query.getStartTime()),
            FreightBalanceRunningWater::getCreateTime, query.startTimeToLocalDateTime())
        .le(Objects.nonNull(query.getEndTime()),
            FreightBalanceRunningWater::getCreateTime, query.endTimeToLocalDateTime())
        .gt(Objects.equals(query.getQueryBackOperationUser(), true),
            FreightBalanceRunningWater::getUpdateUser, 0)
        .orderByDesc(FreightBalanceRunningWater::getCreateTime)
        .page(query.getPageQuery());
  }

  @Override
  public PageResult<FreightBalanceRunningWater> pageFreightSellerRunningWater(
      UserFreightSellerRunningWaterPageQryCmd query) {
    return query()
        .eq(Objects.nonNull(query.getSellerId()),
            FreightBalanceRunningWater::getSellerId, query.getSellerId())
        .orderByDesc(FreightBalanceRunningWater::getCreateTime)
        .page(query.getPageQuery());
  }


  @Override
  public List<FreightBalanceRunningWater> listExportBalanceRunningWater(
      UserFreightBalanceRunningWaterExportQryCmd query) {
    return query()
        .eq(FreightBalanceRunningWater::getSysOrigin, query.getSysOrigin())
        .apply("DATE_FORMAT(create_time,'%Y%m')={0}", query.getMonthDate())
        .list();
  }

  @Override
  public Map<Long, Long> countTransactionsByUserIds(Set<Long> userIds) {
    if (CollectionUtils.isEmpty(userIds)) {
      return new HashMap<>();
    }

    List<FreightBalanceRunningWater> list = query()
        .select(FreightBalanceRunningWater::getUserId)
        .in(FreightBalanceRunningWater::getUserId, userIds)
        .eq(FreightBalanceRunningWater::getType, 1)
        .list();
    return list.stream().collect(Collectors.groupingBy(FreightBalanceRunningWater::getUserId, Collectors.counting()));
  }

  @Override
  public BigDecimal sumAmountByCondition(Long userId, String startTime, String endTime, String rechargeType) {
    List<FreightBalanceRunningWater> list = query()
        .select(FreightBalanceRunningWater::getAmount)
        .eq(FreightBalanceRunningWater::getUserId, userId)
        .eq(Objects.nonNull(rechargeType), FreightBalanceRunningWater::getRechargeType, rechargeType)
        .apply(StringUtils.isNotBlank(startTime), "create_time >= {0}", startTime)
        .apply(StringUtils.isNotBlank(endTime), "create_time <= {0}", endTime)
        .list();
    
    return list.stream()
        .map(FreightBalanceRunningWater::getAmount)
        .filter(Objects::nonNull)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
  }
}
