package com.epai.front.service.dao;

import cn.lxz.sweb.encode.JsonEncoder;
import lombok.Getter;
import lombok.Setter;

import com.epai.front.contract.constant.RechargeOrderStatus;
import com.epai.front.contract.constant.ShopOrderStatus;
import com.epai.front.contract.model.PaymentObj;
import com.epai.front.contract.rpc.BaseResponse;
import com.epai.front.service.mapper.FrontPaymentMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author jihua.li
 * @Date 2017/4/21 17:01
 */
@Repository
public class PayDao {

    @Autowired
    FrontPaymentMapper frontPaymentMapper;

    private static final Logger log= LoggerFactory.getLogger(PayDao.class);

    public BaseResponse createShoppingOrder(PaymentObj paymentObj){
        BaseResponse response=new BaseResponse();
        PaymentObj temp=frontPaymentMapper.getPlayerShoppingRecordById(paymentObj.getPartnerOrderId());
        if(null!=temp){
            response.setState(4);
            response.setMsg("该购物单已存在,请重新分配购物单");
        }else{
            int row=frontPaymentMapper.savePlayerShoppingRecord(paymentObj);
            response.setState(row);
            response.setMsg("购物单保存成功");
        }
        return response;
    }

    @Transactional
    public BaseResponse updateShoppingOrderStatus(Map<String,Object> param){
        BaseResponse response=new BaseResponse();
        PaymentObj temp=frontPaymentMapper.getPlayerShoppingRecordById((String) param.get("partnerOrderId"));
        if(null!=temp&&param.get("onlyThirdId")!=null){
            log.info("第四方支付异步回调更新购物单第四方订单号了,请求更新的参数:{}",JsonEncoder.DEFAULT.encode(param));
            param.put("table","ly_shopping_sequence");
            frontPaymentMapper.onlyUpdateThirdOrderId(param);
            response.setState(1);
            response.setMsg("购物单第四方订单号更新成功!");
            return response;
        }
        log.info("以购物单号{}查询到的购物单{},此时的购物单状态为:{}",param.get("partnerOrderId"),temp,temp.getStatus());
        if(null!=temp&&temp.getStatus()!= ShopOrderStatus.HAS_SEND_GOODS.getValue()){//确保查询到库里的订单处于非 已发货状态
            //第一步:更新购物单的发货状态
            int row=frontPaymentMapper.updateShoppingRecordStatus(param);
            log.info("更新购物单号为{}的单据状态为:{}的返回的结果为:{}",param.get("partnerOrderId"),param.get("status"),row);
            int row2=0;
            if(row>0&&String.valueOf(ShopOrderStatus.HAS_SEND_GOODS.getValue()).equals(param.get("status").toString())){//保证状态更新成功并且这个状态是已发货
                if(null!=param.get("isNeedDeduction")&&"YES".equals(param.get("isNeedDeduction"))){
                    //分三步检查扣除玩家平台币
                    //第一步:检查扣除具体游戏的平台币
                    Object game_coin_reduce_amount=param.get("game_coin_reduce_amount");
                    if(null!=game_coin_reduce_amount&&!"0".equals(game_coin_reduce_amount.toString())&&Double.valueOf(game_coin_reduce_amount.toString())>0){
                        Map<String,Object> game_coin_param=new HashMap<>();
                        game_coin_param.put("amount",BigDecimal.ZERO.subtract(BigDecimal.valueOf(Double.valueOf(game_coin_reduce_amount.toString()))).doubleValue());
                        game_coin_param.put("uin",Integer.valueOf(param.get("uin").toString()));
                        game_coin_param.put("gameId",temp.getGameId());
                        int es=frontPaymentMapper.updateUserGameCoin(game_coin_param);
                        if(es<=0){
                        	throw new RuntimeException("使用参数:{"+JsonEncoder.DEFAULT.encode(game_coin_param)+"}更新用户具体游戏平台币返回值了:{"+es+"},将要回滚事务了");
                        }
                        game_coin_param.put("rebate_amount",BigDecimal.ZERO.subtract(BigDecimal.valueOf(Double.valueOf(game_coin_reduce_amount.toString()))).doubleValue());
                        game_coin_param.put("reason","平台币购物,支付API扣除用户在充值游戏下的平台币");
                        game_coin_param.put("channelId",temp.getChannelId());
                        game_coin_param.put("operator","支付API");
                        frontPaymentMapper.savePlayerPlatformCoinChangeLog(game_coin_param);
                    }
                    //第二步:检查扣除返利游戏圈的平台币
                    Object  activity_coin_reduce_amount=param.get("activity_coin_reduce_amount");
                    Object  activityCoin=param.get("activityCoin");
                    if(null!=activity_coin_reduce_amount&&null!=activityCoin&&Double.valueOf(activity_coin_reduce_amount.toString())>0&&Double.valueOf(activityCoin.toString())>0){
                        Map<String,Object> activity_coin_param=new HashMap<>();
                        activity_coin_param.put("uin",Integer.valueOf(param.get("uin").toString()));
                        activity_coin_param.put("partnerOrderId",temp.getPartnerOrderId());
                        activity_coin_param.put("amount",Double.valueOf(activity_coin_reduce_amount.toString()));
                        frontPaymentMapper.savePlayerRebateCoinConsumeLog(activity_coin_param);
                        activity_coin_param.put("rebate_amount",BigDecimal.ZERO.subtract(BigDecimal.valueOf(Double.valueOf(activity_coin_reduce_amount.toString()))).doubleValue());
                        activity_coin_param.put("reason","平台币购物,支付API扣除用户邀请好友返利获得的平台币");
                        activity_coin_param.put("channelId",temp.getChannelId());
                        activity_coin_param.put("operator","支付API");
                        frontPaymentMapper.savePlayerPlatformCoinChangeLog(activity_coin_param);
                    }
                    //第三步:检查扣除玩家公共的平台币
                    Object global_coin_reduce_amount=param.get("global_coin_reduce_amount");
                    if(null!=global_coin_reduce_amount&&Double.valueOf(global_coin_reduce_amount.toString())>0){
                        Map<String,Object> global_coin_param=new HashMap<>();
                        global_coin_param.put("amount",BigDecimal.ZERO.subtract(BigDecimal.valueOf(Double.valueOf(global_coin_reduce_amount.toString()))).doubleValue());
                        global_coin_param.put("uin",Integer.valueOf(param.get("uin").toString()));
                        global_coin_param.put("gameId",temp.getGameId());
                        int er=frontPaymentMapper.updatePlayerPlatformCoin(global_coin_param);
                        if(er<=0){
                        	throw new RuntimeException("使用参数:{"+JsonEncoder.DEFAULT.encode(global_coin_param)+"}更新用户全局游戏平台币返回值了:{"+er+"},将要回滚事务了");
                        }
                        global_coin_param.put("rebate_amount",BigDecimal.ZERO.subtract(BigDecimal.valueOf(Double.valueOf(global_coin_reduce_amount.toString()))).doubleValue());
                        global_coin_param.put("reason","平台币购物,支付API扣除用户系统通用平台币");
                        global_coin_param.put("channelId",temp.getChannelId());
                        global_coin_param.put("operator","支付API");
                        frontPaymentMapper.savePlayerPlatformCoinChangeLog(global_coin_param);
                    }
                    row2=1;
                }else{
                    row2=1;
                }
            }
            int tranRes=row+row2;
            response.setState(tranRes==2?1:0);
            response.setMsg(tranRes==2?"事物性的购物单状态更新成功!":"事物性的购物单状态没有全部更新!");
        }else{
            response.setState(0);
            response.setMsg(null==temp?"该购物单数据不存在":"该购物单状态之前已更新过了");
        }
        return response;
    }

