package com.game.business.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.game.business.domain.*;
import com.game.business.mapper.AppUserCountMapper;
import com.game.business.service.*;
import com.game.common.constant.CacheConstants;
import com.game.common.constant.finance.FinTranType1;
import com.game.common.constant.finance.FinTranType3;
import com.game.common.core.redis.RedisCache;
import com.game.common.entity.KeyValue;
import com.game.common.utils.DateUtils;
import com.game.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.Date;

@Service
public class AppUserCountServiceImpl extends ServiceImpl<AppUserCountMapper, AppUserCount> implements IAppUserCountService {

    @Autowired
    private AppUserCountMapper appUserCountMapper;

    @Autowired
    private IAppUserService appUserService;

    @Autowired
    private IAppUsersChargeService appUsersChargeService;

    @Autowired
    private IAppUsersCashrecordService appUsersCashrecordService;

    @Autowired
    private IFinTranRecordService finTranRecordService;

    @Autowired
    private IAppUserLiveDividedRecordService appUserLiveDividedRecordService;

    @Autowired
    private IAppUserGameRecordCountService appUserGameRecordCountService;

    @Autowired
    private IAppGameBettingService appGameBettingService;

    @Autowired
    private IAppUserCountDividendService appUserCountDividendService;

    @Autowired
    private IAppUserAgentService appUserAgentService;

    @Autowired
    private RedisCache redisCache;

    @Override
    public List<AppUserCount> getAppUserCount(long userId,String beginTime,String endTIme) {
        LambdaQueryWrapper<AppUserCount> queryWrapper = new LambdaQueryWrapper<AppUserCount>();
        queryWrapper.between(AppUserCount::getStrDate,beginTime,endTIme);
        queryWrapper.eq(AppUserCount::getAgentUserId,userId);
        return appUserCountMapper.selectList(queryWrapper);
    }

    @Override
    public List<AppUserCount> getAppUserCountNew(long userId, String beginTime, String endTIme) {
        return appUserCountMapper.selectTeamUserCount(userId,beginTime,endTIme);
    }

