package com.red.circle.game.fruit.infrastructure.database.repository.impl;

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.game.fruit.application.dto.clientobject.GameFruitUserBetRecordCO;
import com.red.circle.game.fruit.infrastructure.database.dao.GameFruitUserBetRecordDAO;
import com.red.circle.game.fruit.infrastructure.database.entity.GameFruitUserBetRecord;
import com.red.circle.game.fruit.infrastructure.database.repository.GameFruitUserBetRecordService;
import com.red.circle.game.fruit.inner.model.cmd.GameDataStatisticalCmd;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.DateUtils;
import java.math.BigDecimal;
import java.util.HashMap;
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 org.springframework.stereotype.Service;

/**
 * <p>
 * 用户每轮下注情况 服务实现类.
 * </p>
 *
 * @author lisizhe on 2023-11-30 19:18
 */
@Service
public class GameFruitUserBetRecordServiceImpl extends
    BaseServiceImpl<GameFruitUserBetRecordDAO, GameFruitUserBetRecord> implements
    GameFruitUserBetRecordService {

  @Override
  public BigDecimal getUserEarnings(Long userId, Long gameId) {
    return baseDAO.getUserEarnings(gameId, userId);
  }

  @Override
  public BigDecimal sumInvest(Long userId, Long gameId) {
    return baseDAO.sumInvest(gameId, userId);
  }

  @Override
  public List<GameFruitUserBetRecordCO> listUserBetByGameId(Long gameId, String sysOrigin) {
    return baseDAO.listUserBet(gameId, sysOrigin);
  }

  @Override
  public void addBetAmount(List<GameFruitUserBetRecord> list) {
    saveBatch(list);
  }

  @Override
  public void updateOrAddBetAmount(GameFruitUserBetRecord gameFruitUserBetRecord) {
    if (Objects.isNull(gameFruitUserBetRecord.getGameId()) || Objects.isNull(
        gameFruitUserBetRecord.getUserId()) ||
        Objects.isNull(gameFruitUserBetRecord.getPrizeId())) {
      ResponseAssert.failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR);
    }
    GameFruitUserBetRecord gameFruitUserBet = baseDAO.getByIdForUpdate(gameFruitUserBetRecord);
    if (Objects.nonNull(gameFruitUserBet)) {
      update().set(GameFruitUserBetRecord::getInvest,
              gameFruitUserBetRecord.getInvest().add(gameFruitUserBet.getInvest()))
          .set(GameFruitUserBetRecord::getUpdateTime, DateUtils.now())
          .eq(GameFruitUserBetRecord::getId, gameFruitUserBet.getId())
          .execute();
      return;
    }
    save(gameFruitUserBetRecord);
  }

  @Override
  public List<GameFruitUserBetRecord> listLotteryInfo(Long gameId, Set<Long> prizeIds) {
    return query().eq(GameFruitUserBetRecord::getGameId, gameId)
        .in(GameFruitUserBetRecord::getPrizeId, prizeIds).list();
  }

  @Override
  public void updateWinnerStatus(Long gameId, Set<Long> winnerIds, Set<Long> prizeIds) {
    update().set(GameFruitUserBetRecord::getWinner, 1)
        .eq(GameFruitUserBetRecord::getGameId, gameId)
        .eq(GameFruitUserBetRecord::getWinner, 0)
        .in(GameFruitUserBetRecord::getPrizeId, prizeIds)
        .in(GameFruitUserBetRecord::getUserId, winnerIds).execute();
  }

  @Override
  public List<GameFruitUserBetRecord> listLotteryUsers(Long gameId, Set<Long> userIds) {
    return query().eq(GameFruitUserBetRecord::getGameId, gameId)
        .in(GameFruitUserBetRecord::getUserId, userIds).list();
  }

  @Override
  public List<GameFruitUserBetRecord> listLotteryUser(Long gameId, Long userId) {
    return query().eq(GameFruitUserBetRecord::getGameId, gameId)
        .eq(GameFruitUserBetRecord::getUserId, userId).last(PageConstant.formatLimit(8)).list();
  }

  @Override
  public GameFruitUserBetRecord getLotteryInfo(Long prizeId, Long gameId, Long userId) {
    return query().eq(GameFruitUserBetRecord::getGameId, gameId)
        .eq(GameFruitUserBetRecord::getUserId, userId)
        .eq(GameFruitUserBetRecord::getPrizeId, prizeId).last(PageConstant.LIMIT_ONE).getOne();
  }

  @Override
  public Map<Long, List<GameFruitUserBetRecord>> gameFruitWinnerMapList(Long gameId, String sysOrigin) {
    return Optional.ofNullable(query().eq(GameFruitUserBetRecord::getGameId, gameId)
            .eq(GameFruitUserBetRecord::getSysOrigin, sysOrigin)
            .eq(GameFruitUserBetRecord::getWinner, 1)
            .list())
        .map(list -> list.stream().collect(Collectors.groupingBy(GameFruitUserBetRecord::getUserId))
        ).orElse(new HashMap<>());
  }

  @Override
  public Map<Long, List<GameFruitUserBetRecord>> gameFruitTransportMapList(Long gameId,
      Set<Long> userIds) {
    return Optional.ofNullable(query().eq(GameFruitUserBetRecord::getGameId, gameId)
            .notIn(CollectionUtils.isNotEmpty(userIds),GameFruitUserBetRecord::getUserId, userIds)
            .list())
        .map(list -> list.stream().collect(Collectors.groupingBy(GameFruitUserBetRecord::getUserId))
        ).orElse(new HashMap<>());
  }


  @Override
  public Set<Long> listBetGameId(Long lastId, Long userId) {
    return baseDAO.listUserBetRecord(lastId, userId);
  }

  @Override
  public Map<Long, List<GameFruitUserBetRecord>> listPlayersBetHistory(Set<Long> gameIds,
      Long userId) {
    if (CollectionUtils.isEmpty(gameIds)) {
      return CollectionUtils.newHashMap();
    }
    return Optional.ofNullable(query().eq(GameFruitUserBetRecord::getUserId, userId)
            .in(GameFruitUserBetRecord::getGameId, gameIds)
            .orderByDesc(GameFruitUserBetRecord::getId)
            .list())
        .map(
            list -> list.stream().collect(Collectors.groupingBy(GameFruitUserBetRecord::getGameId)))
        .orElse(new HashMap<>());
  }

  @Override
  public PageResult<GameFruitUserBetRecord> pageUserBetRecord(GameDataStatisticalCmd cmd) {
    return query()
        .eq(GameFruitUserBetRecord::getSysOrigin, cmd.getSysOrigin())
        .eq(Objects.nonNull(cmd.getUserId()), GameFruitUserBetRecord::getUserId, cmd.getUserId())
        .gt(GameFruitUserBetRecord::getUpdateTime, cmd.getStartTime())
        .lt(GameFruitUserBetRecord::getUpdateTime, cmd.getEndTime())
        .orderByDesc(GameFruitUserBetRecord::getId)
        .page(cmd.getPageQuery());
  }


  @Override
  public List<GameFruitUserBetRecord> listUserBetRecord(GameDataStatisticalCmd cmd,
      Integer isWinner) {
    return query()
        .eq(Objects.nonNull(cmd.getUserId()), GameFruitUserBetRecord::getUserId, cmd.getUserId())
        .eq(Objects.nonNull(isWinner), GameFruitUserBetRecord::getWinner, 1)
        .gt(GameFruitUserBetRecord::getUpdateTime, cmd.getStartTime())
        .lt(GameFruitUserBetRecord::getUpdateTime, cmd.getEndTime())
        .orderByDesc(GameFruitUserBetRecord::getId)
        .list();
  }
}