    public BaseResponse createRechargeOrder(PaymentObj paymentObj){
        BaseResponse response=new BaseResponse();
        PaymentObj temp=frontPaymentMapper.getPlayerRechargeRecordById(paymentObj.getPartnerOrderId());
        if(null!=temp){
            response.setState(4);
            response.setMsg("该充值单已存在,请重新分配充值单");
        }else{
            int row=frontPaymentMapper.savePlayerRechargeRecord(paymentObj);
            response.setState(row);
            response.setMsg("充值单保存成功");
        }
        return response;
    }

    @Transactional
    public BaseResponse updateRechargeOrderStatus(Map<String,Object> param){
        BaseResponse response=new BaseResponse();
        PaymentObj temp=frontPaymentMapper.getPlayerRechargeRecordById((String) param.get("partnerOrderId"));
        if(null!=temp&&param.get("onlyThirdId")!=null){
            log.info("第四方支付异步回调更新充值单第四方订单号了,请求更新的参数:{}",JsonEncoder.DEFAULT.encode(param));
            param.put("table","ly_recharge_sequence");
            frontPaymentMapper.onlyUpdateThirdOrderId(param);
            response.setState(1);
            response.setMsg("充值单第四方订单号更新成功!");
            return response;
        }
        log.info("以充值单号{}查询到的充值单为{},此时的充值单状态为{}",param.get("partnerOrderId"),JsonEncoder.DEFAULT.encode(temp),temp.getStatus());
        if(null!=temp&&temp.getStatus()!= RechargeOrderStatus.RECHARGE_SUCCESS.getValue()){
              param.put("channelId",temp.getChannelId());
              param.put("gameId",temp.getGameId());
              param.put("uin",temp.getUin());
             //第一步:更新充值单的状态
              int row1=frontPaymentMapper.updateRechargeRecordStatus(param);
              log.info("更新充值单号{}的状态为{}的返回的结果为:{}",param.get("partnerOrderId"),param.get("status"),row1);
              if(row1>0){
            	  this.doRebateAction(temp.getUin(),temp.getGameId(),BigDecimal.valueOf(Integer.valueOf(param.get("amount").toString())).divide(BigDecimal.valueOf(100)).intValue(),temp);
              }
              int row2=0,row3=0,row4=0,row5=0,row6=0;
              if(row1>0&&String.valueOf(RechargeOrderStatus.RECHARGE_SUCCESS.getValue()).equals(param.get("status").toString())){
                   Map<String,Integer> updateParam=new HashMap<>();
                  //第二步:更新当天的充值总金额
                    updateParam.put("rechargeDate",Integer.valueOf(param.get("rechargeDate").toString()));
                    updateParam.put("amount",Integer.valueOf(param.get("amount").toString()));
                    int todayDateExist=frontPaymentMapper.checkTodayDateRecordExist(updateParam);
                    if(todayDateExist>0){
                        row2=frontPaymentMapper.updateTodayDateRecord(updateParam);
                        log.info("当天{}的累计金额记录已存在,更新累计金额了{},更新返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row2);
                    }else{
                        row2=frontPaymentMapper.saveTodayDateRecord(updateParam);
                        log.info("当天{}的累计金额记录不存在,保存累计金额了{},保存返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row2);
                    }

                   updateParam.put("uin",Integer.valueOf(param.get("uin").toString()));
                   Map<String,Object> tempUpdateParam=new HashMap<>();
                   tempUpdateParam.put("rechargeDate",updateParam.get("rechargeDate"));
                   tempUpdateParam.put("amount",BigDecimal.valueOf(updateParam.get("amount")).divide(BigDecimal.valueOf(100)).intValue());
                   tempUpdateParam.put("uin",updateParam.get("uin"));
                   tempUpdateParam.put("gameId",temp.getGameId());
                  //第二步:更新当前用户充值游戏的平台币
                   if(temp.getGameId()>0){
                       int checkCount=frontPaymentMapper.checkUserGameCoinExist(tempUpdateParam);
                       if(checkCount>0){//已经存在了,直接更新
                           row3=frontPaymentMapper.updateUserGameCoin(tempUpdateParam);
                       }else{//不存在,直接插入一条
                           row3=frontPaymentMapper.saveUserGameCoin(tempUpdateParam);
                       }
                   }else{
                       row3=frontPaymentMapper.updatePlayerPlatformCoin(tempUpdateParam);
                   }
                    log.info("更新用户的平台币了{},返回的结果为{}",JsonEncoder.DEFAULT.encode(tempUpdateParam),row3);
                  //第三步:更新当前用户当天的累计充值金额
                    int todayPlayerExist=frontPaymentMapper.checkTodayPlayerRecordExist(updateParam);
                    if(todayPlayerExist>0){
                       row4=frontPaymentMapper.updateTodayPlayerRecord(updateParam);
                        log.info("当天{}用户的累计金额记录已存在,更新累计金额了{},更新返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row4);
                    }else{
                       row4=frontPaymentMapper.saveTodayPlayerRecord(updateParam);
                       log.info("当天{}用户的累计金额记录不存在,保存累计金额了{},保存返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row4);
                   }
                  //第四步:更新当前游戏当天的累计充值金额
                    updateParam.put("gameId",Integer.valueOf(param.get("gameId").toString()));
                    if(temp.getGameId()>0){
                        int todayGameExist=frontPaymentMapper.checkTodayGameRecordExist(updateParam);
                        if(todayGameExist>0){
                            row5=frontPaymentMapper.updateTodayGameRecord(updateParam);
                            log.info("当天{}游戏的累计金额记录已存在,更新累计金额了{},更新返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row5);
                        }else{
                            row5=frontPaymentMapper.saveTodayGameRecord(updateParam);
                            log.info("当天{}游戏的累计金额记录不存在,保存累计金额了{},保存返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row5);
                        }
                    }else{
                        row5=1;
                    }
                  //第五步:如果该用户有渠道所属,则更新所属渠道当天的累计充值金额
                   if(null!=param.get("channelId")&&!"0".equals(param.get("channelId"))){
                         updateParam.put("channelId",Integer.valueOf(param.get("channelId").toString()));
                         int todayChannelExist=frontPaymentMapper.checkTodayChannelRecordExist(updateParam);
                         if(todayChannelExist>0){
                             row6=frontPaymentMapper.updateTodayChannelRecord(updateParam);
                             log.info("当天{}渠道的累计金额记录已存在,更新累计金额了{},更新返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row6);
                         }else{
                             row6=frontPaymentMapper.saveTodayChannelRecord(updateParam);
                             log.info("当天{}渠道的累计金额记录不存在,保存累计金额了{},保存返回的结果为{}",param.get("rechargeDate"),JsonEncoder.DEFAULT.encode(updateParam),row6);
                         }
                   }else{
                       row6=1;
                   }
              }
              int tranRes=row1+row2+row3+row4+row5+row6;
              response.setState(tranRes==6?1:0);
              response.setMsg(tranRes==6?"事物性的充值单状态更新成功!":"事物性的充值单状态没有全部更新!");
        }else{
            response.setState(0);
            response.setMsg(null==temp?"该充值单数据不存在":"该充值单状态之前已更新过了");
        }
        return response;
    }


    
    private void doRebateAction(int invited_uin,int game_id,int order_amount,PaymentObj order){
    	try{
    		  log.info("来检查玩家{}是否被邀请注册的",invited_uin);
    		  //1、检查充值的玩家invited_uin是否是被别人邀请注册的
    		  Map<String,Object> invitedInfo=frontPaymentMapper.getUserInvitiedInfo(invited_uin);
    		 if(!CollectionUtils.isEmpty(invitedInfo)){
    		   int uin=Integer.valueOf(invitedInfo.get("uin").toString());
    		   double player_total_rebate=Double.valueOf(invitedInfo.get("total_rebate_amount").toString());
    		  log.info("当前玩家被邀请的注册信息为:{}",JsonEncoder.DEFAULT.encode(invitedInfo));
    		  //2、获取当前的游戏活动圈信息,这里目前留出扩展,以后可以根据需要查询指定条件的游戏圈
    		   Map<String, Object> gameActivity=frontPaymentMapper.getGameActivity(new HashMap<>());
    		   if(!CollectionUtils.isEmpty(gameActivity)){
    			   log.info("当前系统创建的游戏圈信息为:{}",JsonEncoder.DEFAULT.encode(gameActivity));
    			   float rebateRation=0.1f;
    			   int maxRebateValue=100;
    			   if(null!=gameActivity.get("attr1")&&!"{}".equals(gameActivity.get("attr1").toString())){
    				   Attr attr1=JsonEncoder.DEFAULT.decode(gameActivity.get("attr1").toString(), Attr.class);
    				   rebateRation=changePercentToPoint(attr1.value);
    			   }
    			   if(null!=gameActivity.get("attr2")&&!"{}".equals(gameActivity.get("attr2").toString())){
    				   Attr attr2=JsonEncoder.DEFAULT.decode(gameActivity.get("attr2").toString(), Attr.class);
    				   maxRebateValue=Integer.valueOf(attr2.value);
    			   }
    			   log.info("计算得到的当前游戏圈的返利比率为:{},最高返利金额为:{}",rebateRation,maxRebateValue);
    			   //3、 获取参与当前返利活动的游戏信息
    			      int activityId=Integer.valueOf(gameActivity.get("id").toString());
    			      Map<String,Integer> param=new HashMap<>();
    			      param.put("activityId", activityId);
		    		  List<Map<String,Object>> rebateGameList=frontPaymentMapper.getAllRebateGame(param);
		    		  if(!CollectionUtils.isEmpty(rebateGameList)){
		    			  List<Integer> gameIds=rebateGameList.stream().map(map->Integer.parseInt(map.get("game_id").toString())).collect(Collectors.toList());
		    			  if(!CollectionUtils.isEmpty(gameIds)){
		    				  gameIds=gameIds.stream().filter(id->(null!=id&&id>0)).distinct().collect(Collectors.toList());
		    				  log.info("当前系统设置的参与充值返利活动的游戏ids:{}",gameIds.stream().map(id->String.valueOf(id)).collect(Collectors.joining(",")));
		    				  if(game_id>0){
		    					  if(gameIds.contains(game_id)){
		    						  this.doUpdate(uin, invited_uin, player_total_rebate, maxRebateValue, order_amount, rebateRation,order);
		    					  }else{
		    						  log.info("当前游戏{}不在返利活动设置的游戏圈内",game_id);
		    					  }
		    				  }else{
		    					  this.doUpdate(uin, invited_uin, player_total_rebate, maxRebateValue, order_amount, rebateRation,order);
		    				  }
		    			  }
		    		  }else{
		    			 log.info("当前游戏圈{}里没有设置任何游戏",activityId);
		    		  } 
    		   }else{
    			   log.info("当前系统没有创建任何游戏圈");
    		   }
    		}else{
    		  log.info("玩家{}不是被邀请注册的",invited_uin);
    		}
    	}catch (Exception e) {
    		log.error("执行邀请玩家游戏充值返利更新失败了",e);
		}
    }
    
    private void doUpdate(int uin,int invited_uin,double player_total_rebate,double max_rebate_value,int order_amount,float rebate_ration,PaymentObj order){
        double real_update_amount;
    	if(player_total_rebate<max_rebate_value){
    		double diff=max_rebate_value-player_total_rebate;
    		double real_rebate_amount=BigDecimal.valueOf(order_amount).multiply(BigDecimal.valueOf(rebate_ration)).divide(BigDecimal.ONE,2,RoundingMode.HALF_UP).doubleValue();
    		if(diff>=real_rebate_amount){
    			real_update_amount=real_rebate_amount;
    		}else{
                real_update_amount=diff;
            }
    		Map<String,Object> param=new HashMap<>();
    		param.put("amount", real_update_amount);
    		param.put("uin", uin);
    		param.put("invited_uin", invited_uin);
    	    int res=frontPaymentMapper.updateInvitationUserRebate(param);
    	    log.info("更新邀请玩家的平台币收益了,更新的参数为:{},返回的结果为:{}",JsonEncoder.DEFAULT.encode(param),res);
    	}else{
            real_update_amount=0d;
        }
    	this.saveInvitatedPlayerRechargeLog(uin,invited_uin,order,real_update_amount);
    }

    private void saveInvitatedPlayerRechargeLog(int uin,int invited_uin,PaymentObj order,double real_rebate_amount){
        try {
            log.info("将要保存用户邀请注册的玩家的充值记录了,uin:{},invited_uin:{},real_rebate_amount:{}",uin,invited_uin,real_rebate_amount);
            int fenCoin=BigDecimal.valueOf(real_rebate_amount).multiply(BigDecimal.valueOf(100)).intValue();
            Map<String,Object> param=new HashMap<>();
            param.put("uin",uin);
            param.put("invited_uin",invited_uin);
            param.put("game_id",order.getGameId());
            param.put("channel_id",order.getChannelId());
            param.put("partner_order_id",order.getPartnerOrderId());
            param.put("third_party_order_id",order.getThird_party_id());
            param.put("order_amount",order.getAmount());
            param.put("payway",order.getGateway());
            param.put("rebate_amount",fenCoin);//注意这里,为了保证金额的单位统一,这里需要将收益的平台币转化为 分的单位
            //先保存充值记录
            frontPaymentMapper.saveRebatePlayerRechargeLog(param);
            //再插入玩家平台币变更的记录
            if(fenCoin>0){
                param.put("gameId",-888);//这个只是为了标记本条记录是在充值返利圈游戏的时候返利修改的,没有具体的游戏存在
                int channelId=frontPaymentMapper.getPlayerChannelById(uin);
                param.put("channelId",channelId);//这个渠道是指实际邀请人的玩家注册的渠道,不能用订单上的渠道
                param.put("reason","邀请的下线玩家充值返利圈内游戏后返回的收益");
                param.put("operator","支付API");
                frontPaymentMapper.savePlayerPlatformCoinChangeLog(param);
            }
        }catch (Exception e){
            log.error("保存用户邀请注册的玩家的充值记录出错了",e);
        }
    }
    
    public PaymentObj getPaymentOrderByOrderId(String partnerOrderId,int operation){
    	if(operation==1){
    		return frontPaymentMapper.getPlayerShoppingRecordById(partnerOrderId);
    	}else{
    		return frontPaymentMapper.getPlayerRechargeRecordById(partnerOrderId);
    	}
    }
    
    private float changePercentToPoint(String percent) {
        return new Float(percent.substring(0, percent.indexOf("%"))) / 100;
    }
    
    @Getter
    @Setter
    public static class Attr implements Serializable{
		private String name;
		private String value;
    }

}
