package com.bizzan.bitrade.controller.member;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.annotation.AccessLog;
import com.bizzan.bitrade.vendor.provider.support.EmailProvider;
import com.bizzan.bitrade.constant.*;
import com.bizzan.bitrade.controller.common.BaseAdminController;
import com.bizzan.bitrade.dto.MemberDTO;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.event.MemberEvent;
import com.bizzan.bitrade.model.MemberStatVo;
import com.bizzan.bitrade.model.MemberWithAmountVo;
import com.bizzan.bitrade.model.screen.AccountScreen;
import com.bizzan.bitrade.model.screen.MemberScreen;
import com.bizzan.bitrade.model.vo.AgentStatVo;
import com.bizzan.bitrade.service.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import com.bizzan.bitrade.util.*;
import com.bizzan.bitrade.vo.ExchangeAccount;
import com.bizzan.bitrade.vo.OrderStatVo;
import com.bizzan.bitrade.vo.PositionStatVo;
import com.bizzan.bitrade.vo.TradingAccount;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.BeanUtils;
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.PageImpl;
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.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.bizzan.bitrade.constant.CertifiedBusinessStatus.*;
import static com.bizzan.bitrade.constant.MemberLevelEnum.IDENTIFICATION;
import static com.bizzan.bitrade.entity.QEmailSendRecord.emailSendRecord;
import static com.bizzan.bitrade.entity.QMember.member;
import static org.springframework.util.Assert.isTrue;
import static org.springframework.util.Assert.notNull;

/**
 * @author
 * @description 后台管理会员
 * @date 2019/12/25 16:50
 */
@RestController
@RequestMapping("/member")
@Slf4j
public class MemberController extends BaseAdminController {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    private MemberService memberService;

    @Autowired
    private MemberWalletService memberWalletService;

    @Autowired
    private MemberContractWalletService memberContractWalletService;

    @Autowired
    private BusinessAuthApplyService businessAuthApplyService;

    @Autowired
    private DepositRecordService depositRecordService;

    @Autowired
    private LocaleMessageSourceService messageSource;
    @Autowired
    private MemberEvent memberEvent;
    @Autowired
    private ContractOrderEntrustService contractOrderEntrustService;
    @Autowired
    private MemberTransactionService memberTransactionService;
    @Autowired
    private MemberHistoryService memberHistoryService;
    @Autowired
    private InnerInvokeUtil invokeUtil;
    @Autowired
    private MemberWeightUpperService memberWeightUpperService;
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private UserPurseService userPurseService;
    @Autowired
    private GameWalletService gameWalletService;
    @Autowired
    private FollowWalletService followWalletService;
    @Autowired
    private ExchangeWalletService exchangeWalletService;
    @Autowired
    private MemberContractPositionService memberContractPositionService;
    @Autowired
    private AgentInfoService agentInfoService;

    @Autowired
    private EmailProvider emailProvider;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private EmailSendRecordService emailSendRecordService;

    @Value("${member.default.avatar-url:}")
    private String defaultAvatarUrl;
    @Value("${follow.service.url:http://43.99.6.73:6026}")
    private String followServiceUrl;

    @RequiresPermissions("member:all")
    @PostMapping("all")
    @AccessLog(module = AdminModule.MEMBER, operation = "所有会员Member")
    public MessageResult all() {
        List<Member> all = memberService.findAll();
        if (all != null && all.size() > 0) {
            return success(all);
        }
        return error(messageSource.getMessage("REQUEST_FAILED"));
    }

    @Autowired
    private IdWorkByTwitter idWorkByTwitter;

    @RequiresPermissions("member:all")
    @PostMapping("add")
    @AccessLog(module = AdminModule.MEMBER, operation = "会员Member")
    public MessageResult add(String email, String password, String promotionCode) throws Exception {
        email = email.trim();
        if (memberService.usernameIsExist(email)) {
            return error("用户名已存在");
        }
        if (!ValidateUtil.isEmail(email)) {
            return error("email地址不合法");
        }
        if (promotionCode != null && promotionCode.trim().equals("1")) {
            return error("推荐人不合法");
        }
        if (promotionCode != null && !promotionCode.trim().equals("")) {
            try {
                Member inviter = memberService.findOne(Long.parseLong(promotionCode));
                if (inviter == null)
                    return error("邀请人不存在");
                promotionCode = inviter.getPromotionCode();
            } catch (Exception e) {
                return error("邀请人不存在");
            }
        }

        String loginNo = String.valueOf(idWorkByTwitter.nextId());
        //盐
        String credentialsSalt = ByteSource.Util.bytes(loginNo).toHex();
        //生成密码
        password = Md5.md5Digest(password + credentialsSalt).toLowerCase();
        Member member = new Member();

        member.setMemberLevel(MemberLevelEnum.GENERAL);
        Location location = new Location();
        location.setCountry("中国");
        member.setLocation(location);
        Country country = new Country();
        country.setZhName("中国");
        member.setCountry(country);
        member.setUsername(email);
        member.setPassword(password);
        if (email.indexOf("@") > 0)
            member.setEmail(email);
        else
            member.setMobilePhone(email);
        member.setSalt(credentialsSalt);
        member.setAvatar(defaultAvatarUrl); // 默认用户头像
        member.setPromotionCode(getPromotionCode());
        Member member1 = memberService.save(member);

        memberEvent.onRegisterSuccess(member1, promotionCode);

        return success();
    }

    public String getPromotionCode() {
        String promotionCode = "";
        for (int i = 0; i < 100; i++) {
            promotionCode = getNewPromotionCode();
            if (memberService.findMemberByPromotionCode(promotionCode) == null) {
                return promotionCode;
                //member1.setPromotionCode(promotionCode);
                //break;
            }
        }
        return promotionCode;
    }

    public int getRandomNumber(int from, int to) {
        float a = from + (to - from) * (new Random().nextFloat());
        int b = (int) a;
        return ((a - b) > 0.5 ? 1 : 0) + b;
    }

    public String getNewPromotionCode() {
        String seed = "0123456789AB";
        String code = "";
        for (int i = 0; i < 4; i++) {
            int index = getRandomNumber(0, 10);
            code += seed.charAt(index);
        }
        return code;
    }

    @RequiresPermissions("member:detail")
    @PostMapping("detail")
    @AccessLog(module = AdminModule.MEMBER, operation = "会员Member详情")
    public MessageResult detail(@RequestParam("id") Long id) {
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        List<MemberWallet> list = memberWalletService.findAllByMemberId(member.getId());
        //List<MemberWallet> list = invokeUtil.listWallet(member.getId());
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setMember(member);
        memberDTO.setList(list);
        return success(memberDTO);
    }

    @RequiresPermissions("member:delete")
    @PostMapping("delete")
    @AccessLog(module = AdminModule.MEMBER, operation = "删除会员Member")
    public MessageResult delete(@RequestParam(value = "id") Long id) {
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        member.setStatus(CommonStatus.ILLEGAL);// 修改状态非法
        memberService.save(member);
        return success();
    }