    @Override
//    @Async
    @Transactional
    public void createAppUserCount(AppUserCount appUserCount) {
        synchronized ("app_user_count_".concat(String.valueOf(appUserCount.getUserId()))) {
            //查询当前用户当日是否已经生成记录
            LambdaQueryWrapper<AppUserCount> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AppUserCount::getStrDate, appUserCount.getStrDate());
            queryWrapper.eq(AppUserCount::getUserId, appUserCount.getUserId());
            AppUserCount userCount = appUserCountMapper.selectOne(queryWrapper);
            int res = 0;
            if (userCount == null) {
                appUserCount.setCreateTime(new Date());
                appUserCount.setUpdateTime(new Date());
                res = appUserCountMapper.insert(appUserCount);
            } else {
                appUserCount.setId(userCount.getId());
                /*if(null == appUserCount.getUpdateTime()) {
                    appUserCount.setUpdateTime(new Date());
                }*/
                if (!appUserCount.isUpdate()) {
                    //非全量更新
                    if (appUserCount.getRechargeAmount() != null) {
                        appUserCount.setRechargeAmount(userCount.getRechargeAmount() + appUserCount.getRechargeAmount());
                    }
                    if (appUserCount.getRechargeCommission() != null) {
                        appUserCount.setRechargeCommission(userCount.getRechargeCommission() + appUserCount.getRechargeCommission());
                    }
                    if (appUserCount.getRechargeGive() != null) {
                        appUserCount.setRechargeGive(userCount.getRechargeGive() + appUserCount.getRechargeGive());
                    }
                    if (appUserCount.getWithdrawalCommission() != null) {
                        appUserCount.setWithdrawalAmount(userCount.getWithdrawalAmount() + appUserCount.getWithdrawalAmount());
                    }
                    if (appUserCount.getWithdrawalCommission() != null) {
                        appUserCount.setWithdrawalCommission(userCount.getWithdrawalCommission() + appUserCount.getWithdrawalCommission());
                    }
                    if (appUserCount.getLiveUseAmount() != null) {
                        appUserCount.setLiveUseAmount(userCount.getLiveUseAmount() + appUserCount.getLiveUseAmount());
                    }
                    if (appUserCount.getLiveCommission() != null) {
                        appUserCount.setLiveCommission(userCount.getLiveCommission() + appUserCount.getLiveCommission());
                    }
                    if (appUserCount.getGameWinAmount() != null) {
                        appUserCount.setGameWinAmount(userCount.getGameWinAmount() + appUserCount.getGameWinAmount());
                    }
                    if (appUserCount.getGameLoseAmount() != null) {
                        appUserCount.setGameLoseAmount(userCount.getGameLoseAmount() + appUserCount.getGameLoseAmount());
                    }
                    if (appUserCount.getGameCommission() != null) {
                        appUserCount.setGameCommission(userCount.getGameCommission() + appUserCount.getGameCommission());
                    }
                    if (appUserCount.getGameBetting() != null) {
                        appUserCount.setGameBetting(userCount.getGameBetting() + appUserCount.getGameBetting());
                    }
                    if (appUserCount.getLiveBettingCommission() != null) {
                        appUserCount.setLiveBettingCommission(userCount.getLiveBettingCommission() + appUserCount.getLiveBettingCommission());
                    }
                    if (appUserCount.getLiveInvite() != null) {
                        appUserCount.setLiveInvite(userCount.getLiveInvite() + appUserCount.getLiveInvite());
                    }
                    if (appUserCount.getLiveProfit() != null) {
                        appUserCount.setLiveProfit(userCount.getLiveProfit() + appUserCount.getLiveProfit());
                    }
                }
                res = appUserCountMapper.updateById(appUserCount);
            }
        }
    }

    @Override
    public void staticsUserCount(Long gameId,String dateTime,String gameDate) {
        Date curDate = DateUtils.getNowDate();
        if (StringUtils.isNotBlank(dateTime)) {
            curDate = DateUtil.parse(dateTime, "yyyy-MM-dd");
        } else {
            dateTime = DateUtils.parseDateToStr("yyyy-MM-dd", curDate);
        }

        /*Date lastDate = this.selectLastUpdateDate();
        String lastDateStr = DateUtil.format(lastDate,"yyyy-MM-dd HH:mm:ss");
        if(!dateTime.equals(DateUtil.format(lastDate,"yyyy-MM-dd"))){
            lastDateStr = DateUtil.format(curDate, "yyyy-MM-dd").concat(" 00:00:00");
        }
        String endTimeStr = DateUtil.format(curDate,"yyyy-MM-dd HH:mm:ss");*/
        List<AppGameBetting> gameBettingList = appGameBettingService.selectListByDate(null, null, null,gameId,gameDate);
        if (null != gameBettingList && gameBettingList.size() > 0) {
            String finalDateTime = dateTime;
            Date finalCurDate = curDate;
            List<Long> userIds = gameBettingList.stream().map(AppGameBetting::getUserId).distinct().collect(Collectors.toList());
            userIds.forEach(userId -> {
                AppUserAgent appUserAgent = appUserAgentService.selectInfo(userId);
                if(null != appUserAgent) {
                    AppUserCount appUserCount = new AppUserCount();
                    appUserCount.setUserId(userId);
                    appUserCount.setStrDate(finalDateTime);
                    appUserCount.setAgentUserId(appUserAgent.getPid());
                    appUserCount.setUpdateTime(finalCurDate);
                    //游戏输
                    appUserCount.setGameLoseAmount(gameBettingList.stream().filter(
                            e -> e.getUserId().equals(userId) && e.getIsWinning().intValue() == 2
                    ).mapToDouble(e ->
                            e.getBettingAmount()
                    ).sum());
                    //游戏赢
                    appUserCount.setGameWinAmount(gameBettingList.stream().filter(
                            e -> e.getUserId().equals(userId) && e.getIsWinning().intValue() == 1
                    ).mapToDouble(e ->
                            e.getBettingAmount() * e.getBettingMultiple()
                    ).sum());
                    this.createAppUserCount(appUserCount);
                }
            });
            //更新周盈亏数据
            appUserCountDividendService.reloadCache(null,userIds);
        }
    }

    @Override
    public Date selectLastUpdateDate() {
        LambdaQueryWrapper<AppUserCount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(AppUserCount::getUpdateTime);
        queryWrapper.last("limit 1");
        AppUserCount appUserCount = appUserCountMapper.selectOne(queryWrapper);
        if(null == appUserCount || null == appUserCount.getUpdateTime()) {
            return DateUtil.beginOfDay(DateUtils.getNowDate());
        }
        return DateUtil.offsetSecond(appUserCount.getUpdateTime(), 1);  //往前加1秒用于增量更新
    }

    /**
     * 查询最后更新时间
     * */
    @Override
    public Date selectLastDate() {
       LambdaQueryWrapper<AppUserCount> queryWrapper = new LambdaQueryWrapper<>();
       queryWrapper.orderByDesc(AppUserCount::getCountTime);
       queryWrapper.last("limit 1");
       AppUserCount appUserCount = appUserCountMapper.selectOne(queryWrapper);
       if(null == appUserCount || null == appUserCount.getCountTime()) {
           return DateUtil.beginOfDay(DateUtils.getNowDate());
       }
       return DateUtil.offsetSecond(appUserCount.getCountTime(), 1);  //往前加1秒用于增量更新
    }

    /**
     * 查询最后更新时间
     * */
    @Override
    public Date selectGameLastDate(Long userId) {
       LambdaQueryWrapper<AppUserCount> queryWrapper = new LambdaQueryWrapper<>();
       queryWrapper.orderByDesc(AppUserCount::getGameCountTime);
       queryWrapper.eq(AppUserCount::getUserId,userId);
       queryWrapper.last("limit 1");
       AppUserCount appUserCount = appUserCountMapper.selectOne(queryWrapper);
       if(null == appUserCount || null == appUserCount.getGameCountTime()) {
           return DateUtil.beginOfDay(DateUtils.getNowDate());
       }
       return appUserCount.getGameCountTime();  //往前加1秒用于增量更新
    }

    @Override
    public void staticsUserBetting(AppGameBetting appGameBetting,List<AppUserGameRecordCount>  recordCountList) {
//        synchronized (CacheConstants.USER_GAME_RECORD_COUNT.concat(String.valueOf(appGameBetting.getGameId())).concat(appGameBetting.getGameDate())) {
            Date curDate = DateUtils.getNowDate();
            String dateTime = DateUtils.parseDateToStr("yyyy-MM-dd", curDate);
    /*List<Long> userIds = gameRateList.stream().map(AppGameCommission::getUserId).collect(Collectors.toList());
                    userIds.add(appGameBetting.getUserId());
                    userIds = userIds.stream().distinct().collect(Collectors.toList());*/
            //        List<AppUserGameRecordCount> gameRecordCountList = appUserGameRecordCountService.selectByDate(null, null, null,appGameBetting.getGameId(),appGameBetting.getGameDate());

            if (null != recordCountList && recordCountList.size() > 0) {

                String finalDateTime = dateTime;
                Date finalCurDate = curDate;
                List<Long> userIds = new ArrayList<>();
                recordCountList.forEach(gameRate -> {
                    Long userId = gameRate.getUserId();
                    /*//用户最后一次更新时间
                    Date updateTime = this.selectGameLastDate(userId);
                    if (!DateUtil.format(updateTime, "yyyy-MM-dd").equals(DateUtil.format(finalCurDate, "yyyy-MM-dd"))) {
                        //跨天直接从当日零点开始统计
                        updateTime = DateUtil.beginOfDay(finalCurDate);
                    }*/
                    //查询用户返佣
//                    List<AppUserGameRecordCount> gameRecordCountList = appUserGameRecordCountService.selectByDate(userId, DateUtil.format(updateTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(finalCurDate, "yyyy-MM-dd HH:mm:ss"), gameRate.getGameId(), appGameBetting.getGameDate());
                    userIds.add(userId);
                    AppUserCount appUserCount = new AppUserCount();
                    appUserCount.setUserId(userId);
                    appUserCount.setStrDate(finalDateTime);
                    appUserCount.setAgentUserId(gameRate.getPid());
                    appUserCount.setUpdateTime(finalCurDate);
                    appUserCount.setGameCountTime(finalCurDate);
//                    if (null != gameRecordCountList && gameRecordCountList.size() > 0) {
                        //游戏佣金
                        /*Map<String, Double> map = redisCache.getCacheMap(CacheConstants.USER_GAME_RECORD_COUNT.concat(String.valueOf(userId)));
                        appUserCount.setGameCommission(gameRecordCountList.stream().filter(e -> {
                            return null == map || null == map.get(String.valueOf(e.getId())); //过滤已统计过的id
                        }).mapToDouble(e -> e.getCommission()).sum());
                        setGameCache(gameRecordCountList);*/
                    appUserCount.setGameCommission(gameRate.getCommission());
                    if(gameRate.getType().intValue() == 1){
                        appUserCount.setLiveBettingCommission(gameRate.getCommission());
                    }
//                    }
                    //游戏下注金额 更新当前下注用户 (非金币)
                    if (userId.equals(appGameBetting.getUserId()) && appGameBetting.getBettingType().intValue() == 0) {
                        appUserCount.setGameBetting(appGameBetting.getBettingAmount());
                    }
                    this.createAppUserCount(appUserCount);
                });
                //更新周盈亏数据
                appUserCountDividendService.reloadCache(null, userIds);
            }
//        }
    }

    @Override
    public List<AppUserCount> getListByUserId(long userId, String beginTime, String endTIme) {
        LambdaQueryWrapper<AppUserCount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AppUserCount::getUserId, userId);
        if(StringUtils.isNotBlank(beginTime)){
            queryWrapper.ge(AppUserCount::getStrDate,beginTime);
        }
        if(StringUtils.isNotBlank(endTIme)){
            queryWrapper.le(AppUserCount::getStrDate,endTIme);
        }
        return appUserCountMapper.selectList(queryWrapper);
    }

    @Override
    public void setGameCache(List<AppUserGameRecordCount> gameRecordCountList) {
        if(null != gameRecordCountList && gameRecordCountList.size() > 0) {
            gameRecordCountList.forEach(e->{
                //凌晨定时任务清除前一天的数据
                redisCache.setCacheMapValue(CacheConstants.USER_GAME_RECORD_COUNT.concat(String.valueOf(e.getUserId())),String.valueOf(e.getId()),e.getCommission());
            });
        }
    }

    /**
     * 金额为负数则转为正数
     * */
    private double dealMoney(double money){
        return money<0?money*-1:money;
    }



}
