package com.bizzan.bitrade.service;

import com.alibaba.fastjson.JSON;
import com.bizzan.bitrade.constant.BooleanEnum;
import com.bizzan.bitrade.constant.CertifiedBusinessStatus;
import com.bizzan.bitrade.constant.CommonStatus;
import com.bizzan.bitrade.constant.NotifyType;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.constant.RealNameStatus;
import com.bizzan.bitrade.dao.MemberDao;
import com.bizzan.bitrade.dao.MemberSignRecordDao;
import com.bizzan.bitrade.dao.MemberTransactionDao;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.exception.AuthenticationException;
import com.bizzan.bitrade.pagination.Criteria;
import com.bizzan.bitrade.pagination.PageResult;
import com.bizzan.bitrade.pagination.Restrictions;
import com.bizzan.bitrade.service.Base.BaseService;
import com.bizzan.bitrade.util.BigDecimalUtils;
import com.bizzan.bitrade.util.DESUtil;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.util.Md5;
import com.bizzan.bitrade.util.PredicateUtils;
import com.bizzan.bitrade.util.RedisManager;
import com.bizzan.bitrade.vendor.provider.support.EmailProvider;
import com.bizzan.bitrade.vo.MessageSendTradeNotice;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateNotFoundException;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import static com.bizzan.bitrade.constant.TransactionType.ACTIVITY_AWARD;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class MemberService extends BaseService {

    @Autowired
    private MemberDao memberDao;

    @Autowired
    private MemberSignRecordDao signRecordDao;

    @Value("${dev.mode.enabled:false}")
    private boolean devModeEnabled;

    @Autowired
    private MemberTransactionDao transactionDao;
    @Autowired
    private LocaleMessageSourceService messageSourceService;
	@Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    
    @Autowired
    private EmailProvider emailProvider;
    @Autowired
    private MemberWeightUpperService memberWeightUpperService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private RedisManager redisManager;
    /**
     * 条件查询对象 pageNo pageSize 同时传时分页
     *
     * @param booleanExpressionList
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Transactional(readOnly = true)
    public PageResult<Member> queryWhereOrPage(List<BooleanExpression> booleanExpressionList, Integer pageNo, Integer pageSize) {
        List<Member> list;
        JPAQuery<Member> jpaQuery = queryFactory.selectFrom(QMember.member)
                .where(booleanExpressionList.toArray(new BooleanExpression[booleanExpressionList.size()]));
        jpaQuery.orderBy(QMember.member.id.desc());
        if (pageNo != null && pageSize != null) {
            list = jpaQuery.offset((pageNo - 1) * pageSize).limit(pageSize).fetch();
        } else {
            list = jpaQuery.fetch();
        }
        return new PageResult<>(list, jpaQuery.fetchCount());
    }

    public Member save(Member member) {
        return memberDao.save(member);
    }

    public Member saveAndFlush(Member member) {
        return memberDao.saveAndFlush(member);
    }

    @Transactional(rollbackFor = Exception.class)
    public Member loginWithToken(String token, String ip, String device) {
        if (StringUtils.isBlank(token)) {
            return null;
        }
        //Member mr = memberDao.findMemberByTokenAndTokenExpireTimeAfter(token,new Date());
        Member mr = memberDao.findMemberByToken(token);
        return mr;
    }
    
    public Double statBalance(List<Long> ids) {
    	return 0.0;
    }

    public Member login(String username, String password) throws Exception {
        Member member = memberDao.findMemberByMobilePhoneOrEmail(username, username);
        if (member == null) {
            throw new AuthenticationException(messageSourceService.getMessage("USER_PASSWORD_ERROR"));
        } else if (!Md5.md5Digest(password + member.getSalt()).toLowerCase().equals(member.getPassword())) {
            throw new AuthenticationException(messageSourceService.getMessage("USER_PASSWORD_ERROR"));
        } else if (member.getStatus().equals(CommonStatus.ILLEGAL)) {
            throw new AuthenticationException(messageSourceService.getMessage("ACCOUNT_ACTIVATION_DISABLED"));
        }
        return member;
    }
    
    public Member findMemberByMobilePhoneOrEmail(String username) {
    	return memberDao.findMemberByMobilePhoneOrEmail(username, username);
    }
    
    public void updateExistingToken(String token) throws Exception {
    	memberDao.updateExistingToken(token);
    }

    /**
     * @author 
     * @description
     * @date 2019/12/25 18:42
     */
    public Member findOne(Long id) {
        return memberDao.findOne(id);
    }

    /**
     * @author 
     * @description 查询所有会员
     * @date 2019/12/25 18:43
     */
    @Override
    public List<Member> findAll() {
        return memberDao.findAll();
    }

    public List<Member> findPromotionMember(Long id) {
        return memberDao.findAllByInviterId(id);
    }
    
    public Page<Member> findPromotionMemberPage(Integer pageNo, Integer pageSize,Long id){
        Sort orders = Criteria.sortStatic("id");
        PageRequest pageRequest = new PageRequest(pageNo, pageSize, orders);

        Criteria<Member> specification = new Criteria<Member>();
        specification.add(Restrictions.eq("inviterId", id, false));
        return memberDao.findAll(specification, pageRequest);
    }

    /**
     * @author 
     * @description 分页
     * @date 2019/1/12 15:35
     */
    public Page<Member> page(Integer pageNo, Integer pageSize, CommonStatus status) {
        //排序方式 (需要倒序 这样    Criteria.sort("id","createTime.desc") ) //参数实体类为字段名
        Sort orders = Criteria.sortStatic("id");
        //分页参数
        PageRequest pageRequest = new PageRequest(pageNo, pageSize, orders);
        //查询条件
        Criteria<Member> specification = new Criteria<Member>();
        specification.add(Restrictions.eq("status", status, false));
        return memberDao.findAll(specification, pageRequest);
    }
    
    public Page<Member> findByPage(Integer pageNo, Integer pageSize) {
        //排序方式 (需要倒序 这样    Criteria.sort("id","createTime.desc") ) //参数实体类为字段名
        Sort orders = Criteria.sortStatic("id");
        //分页参数
        PageRequest pageRequest = new PageRequest(pageNo, pageSize, orders);
        //查询条件
        Criteria<Member> specification = new Criteria<Member>();
        return memberDao.findAll(specification, pageRequest);
    }
    
    public Page<Member> findAgentsByPage(Integer pageNo, Integer pageSize) {
        //排序方式 (需要倒序 这样    Criteria.sort("id","createTime.desc") ) //参数实体类为字段名
        Sort orders = Criteria.sortStatic("id");
        //分页参数
        PageRequest pageRequest = new PageRequest(pageNo, pageSize, orders);
        //查询条件
        Criteria<Member> specification = new Criteria<Member>();
        specification.add(Restrictions.eq("superPartner", "1", false));
        return memberDao.findAll(specification, pageRequest);
    }

    public boolean emailIsExist(String email) {
        List<Member> list = memberDao.getAllByEmailEquals(email);
        return list.size() > 0 ? true : false;
    }

    public boolean usernameIsExist(String username) {
        return memberDao.getAllByUsernameEquals(username).size() > 0 ? true : false;
    }

    public boolean phoneIsExist(String phone) {
        return memberDao.getAllByMobilePhoneEquals(phone).size() > 0 ? true : false;
    }

    public Member findByUsername(String username) {
        return memberDao.findByUsername(username);
    }

    public Member findByEmail(String email) {
        return memberDao.findMemberByEmail(email);
    }

    public Member findByPhone(String phone) {
        return memberDao.findMemberByMobilePhone(phone);
    }

    public Page<Member> findAll(Predicate predicate, Pageable pageable) {
        return memberDao.findAll(predicate, pageable);
    }

    public String findUserNameById(long id) {
        return memberDao.findUserNameById(id);
    }
    
    public Page<Member> findByInviterId(Long inviterId, Integer pageNo, Integer pageSize) {
    	ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
		booleanExpressions.add(QMember.member.inviterId.eq(inviterId));
		PageModel pageModel = new PageModel();
		pageModel.setPageNo(pageNo);
		pageModel.setPageSize(pageSize);
		Page<Member> members = findAll(PredicateUtils.getPredicate(booleanExpressions), pageModel.getPageable());
		return members;
    }

    //签到事件
    @Transactional(rollbackFor = Exception.class)
    public void signInIncident(Member member, Sign sign) {
        member.setSignInAbility(false);//失去签到能力
        //memberWallet.setBalance(BigDecimalUtils.add(memberWallet.getBalance(), sign.getAmount()));//签到收益

        // 签到记录
        signRecordDao.save(new MemberSignRecord(member, sign));
        
    }

    //重置会员签到
    public void resetSignIn() {
        memberDao.resetSignIn();
    }

    public void updateCertifiedBusinessStatusByIdList(List<Long> idList) {
        memberDao.updateCertifiedBusinessStatusByIdList(idList, CertifiedBusinessStatus.DEPOSIT_LESS);
    }

    /**
     * 判断验证码是否存在
     * @param promotion
     * @return
     */
    public boolean userPromotionCodeIsExist(String promotion) {
        return memberDao.getAllByPromotionCodeEquals(promotion).size() > 0 ? true : false;
    }
    
    public Long getMaxId() {
    	return memberDao.getMaxId();
    }

	public Member findMemberByPromotionCode(String code) {
		return memberDao.findMemberByPromotionCode(code);
	}

    public List<Member> findSuperPartnerMembersByIds(String uppers) {
        String[] idss = uppers.split(",");
        List<Long> ids = new ArrayList<>();
        for(String id:idss){
            ids.add(Long.parseLong(id));
        }
        return memberDao.findSuperPartnerMembersByIds(ids);
    }
    public List<Member> findAllByIds(String uppers) {
        String[] idss = uppers.split(",");
        List<Long> ids = new ArrayList<>();
        for(String id:idss){
            ids.add(Long.parseLong(id));
        }
        return memberDao.findAllByIds(ids);
    }

    public List<Member> findByInviterId(Long userId) {
        return memberDao.findByInviterId(userId);
    }
    
    public int countByInviterId(Long inviterId) {
    	return memberDao.countByInviterId(inviterId);
    }

    /**
     * 架构图直接下级超级代理商 ID（member_weight_upper.upper + inviter_id 取并集）
     */
    public List<Long> findDirectSuperAgentChildIds(Long upperId) {
        java.util.LinkedHashSet<Long> childIds = new java.util.LinkedHashSet<>();
        List<MemberWeightUpper> lowers = memberWeightUpperService.findAllByUpper(upperId);
        for (MemberWeightUpper lower : lowers) {
            Member member = findOne(lower.getMemberId());
            if (member != null && "1".equals(member.getSuperPartner())) {
                childIds.add(member.getId());
            }
        }
        List<Member> byInviter = memberDao.findAllByInviterId(upperId);
        for (Member member : byInviter) {
            if ("1".equals(member.getSuperPartner())) {
                childIds.add(member.getId());
            }
        }
        return new java.util.ArrayList<>(childIds);
    }

    public int countDirectSuperAgentByInviterId(Long inviterId) {
        return findDirectSuperAgentChildIds(inviterId).size();
    }

    public void updatePromotionCode(Long id, String promotionCode) {
        memberDao.updatePromotionCode(id,promotionCode);
    }
    
    public void updateSuperPartner(Long id, String superPartner) {
    	memberDao.updateSuperPartner(id, superPartner);
    }
    
    public void updateIsLock(Long id, int isLock) {
    	memberDao.updateIsLock(id, isLock);
    }
    
    public void resetGoogle(Long id) {
    	memberDao.resetGoogle(id);
    }
    
    public void updateIsTrader(Long id, int isTrader) {
    	memberDao.updateIsTrader(id, isTrader);
    }
    
    public void updateTransactionStatus(Long id, BooleanEnum transactionStatus) {
    	memberDao.updateTransactionStatus(id, transactionStatus == BooleanEnum.IS_TRUE?1:0);
    }
    
    public void updateIsMoneyLock(Long id, int isMoneyLock) {
    	memberDao.updateIsMoneyLock(id, isMoneyLock);
    }
    
    public void updateDisableReward(Long id, int disableReward) {
    	memberDao.updateDisableReward(id, disableReward);
    }
    
    public void updateIsService(Long id, int isService) {
    	memberDao.updateIsService(id, isService);
    }
    
    public void updateToken(Long id, String token) {
    	memberDao.updateToken(id, token);
    }
    
    public void kick(Member member) {
    	String token = DESUtil.mixup(member.getToken());
    	redisManager.removeSessionByMemberId(member.getId(), token);
    }
    
    public void updateAvatarAndNickname(Long id, String avatar, String nickname) {
    	memberDao.updateAvatarAndNickname(id, avatar, nickname);
    	redisManager.removeMemberInfo(id);
    }
    
    public boolean isTrader(Long id) {
    	Integer isTrader = memberDao.getIsTrader(id);
    	return isTrader!=null && isTrader>=1;
    }
    public boolean isSpecialTrader(Long id) {
    	Integer isTrader = memberDao.getIsTrader(id);
    	SysConfig config = sysConfigService.get();
    	return isTrader!=null && isTrader >= config.getSpecialTrader();
    }
    public Integer getTrader(Long id) {
    	Integer isTrader = memberDao.getIsTrader(id);
    	return isTrader;
    }
    public Member getSpecialTrader() {
    	SysConfig config = sysConfigService.get();
    	Member member = memberDao.findMemberByIsTrader(config.getSpecialTrader());
    	return member;
    }
    public List<Member> getSpecialTraders() {
    	SysConfig config = sysConfigService.get();
    	return memberDao.findSpecialTraders(config.getSpecialTrader());
    }
    
    public List<Member> getServices() {
    	return memberDao.findByIsService(1);
    }
    
    public boolean isBound(Long id) {
    	Member member = this.findOne(id);
    	return member!=null && !StringUtils.isEmpty(member.getMobilePhone()) && !StringUtils.isEmpty(member.getEmail());
    }
    public boolean isValidated(Long id) {
    	Member member = this.findOne(id);
    	return member!=null && !StringUtils.isEmpty(member.getName()) && member.getRealNameStatus().equals(RealNameStatus.VERIFIED);
    }
    
    public int countAll() {
    	return memberDao.countAll();
    }
    public int countByDate(String date) {
    	return memberDao.countByDate(date, date+" 23:59:59");
    }
    public int countByDateAndIds(String date, List<Long> ids) {
    	return memberDao.countByDateAndIds(date, date+" 23:59:59", ids);
    }
    
    public void notifyByEmail(Long id, NotifyType notifyType, JSONObject obj) {
    	// dev.mode.enabled=true 时为测试环境，跳过邮件发送
    	if (devModeEnabled) {
    		log.info("notifyByEmail skipped (dev.mode.enabled=true), type={}, memberId={}", notifyType, id);
    		return;
    	}
		Member member = this.findOne(id);
		if(StringUtils.isEmpty(member.getEmail()))
			return;
    	try {
    		MessageSendTradeNotice notice = new MessageSendTradeNotice();
    		notice.setMemberId(id);
    		notice.setMessageTitle(notifyType.getCnName());
    		notice.setMessageTypeId(3L);
    		String content = "";
    		
	    	Map<String, Object> model = new HashMap<>();
	    	SysConfig sysConfig = sysConfigService.get();
	    	model.put("projectName", sysConfig.getProjectName());
	    	model.put("projectLogo", sysConfig.getProjectLogo());
	    	String dateTime = DateUtil.getDateTime();
    		model.put("time", dateTime);
    		model.put("timewos", dateTime.substring(0,dateTime.length()-3));
    		model.put("email", member.getEmail());
	    	String templateName = "";
	    	if(notifyType == NotifyType.LOGIN) {
	    		model.put("ip", obj.getString("ip"));
	    		model.put("country", obj.getString("country"));
	    		model.put("province", obj.getString("province"));
	    		templateName = "login.ftl";
	    	} else if(notifyType == NotifyType.LOGIN_VALIDATE) {
	    		model.put("ip", obj.getString("ip"));
	    		model.put("country", obj.getString("country"));
	    		model.put("province", obj.getString("province"));
	    		model.put("code", obj.getString("code"));
	    		templateName = "loginValidate.ftl";
	    	} else if(notifyType == NotifyType.AGENT_VALIDATE) {
	    		model.put("code", obj.getString("code"));
	    		templateName = "agentValidate.ftl";
	    	} else if(notifyType == NotifyType.UPDATE_PASSWORD_VALIDATE) {
	    		model.put("code", obj.getString("code"));
	    		templateName = "updatePasswordCode.ftl";
	    	} else if(notifyType == NotifyType.RECHARGE) {
	    		model.put("unit", obj.get("unit"));
	    		model.put("amount", obj.get("amount"));
	    		//log.info("RECHARGE map={}", model);
	    		templateName = "recharge.ftl";
	    		content = "您充值"+obj.get("amount")+obj.get("unit")+"已到账。";
	    	} else if(notifyType == NotifyType.WITHDRAW) {
	    		model.put("unit", obj.get("unit"));
	    		model.put("orderId", obj.get("orderId"));
	    		model.put("amount", obj.get("arrivedAmount"));
	    		model.put("remark", obj.get("remark"));
	    		model.put("address", obj.get("address"));
	    		model.put("transactionNumber", obj.get("transactionNumber"));
	    		templateName = "withdraw.ftl";
	    		content = "您的提币"+obj.get("amount")+obj.get("unit")+"到地址"+obj.get("address")+"已到账。";
	    	} else if(notifyType == NotifyType.WITHDRAW_VALIDATE) {
	    		model.put("unit", obj.get("unit"));
	    		model.put("amount", obj.get("amount"));
	    		//model.put("remark", obj.get("remark"));
	    		model.put("address", obj.get("address"));
	    		model.put("country", obj.getString("country"));
	    		model.put("province", obj.getString("province"));
	    		model.put("code", obj.getString("code"));
	    		model.put("withdrawType", "提币");
	    		model.put("withdrawAddressName", "地址");
	    		templateName = "withdrawValidate.ftl";
	    		content = "您正提币"+obj.get("amount")+obj.get("unit")+"到地址"+obj.get("address")+"。";
	    	} else if(notifyType == NotifyType.TRANSFER_VALIDATE) {
	    		model.put("unit", obj.get("unit"));
	    		model.put("amount", obj.get("amount"));
	    		//model.put("remark", obj.get("remark"));
	    		model.put("address", obj.get("address"));
	    		model.put("country", obj.getString("country"));
	    		model.put("province", obj.getString("province"));
	    		model.put("code", obj.getString("code"));
	    		model.put("withdrawType", "转账");
	    		model.put("withdrawAddressName", "用户");
	    		templateName = "withdrawValidate.ftl";
	    		content = "您正转账"+obj.get("amount")+obj.get("unit")+"到账户"+obj.get("address")+"。";
	    	} else if(notifyType == NotifyType.CUT) {
	    		model.put("contractName", obj.getString("coinSymbol")+"-"+obj.getString("baseSymbol"));
	    		model.put("newPrice", obj.getString("newPrice"));
	    		model.put("direction", obj.getString("direction").equals("SELL")?"看涨":"看跌");
	    		model.put("volume", obj.get("volume"));
	    		model.put("cutType", obj.getInt("cutType")==0?"止盈":"止损");
	    		templateName = "cut.ftl";
	    	} else if(notifyType == NotifyType.CUT_LOSS) {
	    		model.put("contractName", obj.getString("coinSymbol")+"-"+obj.getString("baseSymbol"));
	    		model.put("newPrice", obj.getString("newPrice"));
	    		model.put("direction", obj.getString("direction").equals("SELL")?"看涨":"看跌");
	    		model.put("volume", obj.get("volume"));
	    		templateName = "cutLoss.ftl";
	    		content = "您在"+model.get("contractName")+"-SWAP设置的单向止损委托单在市场价格到达"+obj.getString("newPrice")+"时被止损。";
	    	} else if(notifyType == NotifyType.CUT_PROFIT) {
	    		model.put("contractName", obj.getString("coinSymbol")+"-"+obj.getString("baseSymbol"));
	    		model.put("newPrice", obj.getString("newPrice"));
	    		model.put("direction", obj.getString("direction").equals("SELL")?"看涨":"看跌");
	    		model.put("volume", obj.get("volume"));
	    		templateName = "cutProfit.ftl";
	    		content = "您在"+model.get("contractName")+"-SWAP设置的单向止损委托单在市场价格到达"+obj.getString("newPrice")+"时被止盈。";
	    	} else if(notifyType == NotifyType.BLAST) {
	    		//model.put("contractName", obj.get("contractName"));
	    		net.sf.json.JSONArray positionJsonArray = obj.getJSONArray("positions");
	    		List detailList = new ArrayList();
	    		for(int i=0; i<positionJsonArray.size(); i++) {
	    			net.sf.json.JSONObject positionJsonObject = positionJsonArray.getJSONObject(i);
	    			Map<String, Object> detail = new HashMap<>();
	    			detail.put("contractName", positionJsonObject.get("contractName"));
		    		detail.put("volume", positionJsonObject.get("volume"));
		    		detail.put("leverage", positionJsonObject.get("leverage"));
		    		detail.put("direction", positionJsonObject.getInt("direction")==0?"看涨":"看跌");
		    		detailList.add(detail);
	    		}
	    		model.put("detail", detailList);
	    		model.put("accountType", "全仓");
	    		templateName = "blast.ftl";
	    		content = "因为保证金率低于20%，您的统一账户模式的全仓衍生品仓位已被强制平仓。";
	    	} else if(notifyType == NotifyType.POSITION_BLAST) {
	    		//model.put("contractName", obj.get("contractName"));
	    		net.sf.json.JSONArray positionJsonArray = obj.getJSONArray("positions");
	    		List detailList = new ArrayList();
	    		for(int i=0; i<positionJsonArray.size(); i++) {
	    			net.sf.json.JSONObject positionJsonObject = positionJsonArray.getJSONObject(i);
	    			Map<String, Object> detail = new HashMap<>();
	    			detail.put("contractName", positionJsonObject.get("contractName"));
		    		detail.put("volume", positionJsonObject.get("volume"));
		    		detail.put("leverage", positionJsonObject.get("leverage"));
		    		detail.put("direction", positionJsonObject.getInt("direction")==0?"看涨":"看跌");
		    		detailList.add(detail);
	    		}
	    		model.put("detail", detailList);
	    		model.put("accountType", "逐仓");
	    		templateName = "blast.ftl";
	    		content = "因为保证金率低于20%，您的统一账户模式的逐仓衍生品仓位已被强制平仓。";
	    	} else if(notifyType == NotifyType.BLAST_ALARM) {
	    		model.put("marginRate", obj.get("marginRate"));
	    		model.put("accountType", "全仓");
	    		templateName = "blastAlarm.ftl";
	    		content = "您的统一账户衍生品全仓仓位保证金率已达到"+obj.get("marginRate")+"%。当保证金率低于20%时，该仓位会被强平，请注意风险控制。";
	    	} else if(notifyType == NotifyType.FOLLOW_BLAST) {
	    		//model.put("contractName", obj.get("contractName"));
	    		net.sf.json.JSONArray positionJsonArray = obj.getJSONArray("positions");
	    		List detailList = new ArrayList();
	    		for(int i=0; i<positionJsonArray.size(); i++) {
	    			net.sf.json.JSONObject positionJsonObject = positionJsonArray.getJSONObject(i);
	    			Map<String, Object> detail = new HashMap<>();
	    			detail.put("contractName", positionJsonObject.get("contractName"));
		    		detail.put("volume", positionJsonObject.get("volume"));
		    		detail.put("leverage", positionJsonObject.get("leverage"));
		    		detail.put("direction", positionJsonObject.getInt("direction")==0?"看涨":"看跌");
		    		detailList.add(detail);
	    		}
	    		model.put("detail", detailList);
	    		model.put("accountType", "跟单");
	    		templateName = "blast.ftl";
	    		content = "因为保证金率低于20%，您的跟单账户仓位已被强制平仓。";
	    	} else if(notifyType == NotifyType.FOLLOW_BLAST_ALARM) {
	    		model.put("marginRate", obj.get("marginRate"));
	    		model.put("accountType", "跟单");
	    		templateName = "blastAlarm.ftl";
	    		content = "您的跟单账户仓位保证金率已达到"+obj.get("marginRate")+"%。当保证金率低于20%时，该仓位会被强平，请注意风险控制。";
	    	}
	    	
	    	if(!content.equals("")) {
	    		notice.setContent(content);
	    		log.info("message-receiver-trade-notice, notice={}", notice);
	    		//kafkaTemplate.send("message-receiver-trade-notice", JSON.toJSONString(notice));
	    	}
	    	
	    	Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
	        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
	        
	        model.put("android", sysConfig.getPromotionPrefix() + member.getPromotionCode());
	        model.put("ios", sysConfig.getPromotionPrefix() + member.getPromotionCode());
	        
	        Template bottomTemplate = cfg.getTemplate("bottom.ftl");
	        String bottomHtml = FreeMarkerTemplateUtils.processTemplateIntoString(bottomTemplate, model);
	        model.put("bottomHtml", bottomHtml);
	        
	        Template template = cfg.getTemplate(templateName);
	        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
    		//log.info("html={},member.getEmail()={}", html, member.getEmail());
	        
	        emailProvider.sendSingleSendMail(member.getEmail(), notifyType.getCnName(), html);
    		//log.info("notifyType.getCnName()={}", notifyType.getCnName());
    	} catch(Exception e) {
    		log.info("e.getMessage()={}", e.getMessage());
    		e.printStackTrace();
    	}
    }
    
    public Member getMemberInfo(Long id) {
    	Object object = redisManager.getMemberInfo(id);
		if(object != null) {
			try {
				String jsonStr = object.toString();
				Member member = JSON.parseObject(jsonStr, Member.class);
				if(member!=null) {
					return member;
				}
			} catch (Exception e) {
				log.info("tradingAccount format error, id={}", id);
			}
		}
		Member member = this.findOne(id);
		redisManager.saveMemberInfo(id, JSON.toJSONString(member));
		return member;
    }
    
    public AgentVo sumStatsByMemberId(Long memberId) {
		AgentVo agentVo = new AgentVo();
    	List<Long> ids = memberWeightUpperService.findMemberIdListByAllUppers(memberId);
    	//log.info("ids={}", ids);
    	//if(ids.size()==0)
    	//	return agentVo;
    	ids.add(memberId);
    	Object[][] stats = memberDao.sumStatsByIds(ids);
    	//log.info("stats={}", stats);
    	if(stats.length>0) {
    		Object[] stat = stats[0];
    		if(stat[0]==null)
    			agentVo.setTotalBalance(BigDecimal.ZERO);
    		else
    			agentVo.setTotalBalance(BigDecimal.valueOf(Double.valueOf(stat[0].toString())));

    		if(stat[1]==null)
    			agentVo.setTotalCount(0);
    		else
    			agentVo.setTotalCount(Integer.valueOf(stat[1].toString()));

    		if(stat[2]==null)
    			agentVo.setTotalRecharge(BigDecimal.ZERO);
    		else
    			agentVo.setTotalRecharge(BigDecimal.valueOf(Double.valueOf(stat[2].toString())));

    		if(stat[3]==null)
    			agentVo.setTotalWithdraw(BigDecimal.ZERO);
    		else
    			agentVo.setTotalWithdraw(BigDecimal.valueOf(Double.valueOf(stat[3].toString())));

    		if(stat[4]==null)
    			agentVo.setTotalAward(BigDecimal.ZERO);
    		else
    			agentVo.setTotalAward(BigDecimal.valueOf(Double.valueOf(stat[4].toString())));

    		if(stat[5]==null)
    			agentVo.setTotalFee(BigDecimal.ZERO);
    		else
    			agentVo.setTotalFee(BigDecimal.valueOf(Double.valueOf(stat[5].toString())));

    		if(stat[6]==null)
    			agentVo.setTotalProfit(BigDecimal.ZERO);
    		else
    			agentVo.setTotalProfit(BigDecimal.valueOf(Double.valueOf(stat[6].toString())));

    		if(stat[7]==null)
    			agentVo.setTotalLoss(BigDecimal.ZERO);
    		else
    			agentVo.setTotalLoss(BigDecimal.valueOf(Double.valueOf(stat[7].toString())));
        	log.info("agentVo={}", agentVo);
    		return agentVo;
    	}
    	return agentVo;
    }
}