    @RequiresPermissions("member:update")
    @PostMapping(value = "update")
    @AccessLog(module = AdminModule.MEMBER, operation = "更新会员Member")
    public MessageResult update(Member member) {
        if (member.getId() == null) {
            return error("id必须传参");
        }
        Member one = memberService.findOne(member.getId());
        if (one == null) {
            return error("用户不存在");
        }
        if (StringUtils.isNotBlank(member.getUsername())) {
            one.setUsername(member.getUsername());
        }
        if (StringUtils.isNotBlank(member.getPassword())) {
            one.setPassword(member.getPassword());
        }
        if (StringUtils.isNotBlank(member.getRealName())) {
            one.setRealName(member.getRealName());
        }
        Member save = memberService.save(one);
        return success(save);
    }

    @RequiresPermissions("member:update")
    @PostMapping(value = "lock")
    @AccessLog(module = AdminModule.MEMBER, operation = "锁仓Member")
    public MessageResult lock(Long memberId) {
        Member one = memberService.findOne(memberId);
        if (one == null) {
            return error("用户不存在");
        }
        memberService.updateIsLock(memberId, 1);
        return success();
    }

    @RequiresPermissions("member:update")
    @PostMapping(value = "unlock")
    @AccessLog(module = AdminModule.MEMBER, operation = "解锁Member")
    public MessageResult unlock(Long memberId) {
        Member one = memberService.findOne(memberId);
        if (one == null) {
            return error("用户不存在");
        }
        memberService.updateIsLock(memberId, 0);
        return success();
    }

    @RequiresPermissions("member:update")
    @PostMapping(value = "disableReward")
    @AccessLog(module = AdminModule.MEMBER, operation = "停止返佣Member")
    public MessageResult disableReward(Long memberId) {
        Member one = memberService.findOne(memberId);
        if (one == null) {
            return error("用户不存在");
        }
        one.setDisableReward(1);
        memberService.save(one);
        return success();
    }

    @RequiresPermissions("member:update")
    @PostMapping(value = "enableReward")
    @AccessLog(module = AdminModule.MEMBER, operation = "启动返佣Member")
    public MessageResult enableReward(Long memberId) {
        Member one = memberService.findOne(memberId);
        if (one == null) {
            return error("用户不存在");
        }
        one.setDisableReward(0);
        memberService.save(one);
        return success();
    }

    @RequiresPermissions("member:update")
    @PostMapping(value = "unbind-google")
    @AccessLog(module = AdminModule.MEMBER, operation = "重置谷歌")
    public MessageResult resetGoogle(Long memberId) {
        Member one = memberService.findOne(memberId);
        if (one == null) {
            return error("用户不存在");
        }
        memberService.resetGoogle(memberId);
        return success();
    }

    @RequiresPermissions("member:audit-business")
    @PatchMapping("{id}/audit-business")
    @AccessLog(module = AdminModule.MEMBER, operation = "会员Member认证商家")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult auditBusiness(
            @PathVariable("id") Long id,
            @RequestParam("status") CertifiedBusinessStatus status,
            @RequestParam("detail") String detail) {
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        //确认是审核中
        isTrue(member.getCertifiedBusinessStatus() == AUDITING, "validate member certifiedBusinessStatus!");
        //确认传入certifiedBusinessStatus值正确，审核通过或者不通过
        isTrue(status == VERIFIED || status == FAILED, "validate certifiedBusinessStatus!");
        //member.setCertifiedBusinessApplyTime(new Date());//time
        List<BusinessAuthApply> businessAuthApplyList = businessAuthApplyService.findByMemberAndCertifiedBusinessStatus(member, AUDITING);
        if (status == VERIFIED) {
            //通过
            member.setCertifiedBusinessStatus(VERIFIED);//已认证
            member.setMemberLevel(IDENTIFICATION);//认证商家
            if (businessAuthApplyList != null && businessAuthApplyList.size() > 0) {
                BusinessAuthApply businessAuthApply = businessAuthApplyList.get(0);
                businessAuthApply.setCertifiedBusinessStatus(VERIFIED);
                //如果申请的时候选择了保证金策略
                if (businessAuthApply.getBusinessAuthDeposit() != null) {
                    //扣除保证金
                    MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId(businessAuthApply.getBusinessAuthDeposit().getCoin().getUnit(), member.getId());
                    memberWallet.setFrozenBalance(memberWallet.getFrozenBalance().subtract(businessAuthApply.getAmount()));
                    DepositRecord depositRecord = new DepositRecord();
                    depositRecord.setId(UUID.randomUUID().toString());
                    depositRecord.setAmount(businessAuthApply.getAmount());
                    depositRecord.setCoin(businessAuthApply.getBusinessAuthDeposit().getCoin());
                    depositRecord.setMember(member);
                    depositRecord.setStatus(DepositStatusEnum.PAY);
                    depositRecordService.create(depositRecord);
                    businessAuthApply.setDepositRecordId(depositRecord.getId());
                }
            }
        } else {
            //不通过
            member.setCertifiedBusinessStatus(FAILED);//认证失败
            if (businessAuthApplyList != null && businessAuthApplyList.size() > 0) {
                BusinessAuthApply businessAuthApply = businessAuthApplyList.get(0);
                businessAuthApply.setCertifiedBusinessStatus(FAILED);
                businessAuthApply.setDetail(detail);
                //申请商家认证时冻结的金额退回
                if (businessAuthApply.getBusinessAuthDeposit() != null) {
                    MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId(businessAuthApply.getBusinessAuthDeposit().getCoin().getUnit(), member.getId());
                    memberWallet.setFrozenBalance(memberWallet.getFrozenBalance().subtract(businessAuthApply.getAmount()));
                    memberWallet.setBalance(memberWallet.getBalance().add(businessAuthApply.getAmount()));
                }
            }
        }
        member.setCertifiedBusinessCheckTime(new Date());
        memberService.save(member);
        return success();
    }

    @RequiresPermissions("member:page-query")
    @PostMapping("page-query")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找会员Member")
    public MessageResult page(
            PageModel pageModel,
            MemberScreen screen) {
        Predicate predicate = getPredicate(screen);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        all.forEach(member -> {
            double usdtBalance = getUsdtBalanceByMemberId(member.getId())[0];
            member.setUsdtBalance(usdtBalance);
        });
        return success(all);
    }

    @RequiresPermissions("member:page-query")
    @PostMapping("get-uppers")
    @ResponseBody
    public MessageResult getAllUppers(String account) {
        Member member = memberService.findByUsername(account);
        if (member == null) {
            try {
                member = memberService.findOne(Long.parseLong(account));
            } catch (Exception e) {

            }
        }
        if (member != null) {
            MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());

            return success(memberWeightUpper.getAllUppers());
        } else {
            return error("没有找到对象");
        }
    }

    private double[] getUsdtBalanceByMemberId(long memberId) {
        double usdtBalance = 0;
        List<MemberWallet> wallets = memberWalletService.findAllByMemberId(memberId);

        for (MemberWallet wallet : wallets) {
            if (wallet.getCoin() != null && wallet.getCoin().getStatus() == CommonStatus.NORMAL)
                usdtBalance += wallet.getBalance().doubleValue() + wallet.getFrozenBalance().doubleValue();
        }
        ;

        double contractBalance = 0;
        List<MemberContractWallet> list = memberContractWalletService.findAllByMemberId(memberId);
        for (MemberContractWallet contractWallet : list) {
            if (contractWallet == null || contractWallet.getContractCoin() == null || contractWallet.getContractCoin().getEnable() != 1)
                continue;
            contractBalance += contractWallet.getUsdtBalance().doubleValue() + contractWallet.getUsdtFrozenBalance().doubleValue();
        }
        double[] balance = new double[]{usdtBalance, contractBalance};
        return balance;
    }

   /* @RequiresPermissions("member:audit-business")
    @PatchMapping("{id}/cancel-business")
    @AccessLog(module = AdminModule.MEMBER, operation = "会员Member取消认证商家")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult cancelBusiness(
            @PathVariable("id") Long id,
            @RequestParam("status") CertifiedBusinessStatus status) {
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        //确认是申请取消认证状态
        isTrue(member.getCertifiedBusinessStatus() == CANCEL_AUTH, "validate member certifiedBusinessStatus!");
        //确认传入certifiedBusinessStatus值正确
        isTrue(status == NOT_CERTIFIED || status == VERIFIED, "validate certifiedBusinessStatus!");
        //member.setCertifiedBusinessApplyTime(new Date());//time
        //查询状态为申请取消认证的申请记录
        List<BusinessAuthApply> businessAuthApplyList=businessAuthApplyService.findByMemberAndCertifiedBusinessStatus(member,CANCEL_AUTH);
        if (status == VERIFIED) {
            //不允许取消
            member.setCertifiedBusinessStatus(VERIFIED);//状态改回已认证
            if(businessAuthApplyList!=null&&businessAuthApplyList.size()>0){
                businessAuthApplyList.get(0).setCertifiedBusinessStatus(VERIFIED);
            }
        } else {
            //取消认证的申请通过
            member.setCertifiedBusinessStatus(NOT_CERTIFIED);//未认证
            member.setMemberLevel(MemberLevelEnum.REALNAME);
            if(businessAuthApplyList!=null&&businessAuthApplyList.size()>0){
                businessAuthApplyList.get(0).setCertifiedBusinessStatus(NOT_CERTIFIED);
            }
            //商家认证时收取的保证金退回
            List<DepositRecord> depositRecordList=depositRecordService.findByMemberAndStatus(member,DepositStatusEnum.PAY);
            if(depositRecordList!=null&&depositRecordList.size()>0){
                BigDecimal deposit=BigDecimal.ZERO;
                for(DepositRecord depositRecord:depositRecordList){
                    depositRecord.setStatus(DepositStatusEnum.GET_BACK);
                    deposit=deposit.add(depositRecord.getAmount());
                }
                if(businessAuthApplyList!=null&&businessAuthApplyList.size()>0){
                    BusinessAuthApply businessAuthApply=businessAuthApplyList.get(0);
                    MemberWallet memberWallet=memberWalletService.findByCoinUnitAndMemberId(businessAuthApply.getBusinessAuthDeposit().getCoin().getUnit(),member.getId());
                    memberWallet.setBalance(memberWallet.getBalance().add(deposit));
                }
            }
        }
        memberService.save(member);
        return success();
    }*/

    @RequiresPermissions("member:audit-business")
    @GetMapping("{id}/business-auth-detail")
    @AccessLog(module = AdminModule.MEMBER, operation = "查询会员Member申请资料")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult getBusinessAuthApply(@PathVariable("id") Long id,
                                              @RequestParam("status") CertifiedBusinessStatus status) {
        if (status == null) {
            return MessageResult.error("缺少参数");
        }
        isTrue(status == AUDITING || status == CANCEL_AUTH, "validate certifiedBusinessStatus!");
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        //查询申请记录
        List<BusinessAuthApply> businessAuthApplyList = businessAuthApplyService.findByMemberAndCertifiedBusinessStatus(member, status);
        MessageResult result = MessageResult.success();
        if (businessAuthApplyList != null && businessAuthApplyList.size() > 0) {
            result.setData(businessAuthApplyList.get(0));
        }
        return result;
    }

    private Long coverToLong(String str) {
        try {
            Long num = Long.valueOf(str);//把字符串强制转换为数字
            return num;//如果是数字，数字
        } catch (Exception e) {
            return null;//如果抛出异常，返回null
        }
    }

    private Predicate getPredicate(MemberScreen screen) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        if (screen.getStatus() != null) {
            booleanExpressions.add(member.certifiedBusinessStatus.eq(screen.getStatus()));
        }
        if (screen.getStartTime() != null) {
            booleanExpressions.add(member.registrationTime.goe(screen.getStartTime()));
        }
        if (screen.getEndTime() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(screen.getEndTime());
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            booleanExpressions.add(member.registrationTime.lt(calendar.getTime()));
        }

        if (!StringUtils.isEmpty(screen.getAccount())) {
            Long accountId = coverToLong(screen.getAccount());
            if (accountId == null) {
                booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                        .or(member.mobilePhone.like(screen.getAccount() + "%"))
                        .or(member.email.like(screen.getAccount() + "%"))
                        .or(member.realName.like("%" + screen.getAccount() + "%")));
            } else {
                booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                        .or(member.mobilePhone.like(screen.getAccount() + "%"))
                        .or(member.email.like(screen.getAccount() + "%"))
                        .or(member.id.eq(accountId))
                        .or(member.realName.like("%" + screen.getAccount() + "%")));
            }
        }
        if (screen.getCommonStatus() != null) {
            booleanExpressions.add(member.status.eq(screen.getCommonStatus()));
        }

        if (screen.getSuperPartner() != null && !screen.getSuperPartner().equals("")) {
            booleanExpressions.add(member.superPartner.eq(screen.getSuperPartner()));
        }

        if (screen.getIsLock() != null) {
            booleanExpressions.add(member.isLock.eq(screen.getIsLock()));
        }
        if (screen.getDisableReward() != null) {
            booleanExpressions.add(member.disableReward.eq(screen.getDisableReward()));
        }
        if (screen.getProfitStatus() != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String transactionStartTime = "1970-1-1";
            if (screen.getTransactionStartTime() != null)
                transactionStartTime = sdf.format(screen.getTransactionStartTime());
            String transactionEndTime = sdf.format(new Date());
            if (screen.getTransactionEndTime() != null)
                transactionEndTime = sdf.format(screen.getTransactionEndTime());
            List<Long> memberIdList = memberTransactionService.getMemberIdListByTimeAndSign(transactionStartTime, transactionEndTime, screen.getProfitStatus());
            booleanExpressions.add(member.id.in(memberIdList));
        }
        if (screen.getInviterId() != null)
            booleanExpressions.add(member.inviterId.eq(screen.getInviterId()));
        if (screen.getIsInternal() != null)
            booleanExpressions.add(member.isInternal.eq(screen.getIsInternal()));
        return PredicateUtils.getPredicate(booleanExpressions);
    }

    private Predicate getPositionPredicate(MemberScreen screen, String startTime) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        if (screen.getStatus() != null) {
            booleanExpressions.add(member.certifiedBusinessStatus.eq(screen.getStatus()));
        }

        if (!StringUtils.isEmpty(screen.getAccount())) {
            Long accountId = coverToLong(screen.getAccount());
            if (accountId == null) {
                booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                        .or(member.mobilePhone.like(screen.getAccount() + "%"))
                        .or(member.email.like(screen.getAccount() + "%"))
                        .or(member.realName.like("%" + screen.getAccount() + "%")));
            } else {
                booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                        .or(member.mobilePhone.like(screen.getAccount() + "%"))
                        .or(member.email.like(screen.getAccount() + "%"))
                        .or(member.id.eq(accountId))
                        .or(member.realName.like("%" + screen.getAccount() + "%")));
            }
        }
        if (screen.getCommonStatus() != null) {
            booleanExpressions.add(member.status.eq(screen.getCommonStatus()));
        }

        //if(screen.getSuperPartner() != null && !screen.getSuperPartner().equals("")) {
        //    booleanExpressions.add(member.superPartner.eq(screen.getSuperPartner()));
        //}

        if (screen.getIsLock() != null) {
            booleanExpressions.add(member.isLock.eq(screen.getIsLock()));
        }
        if (screen.getDisableReward() != null) {
            booleanExpressions.add(member.disableReward.eq(screen.getDisableReward()));
        }
        List<BigInteger> idList = memberContractPositionService.findSupervised(startTime);
        List<BigInteger> idList1 = userPurseService.findIdListByIsSupervised();
        //log.info("idList1.length={}", idList1.size());
        List<Long> newIdList = new ArrayList<Long>();
        newIdList.add(0L);
        for (BigInteger id : idList) {
            newIdList.add(id.longValue());
        }
        //log.info("newIdList.length={}", newIdList.size());
        for (BigInteger id : idList1) {
            newIdList.add(id.longValue());
        }
        //log.info("newIdList.length={}, newIdList={}", newIdList.size(), newIdList);
        booleanExpressions.add(member.id.in(newIdList));
        //log.info("booleanExpressions={}", booleanExpressions);
        return PredicateUtils.getPredicate(booleanExpressions);
    }

    private Predicate getPredicate(MemberScreen screen, Long inviterId, boolean isGroup) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        if (screen.getStatus() != null) {
            booleanExpressions.add(member.certifiedBusinessStatus.eq(screen.getStatus()));
        }
        if (screen.getStartTime() != null) {
            booleanExpressions.add(member.registrationTime.goe(screen.getStartTime()));
        }
        if (screen.getEndTime() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(screen.getEndTime());
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            booleanExpressions.add(member.registrationTime.lt(calendar.getTime()));
        }

        if (!StringUtils.isEmpty(screen.getAccount())) {
            booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                    .or(member.mobilePhone.like(screen.getAccount() + "%"))
                    .or(member.email.like(screen.getAccount() + "%"))
                    .or(member.id.eq(Long.valueOf(screen.getAccount())))
                    .or(member.realName.like("%" + screen.getAccount() + "%")));
        }
        // 筛选过滤出我邀请的人
        if (isGroup) {
            List<Long> subIds = memberWeightUpperService.findMemberIdListByAllUppers(inviterId);
            subIds.add(inviterId);
            booleanExpressions.add(member.id.in(subIds));
        } else
            booleanExpressions.add(member.inviterId.eq(inviterId));

        if (screen.getCommonStatus() != null) {
            booleanExpressions.add(member.status.eq(screen.getCommonStatus()));
        }
        return PredicateUtils.getPredicate(booleanExpressions);
    }

    @RequiresPermissions("member:out-excel")
    @GetMapping("out-excel")
    @AccessLog(module = AdminModule.MEMBER, operation = "导出会员Member Excel")
    public MessageResult outExcel(
            @RequestParam(value = "startTime", required = false) Date startTime,
            @RequestParam(value = "endTime", required = false) Date endTime,
            @RequestParam(value = "account", required = false) String account,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        List<BooleanExpression> booleanExpressionList = getBooleanExpressionList(startTime, endTime, account, null);
        List list = memberService.queryWhereOrPage(booleanExpressionList, null, null).getContent();
        return new FileUtil().exportExcel(request, response, list, "member");
    }

    // 获得条件
    private List<BooleanExpression> getBooleanExpressionList(
            Date startTime, Date endTime, String account, CertifiedBusinessStatus status) {
        List<BooleanExpression> booleanExpressionList = new ArrayList();
        if (status != null) {
            booleanExpressionList.add(member.certifiedBusinessStatus.eq(status));
        }
        if (startTime != null) {
            booleanExpressionList.add(member.registrationTime.gt(startTime));
        }
        if (endTime != null) {
            booleanExpressionList.add(member.registrationTime.lt(endTime));
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(account)) {
            booleanExpressionList.add(member.username.like("%" + account + "%")
                    .or(member.mobilePhone.like(account + "%"))
                    .or(member.email.like(account + "%")));
        }
        return booleanExpressionList;
    }


    @RequiresPermissions("member:alter-publish-advertisement-status")
    @PostMapping("alter-publish-advertisement-status")
    @AccessLog(module = AdminModule.SYSTEM, operation = "禁用/解禁发布广告")
    public MessageResult publishAdvertise(@RequestParam("memberId") Long memberId,
                                          @RequestParam("status") BooleanEnum status) {
        Member member = memberService.findOne(memberId);
        if (member.getCertifiedBusinessStatus() != CertifiedBusinessStatus.VERIFIED) {
            return error("请先认证商家");
        }
        Assert.notNull(member, "玩家不存在");
        member.setPublishAdvertise(status);
        memberService.save(member);
        return success(status == BooleanEnum.IS_FALSE ? "禁止发布广告成功" : "解除禁止成功");
    }

    @RequiresPermissions("member:alter-status")
    @PostMapping("alter-status")
    @AccessLog(module = AdminModule.SYSTEM, operation = "禁用/解禁会员账号")
    public MessageResult ban(@RequestParam("status") CommonStatus status,
                             @RequestParam("memberId") Long memberId) {
        Member member = memberService.findOne(memberId);
        if (status == CommonStatus.ILLEGAL) {
            double position = memberContractWalletService.sumPositionByMemberId(memberId).doubleValue();
            if (position > 0) {
                return error("该账户已有仓位, 请先平仓");
            }
            redisManager.removeSessionByMemberId(memberId, DESUtil.mixup(member.getToken()));
        }
        member.setStatus(status);
        memberService.save(member);
        return success(messageSource.getMessage("SUCCESS"));
    }

    @RequiresPermissions("member:alter-transaction-status")
    @PostMapping("alter-transaction-status")
    @AccessLog(module = AdminModule.SYSTEM, operation = "禁用/解禁会员账号")
    public MessageResult alterTransactionStatus(
            @RequestParam("status") BooleanEnum status,
            @RequestParam("memberId") Long memberId) {
        Member member = memberService.findOne(memberId);
        member.setTransactionStatus(status);
        memberService.save(member);
        return success(messageSource.getMessage("SUCCESS"));
    }

    @RequiresPermissions("member:alter-transaction-status")
    @PostMapping("set-money-lock")
    @AccessLog(module = AdminModule.SYSTEM, operation = "禁用/解禁账号资金")
    public MessageResult setMoneyLock(
            @RequestParam("isMoneyLock") int isMoneyLock,
            @RequestParam("memberId") Long memberId) {
        Member member = memberService.findOne(memberId);
        member.setIsMoneyLock(isMoneyLock);
        memberService.save(member);
        return success(messageSource.getMessage("SUCCESS"));
    }

    @RequiresPermissions("member:alter-transaction-status")
    @PostMapping("set-internal")
    @AccessLog(module = AdminModule.SYSTEM, operation = "设置/取消内部账户")
    public MessageResult setInternal(
            @RequestParam("isInternal") int isInternal,
            @RequestParam("memberId") Long memberId) {
        Member member = memberService.findOne(memberId);
        member.setIsInternal(isInternal);
        memberService.save(member);
        return success(messageSource.getMessage("SUCCESS"));
    }

    @RequiresPermissions("member:alter-transaction-status")
    @PostMapping("set-service")
    @AccessLog(module = AdminModule.SYSTEM, operation = "设置/取消客服")
    public MessageResult setService(
            @RequestParam("isService") int isService,
            @RequestParam("memberId") Long memberId) {
        Member member = memberService.findOne(memberId);
        member.setIsService(isService);
        memberService.save(member);
        return success(messageSource.getMessage("SUCCESS"));
    }

    /**
     * 更改用户等级（合伙人/代理商等）
     *
     * @param superPartner
     * @param memberId
     * @return
     */
    @RequiresPermissions("member:alter-member-superpartner")
    @PostMapping("alter-member-superpartner")
    @AccessLog(module = AdminModule.SYSTEM, operation = "修改用户等级")
    public MessageResult alterSuperPartner(
            @RequestParam("superPartner") String superPartner,
            @RequestParam("memberId") Long memberId) {
        if (superPartner.equals("0")) {
            memberWeightUpperService.cancelSuperPartner(memberId);
        } else {
            Member member = memberService.findOne(memberId);
            member.setSuperPartner(superPartner);
            memberService.save(member);
        }
        return success(messageSource.getMessage("SUCCESS"));
    }

    /**
     * 查询代理商列表
     *
     * @param pageModel
     * @param screen
     * @return
     */
    @RequiresPermissions("member:page-query-super")
    @PostMapping("page-query-super")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找会员Member")
    public MessageResult pageSuperPartner(
            PageModel pageModel,
            MemberScreen screen) {
        screen.setSuperPartner("1"); // 默认选择代理商
        Predicate predicate = getPredicate(screen);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        return success(all);
    }

    /**
     * 查询代理商邀请用户列表
     *
     * @param pageModel
     * @param screen
     * @param userId
     * @return
     */
    @RequiresPermissions("member:supermember-page-query")
    @PostMapping(value = "/supermember-page-query")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public MessageResult pageSuperMember(
            PageModel pageModel,
            MemberScreen screen,
            Long userId) {
        // 检查用户是否是代理商
        Member checkMember = memberService.findOne(userId);
        if (!checkMember.getSuperPartner().equals("1")) {
            return error("您不是代理商！");
        }
        Predicate predicate = getPredicate(screen, userId, true);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        return success(all);
    }

    @RequiresPermissions("member:set-inviter")
    @PostMapping("setInviter")
    @AccessLog(module = AdminModule.MEMBER, operation = "设置邀请人")
    public MessageResult setInviter(
            @RequestParam(value = "id") Long id,
            @RequestParam(value = "inviterId") Long inviterId) throws Exception {
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        Member pMember = memberService.findOne(inviterId);
        notNull(member, "validate id!");
        //if(member.getInviterId()!=null){
        //    return error("已存在邀请人");
        //}

        if (id.longValue() == inviterId) {
            return error("不能设置自己为邀请人");
        }

        List<Long> subIds = memberWeightUpperService.findMemberIdListByAllUppers(id);
        if (subIds.contains(inviterId)) {
            return error("不能设置自己的下级为邀请人");
        }

        memberEvent.setMemberInviter(member, pMember);
        return success();
    }

    @RequiresPermissions("member:update")
    @PostMapping("force-offline")
    @AccessLog(module = AdminModule.MEMBER, operation = "强制下线")
    public MessageResult kick(
            @RequestParam(value = "id") Long id) throws Exception {
        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        memberService.kick(member);
        return success();
    }

    @PostMapping("stat")
    public MessageResult stat(
            @RequestParam(value = "date") String date) throws Exception {
        MemberStatVo vo = new MemberStatVo();
        vo.setTotalCount(memberService.countAll());
        vo.setTodayCount(memberService.countByDate(date));
        vo.setActiveCount(contractOrderEntrustService.countActiveMembersByDate(date));
        vo.setTotalOrderCount(contractOrderEntrustService.countContract());
        vo.setSpotBalance(memberWalletService.sumBalance());
        vo.setSwapBalance(userPurseService.sumBalance());
        vo.setFollowBlance(followWalletService.sumBalance());
        return success(vo);
    }

    @RequiresPermissions("member:page-query")
    @PostMapping("page-with-amount")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找会员Member")
    public MessageResult pageWithAmount(
            PageModel pageModel,
            MemberScreen screen) throws ParseException {
        Long[] todayTime = DateUtil.getRealStartAndEndDate(0);
        final long startTimeLong = todayTime[0];
        final long endTimeLong = todayTime[1];
        java.text.SimpleDateFormat sdf1 = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startTimeStr = sdf1.format(new Date(startTimeLong));
        String endTimeStr = sdf1.format(new Date(endTimeLong));
        Predicate predicate = getPredicate(screen);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<MemberWithAmountVo> list = new ArrayList<MemberWithAmountVo>();
        all.forEach(member -> {
            //double[] balance = getUsdtBalanceByMemberId(member.getId());
            //member.setUsdtBalance(balance[0] + balance[1]);
            TradingAccount tradingAccount = userPurseService.findOneVO(member.getId());
            BigDecimal contractBalance = tradingAccount.getCurrentCapital();
            GameWallet gameWallet = gameWalletService.findOne(member.getId());
            BigDecimal gameBalance = gameWallet.getBalance().add(gameWallet.getFrozenBalance());
            FollowWallet followWallet = followWalletService.findOne(member.getId());
            BigDecimal followBalance = followWallet.getBalance().add(followWallet.getFrozenBalance());
            BigDecimal cashBalance = memberWalletService.sumBalanceByMemberId(member.getId());
            ExchangeAccount exchangeAccount = exchangeWalletService.findExchangeAccount(member.getId());
            BigDecimal totalBalance = cashBalance.add(contractBalance).add(gameBalance).add(followBalance).add(exchangeAccount.getCurrentValue());

            BigDecimal historyBalance = memberHistoryService.sumBalanceByMemberId(member.getId());
            String[] todayTimes = DateUtil.getTodayRealSartAndEndDateStr();
            BigDecimal estimatedBalance = historyBalance.add(memberTransactionService.sumAmountByMemberIdAndTime(todayTimes[0], todayTimes[1], member.getId()));
            BigDecimal totalProfit = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_PROFIT);
            BigDecimal totalLoss = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_LOSS);
            BigDecimal todayProfit = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_PROFIT);
            BigDecimal todayLoss = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_LOSS);
            BigDecimal totalFee = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_FEE);
            BigDecimal totalAward = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_AWARD);
            BigDecimal followProfit = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.FOLLOW_PROFIT);
            BigDecimal followLoss = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.FOLLOW_LOSS);
            BigDecimal followFee = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.FOLLOW_FEE);
            BigDecimal followAward = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.FOLLOW_AWARD);
            BigDecimal todayAward = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_AWARD);
            BigDecimal totalWithdraw = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.WITHDRAW);
            BigDecimal totalRecharge = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.RECHARGE);
            BigDecimal totalAdminRecharge = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.ADMIN_RECHARGE);
            totalRecharge = totalRecharge.add(totalAdminRecharge);
            int todayOrder = (int) contractOrderEntrustService.countByMemberId(member.getId(), startTimeLong, endTimeLong);

            PositionStatVo positionStatVo = memberContractPositionService.findStatVo(member.getId(), startTimeStr, endTimeStr);
            int todayPosition = positionStatVo.getPositionCount();

            MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());
            int groupCount = memberWeightUpperService.findAllByAllUppers(member.getId()).size();

            MemberWithAmountVo vo = new MemberWithAmountVo();
            BeanUtils.copyProperties(member, vo);
            vo.setTotalBalance(totalBalance);
            vo.setCashBalance(cashBalance.doubleValue());
            vo.setContractBalance(contractBalance.doubleValue());
            vo.setFollowBalance(followBalance.doubleValue());
            vo.setTotalProfit(totalProfit);
            vo.setTotalLoss(totalLoss);
            vo.setTodayProfit(todayProfit);
            vo.setTodayLoss(todayLoss);
            vo.setTotalFee(totalFee);
            vo.setTotalAward(totalAward);
            vo.setFollowProfit(followProfit.doubleValue());
            vo.setFollowLoss(followLoss.doubleValue());
            vo.setFollowFee(followFee.doubleValue());
            vo.setFollowAward(followAward.doubleValue());
            vo.setTodayAward(todayAward);
            vo.setTodayOrder((int) todayOrder);
            vo.setTodayPosition(todayPosition);
            vo.setTotalWithdraw(totalWithdraw);
            vo.setTotalRecharge(totalRecharge);
            vo.setAdminRecharge(totalAdminRecharge);
            vo.setEstimatedBalance(estimatedBalance);
            vo.setGameBalance(gameBalance.doubleValue());
            if (memberWeightUpper != null) {
                vo.setRate(memberWeightUpper.getRate());
                vo.setWcRate(memberWeightUpper.getWcRate());
            }
            vo.setGroupCount(groupCount);
            list.add(vo);
        });

        Page<MemberWithAmountVo> newAll = new PageImpl<MemberWithAmountVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }

    @RequiresPermissions("member:page-query")
    @PostMapping("all-with-amount")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找会员Member")
    public MessageResult allWithAmount(
            PageModel pageModel,
            MemberScreen screen) throws ParseException {
        Long[] todayTime = DateUtil.getRealStartAndEndDate(0);
        final long startTimeLong = todayTime[0];
        final long endTimeLong = todayTime[1];
        java.text.SimpleDateFormat sdf1 = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startTimeStr = sdf1.format(new Date(startTimeLong));
        String endTimeStr = sdf1.format(new Date(endTimeLong));
        Predicate predicate = getPredicate(screen);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<MemberWithAmountVo> list = new ArrayList<MemberWithAmountVo>();
        all.forEach(member -> {
            //double[] balance = getUsdtBalanceByMemberId(member.getId());
            //member.setUsdtBalance(balance[0] + balance[1]);
            //TradingAccount tradingAccount = userPurseService.findOneVO(member.getId());
            //BigDecimal totalBalance = memberWalletService.sumBalanceByMemberId(member.getId()).add(tradingAccount.getCurrentCapital());
            //BigDecimal estimatedBalance = memberTransactionService.sumAmountByMemberId(member.getId());
    		/*BigDecimal totalBalance = memberWalletService.sumBalanceByMemberId(member.getId()).add(memberContractWalletService.sumBalanceByMemberId(member.getId()));
        	BigDecimal totalProfit = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_PROFIT);
        	BigDecimal totalLoss = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_LOSS);
        	BigDecimal todayProfit = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_PROFIT);
        	BigDecimal todayLoss = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_LOSS);
        	BigDecimal totalFee = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_FEE);
        	BigDecimal totalAward = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.CONTRACT_AWARD);
        	BigDecimal todayAward = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_AWARD);
        	BigDecimal totalWithdraw = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.WITHDRAW);
        	BigDecimal totalRecharge = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.RECHARGE);
        	BigDecimal totalAdminRecharge = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.ADMIN_RECHARGE);
        	
        	totalRecharge = totalRecharge.add(totalAdminRecharge);
        	long todayOrder = 0;
        	try {
				todayOrder = contractOrderEntrustService.countByMemberId(member.getId(), startTimeLong, endTimeLong);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}*/

            MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());
            int groupCount = memberWeightUpperService.findAllByAllUppers(member.getId()).size();


            MemberWithAmountVo vo = new MemberWithAmountVo();
            BeanUtils.copyProperties(member, vo);
            //vo.setTotalBalance(totalBalance);
        	/*vo.setTotalProfit(totalProfit);
        	vo.setTotalLoss(totalLoss);
        	vo.setTodayProfit(todayProfit);
        	vo.setTodayLoss(todayLoss);
        	vo.setTotalFee(totalFee);
        	vo.setTotalAward(totalAward);
        	vo.setTodayAward(todayAward);
        	vo.setTodayOrder((int)todayOrder);
        	vo.setTotalWithdraw(totalWithdraw);
        	vo.setTotalRecharge(totalRecharge);*/
            //vo.setEstimatedBalance(estimatedBalance);
            if (memberWeightUpper != null)
                vo.setRate(memberWeightUpper.getRate());
            vo.setGroupCount(groupCount);
            list.add(vo);
        });

        Page<MemberWithAmountVo> newAll = new PageImpl<MemberWithAmountVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }

    @RequiresPermissions("member:page-query")
    @PostMapping("under-supervised")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找会员Member")
    public MessageResult underSupervised(
            PageModel pageModel,
            MemberScreen screen) throws ParseException {
    	/*Calendar calendar = Calendar.getInstance();
    	String startTime = DateUtil.getDate();
    	java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
    	Date date = sdf.parse(startTime);
    	String startTimeStr = sdf.format(date);
    	String endTimeStr = startTimeStr + " 23:59:59";*/
        Long[] todayTime = DateUtil.getRealStartAndEndDate(0);
        final long startTimeLong = todayTime[0];
        final long endTimeLong = todayTime[1];
        java.text.SimpleDateFormat sdf1 = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startTimeStr = sdf1.format(new Date(startTimeLong));
        String endTimeStr = sdf1.format(new Date(endTimeLong));
        Predicate predicate = getPositionPredicate(screen, startTimeStr);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<MemberWithAmountVo> list = new ArrayList<MemberWithAmountVo>();
        all.forEach(member -> {
            TradingAccount tradingAccount = userPurseService.findOneVO(member.getId());
            BigDecimal balance = memberWalletService.sumBalanceByMemberId(member.getId());
            BigDecimal contractBalance = tradingAccount.getCurrentCapital();
            BigDecimal todayFee = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startTimeStr, endTimeStr, member.getId(), TransactionType.CONTRACT_FEE);

            PositionStatVo positionStatVo = memberContractPositionService.findStatVo(member.getId(), startTimeStr, endTimeStr);
            int todayPosition = positionStatVo.getPositionCount();
            OrderStatVo orderStatVo = contractOrderEntrustService.findStatVo(member.getId(), startTimeLong, endTimeLong);
            int todayOrder = (int) contractOrderEntrustService.countByMemberId(member.getId(), startTimeLong, endTimeLong);

            MemberWithAmountVo vo = new MemberWithAmountVo();
            BeanUtils.copyProperties(member, vo);
            vo.setTotalBalance(balance);
            vo.setContractBalance(contractBalance.doubleValue());
            vo.setTotalFee(todayFee);
            vo.setTodayOrder(todayOrder);
            vo.setOrderViolateCount(orderStatVo.getViolateCount());
            vo.setTodayPosition(todayPosition);
            vo.setViolateCount(positionStatVo.getViolateCount());
            if (tradingAccount.getIsSupervised() != null)
                vo.setIsSupervised(tradingAccount.getIsSupervised());
            list.add(vo);
        });

        Page<MemberWithAmountVo> newAll = new PageImpl<MemberWithAmountVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }

    @RequiresPermissions("member:update")
    @GetMapping(value = "generateContractWallet")
    public MessageResult generateContractWallet(Long memberId) {
        JSONObject json = new JSONObject();
        json.put("uid", memberId);
        kafkaTemplate.send("member-register-swap", json.toJSONString());
        log.info("json={}", json);
        return success();
    }

    @ApiOperation(value = "查询代理商统计信息", notes = "查询代理商统计信息")
    @RequiresPermissions("member:page-query")
    @PostMapping("/agent/page")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找代理商Member")
    public MessageResult pageAgent(
            PageModel pageModel,
            MemberScreen screen,
            String startStatTime,
            String endStatTime) throws ParseException {
        java.text.SimpleDateFormat sdf1 = new java.text.SimpleDateFormat("yyyy-MM-dd");

        final String startDate;
        if (StringUtils.isNotEmpty(startStatTime)) {
            startDate = startStatTime;
        } else {
            startDate = "1970-1-1";
        }
        final String endDate;
        if (endStatTime == null || endStatTime.equals("")) {
            endDate = DateUtil.getDate() + " 23:59:59";
        } else {
            endDate = endStatTime + " 23:59:59";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date endDateDate = sdf.parse(endDate);
            long balanceEndDateLong = endDateDate.getTime() - endDateDate.getDay() * 24 * 60 * 60000 - 60 * 60000;
        }
        String todayDate = DateUtil.getDate();
        screen.setSuperPartner("1");
        Predicate predicate = getPredicate(screen);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<AgentStatVo> list = new ArrayList<AgentStatVo>();
        all.forEach(member -> {
            List<MemberWeightUpper> subList = memberWeightUpperService.findAllByAllUppers(member.getId());
            List<Long> subIds = new ArrayList<Long>();
            for (MemberWeightUpper upper : subList)
                subIds.add(upper.getMemberId());
            subIds.add(member.getId());
            AgentStatVo vo = new AgentStatVo();
            vo.setMemberId(member.getId());

            BigDecimal swapBalance = userPurseService.sumBalanceByMemberIds(subIds);
            long swapCount = userPurseService.countWithBalanceByMemberIds(subIds);
            BigDecimal followBalance = followWalletService.sumBalanceByMemberIds(subIds);
            long followCount = followWalletService.countWithBalanceByMemberIds(subIds);
            BigDecimal spotBalance = memberWalletService.sumBalanceByMemberIds(subIds);
            BigDecimal totalBalance = spotBalance.add(swapBalance).add(followBalance);

            BigDecimal totalProfit = memberTransactionService.getTotalProfit(subIds, startDate, endDate);
            BigDecimal totalLoss = memberTransactionService.getTotalLoss(subIds, startDate, endDate);
            //BigDecimal totalRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.RECHARGE);
            //BigDecimal totalWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.WITHDRAW);
            BigDecimal totalAward = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.CONTRACT_AWARD);
            BigDecimal totalFee = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.CONTRACT_FEE);
            BigDecimal totalFollowAward = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.FOLLOW_AWARD);
            BigDecimal totalFollowFee = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.FOLLOW_FEE);
            BigDecimal totalDividend = memberTransactionService.sumPositiveAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.FOLLOW_DIVIDEND);
            String[] todayTimeStr = DateUtil.getTodayRealSartAndEndDateStr();
            BigDecimal todayRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.RECHARGE);
            BigDecimal todayWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.WITHDRAW);
            BigDecimal todayFee = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.CONTRACT_FEE);
            String[] yesterdayTimeStr = DateUtil.getTodaySartAndEndDateStr();
            BigDecimal yesterdayRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(yesterdayTimeStr[0], yesterdayTimeStr[1], subIds, TransactionType.RECHARGE);
            BigDecimal yesterdayWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(yesterdayTimeStr[0], yesterdayTimeStr[1], subIds, TransactionType.WITHDRAW);
            BigDecimal totalPrincipalAmount = contractOrderEntrustService.sumTotalPrincipalAmountByMemberIds(subIds);
            log.info("startDate={}, subIds={}", todayDate, subIds);
            int todayUserCount = memberService.countByDateAndIds(todayDate, subIds);

            MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());
            if (memberWeightUpper != null) {
                vo.setRate(memberWeightUpper.getRate());
                vo.setFollowRate(memberWeightUpper.getFollowRate());
                vo.setDividendRate(memberWeightUpper.getDividendRate());
                vo.setWcRate(memberWeightUpper.getWcRate());
            }

            Map<String, String> params = new HashMap<>();
            //params.put("id", member.getId().toString());
            params.put("subIds", subIds.toString());
            String result = HttpSend.post(followServiceUrl + "/follow/follow-infor-agent", params);
            JSONObject jsonObject = JSON.parseObject(result).getJSONObject("data");
            vo.setCancelFollowerCustomer(jsonObject.getInteger("cancelFollowerCustomer"));
            vo.setRemoveFollowerCustomer(jsonObject.getInteger("removeFollowerCustomer"));
            vo.setTeacherIds(jsonObject.getString("teacherIds"));

            vo.setTotalProfit(totalProfit);
            vo.setTotalLoss(totalLoss);
            vo.setTotalRecharge(member.getAgentTotalRecharge());
            vo.setTotalWithdraw(member.getAgentTotalWithdraw());
            vo.setTodayRecharge(todayRecharge);
            vo.setTodayWithdraw(todayWithdraw);
            vo.setTotalFee(totalFee);
            vo.setTodayFee(todayFee);
            vo.setYesterdayRecharge(yesterdayRecharge);
            vo.setYesterdayWithdraw(yesterdayWithdraw);
            vo.setTotalAward(totalAward);
            vo.setTotalPrincipalAmount(totalPrincipalAmount);
            vo.setTodayNewUserCount(todayUserCount);
            Long[] todayTime = DateUtil.getStartAndEndDate(0);
            /*BigDecimal balance = BigDecimal.ZERO;
            if(balanceEndDate==null) {
            	balance = memberWalletService.sumBalanceByMemberIds(subIds);
        		balance = balance.add(userPurseService.sumBalanceByMemberIds(subIds));
            } else
            	balance = memberTransactionService.sumAmountByMemberIdsAndTime("1970-1-1", balanceEndDate, subIds);*/
            int todayOrderCount = contractOrderEntrustService.countActiveMembersByMemberIdsAndTime(todayTime[0], todayTime[1], subIds);
            String[] todayRealTimeStr = DateUtil.getTodayRealSartAndEndDateStr();
            BigDecimal todayAward = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayRealTimeStr[0], todayRealTimeStr[1], subIds, TransactionType.CONTRACT_AWARD);
            vo.setTotalCount(subIds.size());
            vo.setTotalBalance(totalBalance);
            vo.setTotalSwapBalance(swapBalance);
            vo.setTotalSwapCount((int) swapCount);
            vo.setTotalFollowBalance(followBalance);
            vo.setTotalFollowDividend(totalDividend);
            vo.setTotalFollowCount((int) followCount);
            vo.setTotalFollowAward(totalFollowAward);
            vo.setTotalFollowFee(totalFollowFee);
            vo.setTodayOrderCount(todayOrderCount);
            vo.setTodayAward(todayAward);
            vo.setUsername(member.getUsername());
            list.add(vo);
        });
        log.info("2222");

        Page<AgentStatVo> newAll = new PageImpl<AgentStatVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }

    @ApiOperation(value = "查询代理商信息", notes = "查询代理商信息")
    @RequiresPermissions("member:page-query")
    @PostMapping("/agent/info/page")
    @ResponseBody
    @AccessLog(module = AdminModule.MEMBER, operation = "分页查找代理商Member")
    public MessageResult pageAgentInfo(
            PageModel pageModel,
            AccountScreen screen) throws ParseException {
        ArrayList<BooleanExpression> predicates = new ArrayList<>();
        if (!StringUtils.isEmpty(screen.getAccount())) {
            Member member = memberService.findByUsername(screen.getAccount());
            if (member != null) {
                predicates.add(QAgentInfo.agentInfo.id.eq(member.getId()));
            } else {
                predicates.add(QAgentInfo.agentInfo.id.eq(Long.parseLong(screen.getAccount())));
            }
        }
        Page<AgentInfo> results = agentInfoService.findAll(PredicateUtils.getPredicate(predicates), pageModel.getPageable());
        return success(results);

    }

    @PostMapping("/agent/info/modify")
    public MessageResult modifyAgent(AgentInfo agentInfo) {
        agentInfoService.save(agentInfo);
        return MessageResult.success();
    }

    @PostMapping("/agent/info/deletes")
    public MessageResult deleteAgent(@RequestParam(value = "ids") Long[] ids) {
        agentInfoService.deleteBatch(ids);
        return MessageResult.success();
    }

    /**
     * 向指定用户发送自定义邮件
     *
     * @param memberId 用户ID
     * @param subject  邮件主题
     * @param content  邮件正文（支持 HTML）
     * @return 操作结果
     * @author admin
     * @date 2026-04-28
     */
    @ApiOperation(value = "向指定用户发送自定义邮件", notes = "根据用户ID查找邮箱并发送自定义邮件内容")
    @RequiresPermissions("member:all")
    @PostMapping("/send-email")
    @AccessLog(module = AdminModule.MEMBER, operation = "向指定用户发送自定义邮件")
    public MessageResult sendEmail(
            @RequestParam("memberId") Long memberId,
            @RequestParam("subject") String subject,
            @RequestParam("content") String content) throws TemplateException, IOException {

        if (StringUtils.isBlank(subject)) {
            return error("邮件主题不能为空");
        }
        if (StringUtils.isBlank(content)) {
            return error("邮件内容不能为空");
        }

        Member targetMember = memberService.findOne(memberId);
        if (targetMember == null) {
            return error("用户不存在");
        }
        if (StringUtils.isBlank(targetMember.getEmail())) {
            return error("该用户未绑定邮箱，无法发送邮件");
        }

        EmailSendRecord record = new EmailSendRecord();
        record.setMemberId(memberId);
        record.setEmail(targetMember.getEmail());
        record.setSubject(subject);
        record.setContent(content);

        try {
            String html = renderAdminSendEmailHtml(subject, content);
            emailProvider.sendSingleSendMailSync(targetMember.getEmail(), subject, html);
            record.setStatus(1);
            log.info("管理后台向用户 [{}] 邮箱 [{}] 发送自定义邮件，主题：{}", memberId, targetMember.getEmail(), subject);
        } catch (Exception e) {
            record.setStatus(0);
            record.setFailReason(e.getMessage());
            log.error("管理后台向用户 [{}] 发送邮件失败: {}", memberId, e.getMessage());
            return error("邮件发送失败: " + e.getMessage());
        } finally {
            emailSendRecordService.save(record);
        }

        return success("邮件发送成功");
    }

    /**
     * 邮件发送记录列表
     */
    @ApiOperation(value = "邮件发送记录列表")
    @RequiresPermissions("member:all")
    @PostMapping("/email-send-record/list")
    @AccessLog(module = AdminModule.MEMBER, operation = "查询邮件发送记录")
    public MessageResult emailSendRecordList(
            @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
            @RequestParam(value = "pageSize", defaultValue = "15") Integer pageSize,
            @RequestParam(value = "memberId", required = false) Long memberId,
            @RequestParam(value = "subject", required = false) String subject) {

        BooleanExpression predicate = emailSendRecord.isNotNull();
        if (memberId != null) {
            predicate = predicate.and(emailSendRecord.memberId.eq(memberId));
        }
        if (StringUtils.isNotBlank(subject)) {
            predicate = predicate.and(emailSendRecord.subject.like("%" + subject + "%"));
        }
        Sort sort = new Sort(Sort.Direction.DESC, "sendTime");
        Pageable pageable = new PageRequest(pageNo - 1, pageSize, sort);
        Page<EmailSendRecord> page = emailSendRecordService.getDao().findAll(predicate, pageable);
        return success(page);
    }

    private String renderAdminSendEmailHtml(String subject, String content) throws IOException, TemplateException {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
        cfg.setDefaultEncoding("UTF-8");
        Template template = cfg.getTemplate("adminSendEmail.ftl", "UTF-8");
        // 将换行符替换为 <br> 以便 HTML 邮件正确显示换行
        String htmlContent = content.replace("\r\n", "<br>").replace("\n", "<br>");
        Map<String, Object> model = new HashMap<>();
        model.put("subject", subject);
        model.put("content", htmlContent);
        model.put("projectName", sysConfigService.get().getProjectName());
        model.put("projectLogo", sysConfigService.get().getProjectLogo());
        return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
    }
}
