package com.muchinfo.mtp3century.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.muchinfo.mtp.proto.AccountRedis;
import com.muchinfo.mtp.proto.AkernelMI1;
import com.muchinfo.mtp.proto.Common;
import com.muchinfo.mtp.proto.QuoteMI1;
import com.muchinfo.mtp3century.service.ICommonService;
import com.muchinfo.mtp3century.service.ISendMsgService;
import com.muchinfo.mtp3century.utils.RedisServiceUtil;
import com.muchinfo.mtp3common.enumtype.*;
import com.muchinfo.mtp3century.utils.AjaxResult;
import com.muchinfo.mtp3common.utils.DateTimeUtils;
import com.muchinfo.mtp3common.utils.JwtUtil;
import com.muchinfo.mtp3interface.mapper.*;
import com.muchinfo.mtp3pojos.entity.*;
import com.muchinfo.mtp3pojos.vo.FileMetaVo;
import com.muchinfo.mtp3pojos.vo.HolderDetailExRedisVo;
import com.muchinfo.mtp3pojos.vo.RealtimeQuoteVo;
import com.muchinfo.mtp3pojos.vo.bankcusbank.BankCusBankExtendResult;
import com.muchinfo.mtp3pojos.vo.common.*;
import com.muchinfo.mtp3pojos.vo.taaccount.TaAccountQueryResult;
import com.muchinfo.mtp3pojos.vo.taaccount.TaAccountReportParam;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.muchinfo.mtp3common.utils.SerialNumberUtils;
import com.muchinfo.mtp3common.vo.Calculator;
import com.muchinfo.mtp3common.vo.ProtoHelper;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CommonServiceImpl implements ICommonService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private String IS_TARGET_FILENAME = "isTargetFileName";
    @Resource
    private RedisServiceUtil redisServiceUtil;
    @Resource
    private ISystemparamMapper iSystemparamMapper;
    @Resource
    private IUseraccountMapper iUseraccountMapper;
    @Resource
    private IWskhOpenaccountconfigMapper iWskhOpenaccountconfigMapper;
    @Resource
    private IEnumdicitemMapper iEnumdicitemMapper;
    @Resource
    private IBankAccountsignMapper iBankAccountsignMapper;
    @Resource
    private IBankCusbankinfoMapper iBankCusbankinfoMapper;
    @Resource
    private ITaaccountMapper iTaaccountMapper;
    @Resource
    private IGoodsMapper iGoodsMapper;
    @Resource
    private IMarketMapper iMarketMapper;
    @Resource
    private IMarketrunMapper iMarketrunMapper;
    @Resource
    private IUserinfoMapper iUserinfoMapper;
    @Resource
    private IWskhUserinfoMapper iWskhUserinfoMapper;
    @Resource
    private IBankBankinfoMapper iBankBankinfoMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private ILoginaccountMapper iLoginaccountMapper;
    @Resource
    private ISendMsgService iSendMsgService;
    @Resource
    @Qualifier("byteArrayRedisTemplate")
    private RedisTemplate<String, String> stringRedisTemplate;

    /**
     * 获取当前登入用户loginCode
     *
     * @param request
     * @return
     */
    @Override
    public String getUserLoginCode(HttpServletRequest request) {
        String token = request.getHeader(JwtUtil.TOKEN_HEADER).substring(JwtUtil.TOKEN_PREFIX.length());
        //解析token
        Claims claims = JwtUtil.parseToken(token);
        return JwtUtil.getUsername(claims);
    }


    /**
     * 获取系统参数SystemParam
     *
     * @param key
     * @param filed
     * @return
     */
    @Override
    public String getSystemParam(String key, String filed) {
        Object param = redisServiceUtil.getCacheMapValue(key, filed);
        if (Objects.isNull(param)) {
            Systemparam systemparam = iSystemparamMapper.selectOne(new QueryWrapper<Systemparam>().eq("PARAMCODE", filed));
            if (Objects.isNull(systemparam)) {
                return null;
            }
            return systemparam.getParamvalue();
        }
        return param.toString();
    }

    @Override
    public AjaxResult<OrganSelectResult> queryOrganSelect(OrganSelectParam vo, HttpServletRequest request) {
        List<OrganSelectResult> organSelectVo = iUseraccountMapper.queryOrganSelect(vo);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), organSelectVo);
    }

    @Override
    public AjaxResult<FileMetaVo> uploadFile(HttpServletRequest request) {
        WskhOpenaccountconfig configtype = iWskhOpenaccountconfigMapper.selectOne(new QueryWrapper<WskhOpenaccountconfig>().eq("CONFIGTYPE", 6));
        List<FileMetaVo> res = new ArrayList<>();

        String getImagePath = configtype.getConfigvalue() + "/uploadFile/" + DateTimeUtils.formatChar(new Date(), null) + "/";
        File file = new File(getImagePath);
        if (!file.exists()) {
            file.mkdirs();
        }

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultiValueMap<String, MultipartFile> multipartMap = multipartRequest.getMultiFileMap();
        try {
            for (Map.Entry<String, List<MultipartFile>> entry : multipartMap.entrySet()) {

                List<MultipartFile> multipartFile = entry.getValue();
                for (MultipartFile item : multipartFile) {
                    FileMetaVo meta = new FileMetaVo();

                    String filePageName = item.getName();
                    String fileName = item.getOriginalFilename();
                    if (!request.getParameterMap().containsKey(IS_TARGET_FILENAME)) {
                        fileName = this.generateFileName(fileName);
                    }
                    FileCopyUtils.copy(item.getBytes(), Files.newOutputStream(Paths.get(getImagePath + fileName)));
                    meta.setSubmitName(entry.getKey());
                    meta.setOriginalName(item.getOriginalFilename());
                    meta.setFilePageName(filePageName);
                    meta.setFileName(fileName);
                    meta.setFileSize(item.getSize() / 1024 + "KB");
                    meta.setFileType(item.getContentType());

                    meta.setFilePath("./uploadFile/" + DateTimeUtils.formatChar(new Date(), null) + "/" + fileName);
                    res.add(meta);
                }
            }
        } catch (Exception e) {
            logger.error("文件上传失败，失败原因=" + e);
            return AjaxResult.error(Constants.Error_Code_Design, MessageType.MESSAGE_ERROR_CODE_SYSTEM004.getCode(), request.getHeader("Accept-Language"));
        }
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), res);
    }

    /**
     * 获取登录时的sign用于详细数据解密
     *
     * @return
     */

    @Override
    public AjaxResult getEnumType(String typeCode, HttpServletRequest request) {
        List<Enumdicitem> enumdicitems = iEnumdicitemMapper.selectInternational(typeCode);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), enumdicitems);
    }

    @Override
    public AjaxResult<InvestorSelectResult> queryInvestorSelect(InvestorSelectParam investorSelectParam, HttpServletRequest request) {
        List<InvestorSelectResult> investorSelectResults = iUseraccountMapper.queryInvestorSelect(investorSelectParam);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), investorSelectResults);
    }

    @Override
    public AjaxResult<BankAccountsign> getSignBank(HttpServletRequest request) {
        List<BankAccountsign> bankAccountsignList = iBankAccountsignMapper.selectList(new QueryWrapper<>());
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), bankAccountsignList);
    }

    @Override
    public AjaxResult<CusBankInfoResult> getBankInfoByCusBank(String cusBankId, String bankName, HttpServletRequest request) {
        List<CusBankInfoResult> cusBankInfoResults = iBankCusbankinfoMapper.getBankInfoByCusBank(cusBankId, bankName);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), cusBankInfoResults);
    }

    @Override
    public AjaxResult<TAAccountChildrenResult> queryTAAccountChildren(String accountName, Long areaUserId, HttpServletRequest request) {
        List<TAAccountChildrenResult> results = iTaaccountMapper.queryTAAccountChildren(accountName, areaUserId);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), results);
    }

    @Override
    public AjaxResult<GoodsSelectResult> queryGoodsSelect(GoodsSelectParam param, HttpServletRequest request) {
        String[] split = new String[0];
        String[] tradeModeSplit = new String[0];
        if (StringUtils.isNotBlank(param.getGoodsStatusIds())) {
            split = param.getGoodsStatusIds().split(",");
        }
        if (("," + param.getOrgztypes() + ",").contains(",3,")) {
            param.setAreauserid(null);
        }
        if (StringUtils.isNotBlank(param.getTrademodels())) {
            tradeModeSplit = param.getTrademodels().split(",");
        }

        List<GoodsSelectResult> goodsSelectResults = iGoodsMapper.queryGoodsSelect(split, tradeModeSplit, param);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), goodsSelectResults);
    }

    @Override
    public AjaxResult<Market> getOrderListAll(List<Long> markets, HttpServletRequest request) {
        QueryWrapper<Market> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("markettype", 2)
                .eq("marketstatus", SysEnums.EnumMarketStatus.NORMAL.getType());

        // 只有当markets非空时，才添加marketid的IN条件
        if (markets != null && !markets.isEmpty()) {
            queryWrapper.in("marketid", markets);
        }
        //收益权  所有权  期权 币交易
        List<Market> marketList = iMarketMapper.selectList(queryWrapper);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), marketList);
    }

    @Override
    public AjaxResult<InvestorSelectResult> getOrganListAll(Long userId, String searchCode, HttpServletRequest request) {
        List<InvestorSelectResult> results = iUseraccountMapper.getOrganListAll(userId, searchCode);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), results);
    }

    @Override
    public String getSysparmById(String number) {
        Systemparam systemparam = iSystemparamMapper.selectOne(new QueryWrapper<Systemparam>().eq("PARAMCODE", number));
        if (Objects.isNull(systemparam)) {
            return null;
        }
        return systemparam.getParamvalue();
    }

    /**
     * 计算浮动盈亏
     * 收益权=(最新价*持仓数量*合约单位 - 持仓金额) *方向(买[1]:卖[-1])
     * 所有权=(最新价*持仓数量*合约单位 - 持仓金额)
     * 根据“系统“市场状态：(24.资金结算成功 26.系统结算成功 27.系统结算失败)
     * 1.系统状态= (24\26\27)时：
     * 最新价顺序：实时结算价->最新成交价->昨日结算
     * 2.系统状态 !=(24\26\27) 时：
     * 最新价顺序：最新成交价->昨日结算
     * 最新价均获取不到，则该商品持仓不计算浮动盈亏
     */
    @Override
    public BigDecimal calcFloaPL(String goodsCode, BigDecimal agreeUnit, Integer buyorsell, Integer holdQty, BigDecimal holderamount) {
        BigDecimal floatPL = BigDecimal.ZERO;//浮动盈亏
        try {
            BigDecimal newPrice = BigDecimal.ZERO;//最新价
            byte[] valuebts = redisServiceUtil.getBytes("QUOTE:" + goodsCode);
            ;
            if (valuebts != null) {
                QuoteMI1.RealtimeQuote goodQuot = QuoteMI1.RealtimeQuote.parseFrom(valuebts);
                BigDecimal pow = BigDecimal.TEN.pow(goodQuot.getDecimalPlace());
                //根据“系统“市场状态取价格
                Marketrun mr = iMarketrunMapper.selectOne(new QueryWrapper<Marketrun>().eq("marketid", 0L));
                if (mr.getRunstatus() == 24 || mr.getRunstatus() == 26 || mr.getRunstatus() == 27) {
                    //状态为24,26,27
                    //最新价顺序：实时结算价->最新成交价->昨日结算
                    if (goodQuot.getReckonPrice() > 0) {
                        newPrice = new BigDecimal(goodQuot.getReckonPrice());
                    } else if (goodQuot.getLast() > 0) {
                        newPrice = new BigDecimal(goodQuot.getLast());
                    } else if (goodQuot.getPreReckonPrice() > 0) {
                        newPrice = new BigDecimal(goodQuot.getPreReckonPrice());
                    }
                } else {
                    //最新价顺序：最新成交价->昨日结算
                    if (goodQuot.getLast() > 0) {
                        newPrice = new BigDecimal(goodQuot.getLast());
                    } else if (goodQuot.getPreReckonPrice() > 0) {
                        newPrice = new BigDecimal(goodQuot.getPreReckonPrice());
                    }
                }
                //最新价均获取不到，则该商品持仓不计算浮动盈亏
                newPrice = newPrice.divide(pow);
                if (newPrice.compareTo(new BigDecimal(0)) > 0) {
                    int bsFlat = buyorsell == 0 ? 1 : -1;
                    // 浮动盈亏统一公式 (最新价*持仓数量*合约单位 - 持仓金额) *方向(买[1]:卖[-1])
                    floatPL = newPrice.multiply(agreeUnit).multiply(BigDecimal.valueOf(holdQty)).subtract(holderamount).multiply(new BigDecimal(bsFlat)).setScale(2, BigDecimal.ROUND_HALF_UP);
                }
            }
        } catch (Exception e) {
            logger.error("计算浮动盈亏失败，失败原因：" + e.getMessage());
        }
        return floatPL;
    }

    @Override
    public AjaxResult<BankCusbankinfo> getAllBankCus(HttpServletRequest request) {
        List<BankCusbankinfo> cusbankinfos = iBankCusbankinfoMapper.selectList(new QueryWrapper<>());
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), cusbankinfos);
    }

    @Override
    public AjaxResult<BankCusBankExtendResult> queryBooleanForAmount(String cusbankid, Integer extendbiztype, Integer usabletype, HttpServletRequest request) {
        List<BankCusBankExtendResult> biztypeList = iBankCusbankinfoMapper.queryFieldById(cusbankid, extendbiztype, usabletype);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), biztypeList);
    }

    //生成新的文件名
    private String generateFileName(String fileName) {
        DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        String formatDate = format.format(new Date());
        int random = new Random().nextInt(10000);
        int position = fileName.lastIndexOf(".");
        String extension = fileName.substring(position);
        return formatDate + random + extension;
    }

    /**
     * 用于判断用户操作权限
     *
     * @param systemmanager
     * @param userId
     * @return
     */
    public boolean checkUserAccountRole(Systemmanager systemmanager, Long userId) {
        //平台
        if (systemmanager.getReletype() == 1) {
            return true;
        }
        //会员或子机构
        if (systemmanager.getReletype() == 2 || systemmanager.getReletype() == 3) {
            Useraccount useraccount = iUseraccountMapper.selectOne(new QueryWrapper<Useraccount>().eq("userid", userId));
            if (Objects.isNull(useraccount)) {
                return false;
            }
            if (useraccount.getSubarealevelpath().contains("," + systemmanager.getAreauserid().toString() + ",")) {
                return true;
            }
        }
        return false;
    }

    public boolean checkTaAccountReport(Systemmanager systemmanager, Long accountId) {
        if (systemmanager.getReletype() == 1) {
            return true;
        }
        TaAccountReportParam vo = new TaAccountReportParam();
        vo.setAccountId(accountId);
        vo.setUserId(systemmanager.getAreauserid());
        List<TaAccountQueryResult> voList = queryTAAccount(vo);
        //不是本机构的资金账户不能使用
        return !voList.isEmpty();
    }

    public boolean checkIsAreaSon2(Long fUserId, Long userid) {
        Useraccount u = iUseraccountMapper.selectOne(new QueryWrapper<Useraccount>().eq("userid", userid));
        return u.getSubarealevelpath().indexOf("," + fUserId + ",") >= 0;
    }

    public Boolean checkOranCardNumOrMobile(Integer checkType, Integer checkField, Long userid, String message) {
        if (StringUtils.isBlank(message)) return true;
        Long wskhUserinfoList = 0L;
        Long userinfoList = 0L;

        if (checkType == 1) {
            wskhUserinfoList = iWskhUserinfoMapper.selectCount(new QueryWrapper<WskhUserinfo>()
                    .eq(checkField == 1, "cardnum", message)
                    .eq(checkField == 2, "mobile", message)
                    .ne(userid != null, "userid", userid));
        } else if (checkType == 2) {
            userinfoList = iUserinfoMapper.selectCount(new QueryWrapper<Userinfo>()
                    .eq(checkField == 1, "cardnum", message)
                    .eq(checkField == 2, "mobile", message)
                    .ne(userid != null, "userid", userid));
        } else if (checkType == 3) {
            wskhUserinfoList = iWskhUserinfoMapper.selectCount(new QueryWrapper<WskhUserinfo>()
                    .eq(checkField == 1, "cardnum", message)
                    .eq(checkField == 2, "mobile", message)
                    .ne(userid != null, "userid", userid));
            userinfoList = iUserinfoMapper.selectCount(new QueryWrapper<Userinfo>()
                    .eq(checkField == 1, "cardnum", message)
                    .eq(checkField == 2, "mobile", message)
                    .ne(userid != null, "userid", userid));
        }
        return wskhUserinfoList + userinfoList == 0;
    }

    @Override
    public AjaxResult<BankAccountsign> getBankAccountSign(Long accountcode, Integer signstatus, HttpServletRequest request) {
        List<BankAccountsign> bankAccountsign = iBankAccountsignMapper.selectList(new QueryWrapper<BankAccountsign>()
                .eq(accountcode != null, "ACCOUNTCODE", accountcode)
                .eq(signstatus != null, "signstatus", signstatus)
        );
        bankAccountsign.forEach(a -> {
            a.setCusbankname(iBankCusbankinfoMapper.selectOne(new QueryWrapper<BankCusbankinfo>().eq("cusbankid", a.getCusbankid())).getCusbankname());
            a.setBankname(iBankBankinfoMapper.selectOne(new QueryWrapper<BankBankinfo>().eq("BANKID", a.getBankid())).getBankname());
        });
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), bankAccountsign);
    }

    @Override
    public AjaxResult queryMoney(Long accountid, Integer type, Integer mtype, HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        Long id = accountid;
        if (type == 2) {
            //转入 查询母账户可转出余额
            Taaccount taa = iTaaccountMapper.selectOne(new QueryWrapper<Taaccount>().eq("accountid", accountid));
            id = taa.getFromaccountid();
        }

        Taaccount taa = iTaaccountMapper.selectOne(new QueryWrapper<Taaccount>().eq("accountid", id));
        result.put("money", BigDecimal.ZERO);
        result.put("currencyid", taa.getCurrencyid());
        Long uuid = SerialNumberUtils.getNewSerialNumber(SerialNumberUtils.prefix_account);

        //可出资金  接口
        AkernelMI1.AccountFundInfoReq.Builder builder = AkernelMI1.AccountFundInfoReq.newBuilder();
        Common.MessageHead.Builder hd = Common.MessageHead.newBuilder();
        hd.setAccountID(id);
        hd.setClientTime(System.currentTimeMillis());
        hd.setResponseTopic(SysConstants.RabbitMoneyReqKey);
        hd.setFunCode(FunCodeConstants.FunCode_Trade_AccountFundInfoReq);
        builder.setOrderId(uuid);
        builder.setAccountId(id);
        builder.setQueryBitMask(mtype);
        byte[] body = ProtoHelper.getNTAS(builder.build().toByteArray(),
                FunCodeConstants.FunCode_Trade_AccountFundInfoReq);
        logger.debug("sssss---{}", builder.build().toString());
        //卡住
        Calculator ca = new Calculator(uuid);
        SerialNumberUtils.lockMap.put(uuid, ca);

        if (taa.getTaaccounttype() == 1) {
            rabbitTemplate.send(SysConstants.TOPIC_REQ_EX_MONEY, new Message(body, new MessageProperties()));
        } else {
            rabbitTemplate.send(SysConstants.RabbitMoneyReqKey, new Message(body, new MessageProperties()));
        }
        synchronized (ca) {
            try {
                ca.wait(6000);
                Object o = ca.obj;
                if (o != null) {
                    AkernelMI1.AccountFundInfoRsp rsp = (AkernelMI1.AccountFundInfoRsp) o;
                    logger.info("AccountFundInfoReq---{},---{}", rsp.getAvailableMargin(), rsp.getAvailableOutMoney());
                    double money = mtype == 1 ? rsp.getAvailableMargin() : rsp.getAvailableOutMoney();
                    logger.info("money:{},changeMoney:{}", money, new BigDecimal(money).setScale(2, RoundingMode.HALF_UP));
                    result.put("money", new BigDecimal(money).setScale(2, RoundingMode.HALF_UP));
                }
            } catch (InterruptedException e) {
                logger.error("获取可用金额失败，失败原因：" + e.getMessage());
            } finally {
                SerialNumberUtils.lockMap.remove(uuid);
            }
        }
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), result);
    }

    @Override
    public boolean checkTaaccountReport(Systemmanager systemmanager, Long accountid) {
        if (systemmanager.getReletype() == 1) {
            return true;
        }
        TaAccountReportParam vo = new TaAccountReportParam();
        vo.setAccountId(accountid);
        vo.setUserId(systemmanager.getAreauserid());
        List<TaAccountQueryResult> taAccountQueryResults = queryTAAccount(vo);
        //不是本机构的资金账户不能使用
        if (CollectionUtils.isNotEmpty(taAccountQueryResults)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean checkLoginAccountRole(Systemmanager systemmanager, Long loginid) {
        //平台
        if (systemmanager.getReletype() == 1) {
            return true;
        }

        //会员或子机构
        if (systemmanager.getReletype() == 2 || systemmanager.getReletype() == 3) {
            Loginaccount la = iLoginaccountMapper.selectOne(new QueryWrapper<Loginaccount>().eq("loginid", loginid));
            if (la == null) {
                return false;
            }
            Useraccount ua = iUseraccountMapper.selectOne(new QueryWrapper<Useraccount>().eq("userid", la.getUserid()));
            if (ua == null) {
                return false;
            }
            if (ua.getSubarealevelpath().contains("," + systemmanager.getAreauserid().toString() + ",")) {
                return true;
            }
        }
        return false;
    }

    @Override
    public AjaxResult<CommonResult> queryCommonFlag(CommonParam commonParam, HttpServletRequest request) {
        CommonResult commonResult = new CommonResult();
        if (commonParam.getAccountid() != null) {
            //获取资金管理银行签约账户类型控制枚举
            Taaccount ta = iTaaccountMapper.selectOne(new QueryWrapper<Taaccount>().eq("accountid", commonParam.getAccountid()));
            // 客户信息放条件外 -- 20231009 对未签约信息修改时，若修改了用户信息，证件号等还是会取未签约里的内容
            Userinfo ui = iUserinfoMapper.selectOne(new QueryWrapper<Userinfo>().eq("userid", ta.getUserid()));
            commonResult.setCardnum(ui.getCardnum());
            commonResult.setCardtypeid(ui.getCardtypeid());
            commonResult.setUserinfotype(ui.getUserinfotype());
            commonResult.setCustomername(ui.getCustomername());
            commonResult.setMobile(ui.getMobile());
        }
        //获取市场交易日期
        Marketrun mr = iMarketrunMapper.selectOne(new QueryWrapper<Marketrun>().eq("marketid", 0L));
        commonResult.setTradedate(mr.getTradedate());
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), commonResult);
    }

    @Override
    public void sendMsg(Loginaccount la, int type) {
        Set<Long> logins = new HashSet<>();
        logins.add(la.getLoginid());

        // 0 新增帐号 1 删除帐号  2 修改帐号 3 修改帐号个性化 4 修改账户权限 5 删除三方登陆信息
        Thread myThread = new Thread(new Runnable() {
            public void run() {
                try {
                    // 使用线程发送消息  延迟5秒发送, 避免数据库未写入
                    Thread.sleep(5000);

                    iSendMsgService.sendLoginMsg(logins, type, 0);
                } catch (Exception ex) {
                    logger.error("发送消息" + type + "失败，失败原因：" + ex.getMessage());
                }
            }
        });

        // 启动线程
        myThread.start();
    }

    @Override
    public List<HolderDetailExRedisVo> getHolderDetailExFromRedis(HolderDetailExRedisVo param, int flag) {
        // flag=1:YJ(按定金率，值小风险大  flag=2:交易中心(按风险率，值大风险大)
        List<HolderDetailExRedisVo> resultList = new ArrayList<>();
        try {
            StringBuilder key = new StringBuilder("TradeHolderDetailEx:");
            // 根据方向过滤
            if (param.getBuyorsell() != null) {
                key.append("*_").append(param.getBuyorsell()).append("_");
            }
            key.append("*");

            Set<String> set = stringRedisTemplate.keys(key.toString());
            Enumdicitem buyItem = iEnumdicitemMapper.selectOne(new QueryWrapper<Enumdicitem>()
                    .eq("enumdiccode", "buyOrSell").eq("enumitemname", 0L));
            String buyStr = buyItem == null ? "B" : buyItem.getEnumdicname();
            Enumdicitem sellItem = iEnumdicitemMapper.selectOne(new QueryWrapper<Enumdicitem>()
                    .eq("enumdiccode", "buyOrSell").eq("enumitemname", 1L));
            String sellStr = sellItem == null ? "S" : sellItem.getEnumdicname();

            BigDecimal riskParam = null;
            if (param.getRisk() != null) {
                riskParam = param.getRisk().divide(new BigDecimal(100));
            }
            if (CollectionUtils.isNotEmpty(set)) {
                for (String str : set) {
                    byte[] valuebts = redisServiceUtil.getBytes(str);
                    if (valuebts != null) {
                        try {
                            AccountRedis.RedisTradeHolderDetailEx redisEx = AccountRedis.RedisTradeHolderDetailEx.newBuilder().mergeFrom(valuebts).build();
                            if (redisEx != null && redisEx.getTHDetailEx() != null) {
                                AccountRedis.TradeHolderDetailEx ex = redisEx.getTHDetailEx();
                                // 过滤持仓量为0的单据（当天已平仓）
                                if (ex.getHolderQty() == 0L) {
                                    continue;
                                }
                                // flag=1:YJ(按定金率，值小风险大  flag=2:交易中心(按风险率，值大风险大)
                                if (flag == 1) {
                                    // 根据 定金率 risk 过滤 值小风险大
                                    if (riskParam != null && BigDecimal.valueOf(ex.getDepositRate()).compareTo(riskParam) >= 0) {
                                        continue;
                                    }
                                } else if (flag == 2) {
                                    // 根据 风险率 risk 过滤 值大风险大
                                    if (riskParam != null && riskParam.compareTo(BigDecimal.valueOf(ex.getDepositRate())) >= 0) {
                                        continue;
                                    }
                                }
                                // 过滤不合法单据号
                                if (ex.getTradeID() <= 0L) {
                                    continue;
                                }
                                // 根据商品过滤
                                if (!StringUtils.isBlank(param.getGoodsfullname())) {
                                    String goodsSearch = param.getGoodsfullname().trim();
                                    if (!goodsSearch.equals(redisEx.getGoodsCode()) && !goodsSearch.equals(redisEx.getGoodsName())) {
                                        continue;
                                    }
                                }

                                HolderDetailExRedisVo vo = new HolderDetailExRedisVo();
                                vo.setTradeid(String.valueOf(ex.getTradeID()));

                                vo.setUserfullname(ex.getUserID() + "");
                                Useraccount ua = iUseraccountMapper.selectOne(new QueryWrapper<Useraccount>().eq("userid", ex.getUserID()));
                                if (ua != null) {
                                    // 根据选择客户过滤
                                    if (!StringUtils.isBlank(param.getUserfullname())) {
                                        String username = param.getUserfullname().trim();
                                        if (!Integer.toString(ex.getUserID()).contains(username) &&
                                                !ua.getAccountname().contains(username) &&
                                                !Long.toString(ex.getAccountID()).contains(username)
                                        ) {
                                            continue;
                                        }
                                    }

                                    // 根据所属机构代码过滤
                                    if (!StringUtils.isBlank(param.getParentusername())) {
                                        String memberuserid = param.getParentusername().trim();
                                        if (!memberuserid.equals(ua.getMemberuserid().toString())) {
                                            continue;
                                        }
                                    }

                                    vo.setUserfullname(ua.getUserid() + "/" + ua.getAccountname());
                                    vo.setMemberusername(iUseraccountMapper.selectOrganName(ua.getMemberuserid()));
                                    if (ua.getMemberuserid().equals(ua.getParentuserid())) {
                                        vo.setParentusername("--");
                                    } else {
                                        vo.setParentusername(iUseraccountMapper.selectOrganName(ua.getMemberuserid()));
                                    }
                                }
                                vo.setGoodsCode(redisEx.getGoodsCode());
                                vo.setGoodsfullname(redisEx.getGoodsCode() + "/" + redisEx.getGoodsName());
                                vo.setBuyorsell(ex.getBuyOrSell());
                                vo.setBuyorselldisplay(ex.getBuyOrSell() == 1 ? sellStr : buyStr);
                                vo.setHolderprice(BigDecimal.valueOf(ex.getHolderPrice()));
                                long num = ex.getHolderQty() * (long) redisEx.getAgreeUnit();
                                vo.setHolderqty(ex.getHolderQty());
                                vo.setAgreeunit(redisEx.getAgreeUnit());
                                vo.setHoldernum(Long.toString(num));
                                vo.setHolderamount(BigDecimal.valueOf(ex.getHolderAmount()).setScale(2, RoundingMode.HALF_UP));
                                vo.setPayeddeposit(BigDecimal.valueOf(ex.getPayedDeposit()).setScale(2, RoundingMode.HALF_UP));
                                vo.setRestockdeposit(BigDecimal.valueOf(ex.getRestockDeposit()).setScale(2, RoundingMode.HALF_UP));
                                vo.setCallatefee(BigDecimal.valueOf(ex.getCallAteFee()).setScale(2, RoundingMode.HALF_UP));
                                vo.setHolddays(ex.getHoldDays() + 1);
                                vo.setFloatpl(BigDecimal.valueOf(ex.getFloatPL()).setScale(2, RoundingMode.HALF_UP));

                                if (flag == 1) {
                                    // 四舍五入（值越小风险越大）
                                    vo.setDepositrate(BigDecimal.valueOf(ex.getDepositRate()).setScale(4, RoundingMode.HALF_UP));
                                } else {
                                    // 截断（值越大风险越大）
                                    vo.setDepositrate(BigDecimal.valueOf(ex.getDepositRate()).setScale(4, RoundingMode.DOWN));
                                }
                                vo.setDepositratedisplay(vo.getDepositrate().multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP) + "%");
                                vo.setPromptdepositrate(BigDecimal.valueOf(ex.getPromptDepositRate()).setScale(4, RoundingMode.HALF_UP));
                                vo.setCutdepositrate(BigDecimal.valueOf(ex.getCutDepositRate()).setScale(4, RoundingMode.HALF_UP));
                                long freezeNum = ex.getFreezeQty() * (long) redisEx.getAgreeUnit();
                                vo.setFreezeqty(ex.getFreezeQty());
                                vo.setFreezenum(Long.toString(freezeNum));
                                // 添加现价(平仓价)
                                RealtimeQuoteVo quote = getRealtimeQuote(redisEx.getGoodsCode(), redisEx.getDecimalPlace());
                                if (quote == null) {
                                    vo.setLastprice("--");
                                } else {
                                    if (vo.getBuyorsell().equals(0)) {
                                        // 买单显示买价
                                        if (quote.getBid() == null) {
                                            vo.setLastprice("--");
                                        } else {
                                            vo.setLastprice(quote.getBid().toString());
                                        }
                                    } else if (vo.getBuyorsell().equals(1)) {
                                        // 卖单显示卖价
                                        if (quote.getAsk() == null) {
                                            vo.setLastprice("--");
                                        } else {
                                            vo.setLastprice(quote.getAsk().toString());
                                        }
                                    }
                                }

                                // 添加提示价格、
                                String promptPrice = BigDecimal.valueOf(ex.getPromptPrice()).setScale(redisEx.getDecimalPlace(), RoundingMode.HALF_UP).toString();
                                vo.setPromptprice(promptPrice);
                                String cutPrice = BigDecimal.valueOf(ex.getCutPrice()).setScale(redisEx.getDecimalPlace(), RoundingMode.HALF_UP).toString();
                                vo.setCutprice(cutPrice);
                                //vo.setTradetimestr(ex.getTradeTime());
                                resultList.add(vo);

                            }
                        } catch (Exception e) {
                            logger.error("获取风险率等信息失败，失败原因:" + e.getMessage());
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("获取风险率等信息失败，失败原因:" + e.getMessage());
        }
        return resultList;
    }

    @Override
    public AjaxResult<OrganSelectResult> queryOrganSelect2And3(OrganSelectParam param, HttpServletRequest request) {
        List<OrganSelectResult> results = iUseraccountMapper.queryOrganSelect2And3(param);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), results);
    }

    @Override
    public RealtimeQuoteVo getRealtimeQuote(String goodscode, int decimalplace) {
        RealtimeQuoteVo entity = null;
        byte[] value = redisServiceUtil.getBytes("QUOTE:" + goodscode);
        String strUnit = "1";
        for (int i = 0; i < decimalplace; i++) {
            strUnit += "0";
        }
        double decimal = Double.parseDouble(strUnit);
        try {
            QuoteMI1.RealtimeQuote quoteProto = QuoteMI1.RealtimeQuote.parseFrom(value);
            if (quoteProto != null) {
                entity = new RealtimeQuoteVo();
                entity.setLast((double) quoteProto.getLast() / decimal);
                entity.setOpen((double) quoteProto.getOpen() / decimal);
                entity.setHigh((double) quoteProto.getHigh() / decimal);
                entity.setLow((double) quoteProto.getLow() / decimal);
                entity.setPreclose((double) quoteProto.getPreClose() / decimal);
                entity.setReckonprice((double) quoteProto.getReckonPrice() / decimal);
                entity.setLowlimit((double) quoteProto.getLowLimit() / decimal);
                entity.setHighlimit((double) quoteProto.getHighLimit() / decimal);
                entity.setAverage((double) quoteProto.getAverage() / decimal);

                if (quoteProto.getBidPriceArrayCount() > 0 && quoteProto.getBidPriceArray(0) > 0) {
                    entity.setBid(quoteProto.getBidPriceArray(0) / decimal);
                }
                if (quoteProto.getAskPriceArrayCount() > 0 && quoteProto.getAskPriceArray(0) > 0) {
                    entity.setAsk(quoteProto.getAskPriceArray(0) / decimal);
                }
            }
        } catch (Exception e) {
            logger.error("获取实时行情异常", e);
            entity = null;
        }
        return entity;
    }

    @Override
    public AjaxResult<Taaccount> queryAccountId(Long userid, HttpServletRequest request) {
        List<Taaccount> list = iTaaccountMapper.selectList(new QueryWrapper<Taaccount>().eq("userid", userid));
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), list);
    }

    @Override
    public AjaxResult<TaAccountQueryResult> queryTAAccountList(TaAccountReportParam param, HttpServletRequest request) {
        List<TaAccountQueryResult> list = queryTAAccount(param);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), list);
    }

    @Override
    public AjaxResult<Userinfo> queryUserinfoUserId(Long userid, HttpServletRequest request) {
        Userinfo userinfo = iUserinfoMapper.selectOne(new QueryWrapper<Userinfo>().eq("userid", userid));
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), userinfo);
    }

    @Override
    public AjaxResult<OrganSelectResult> queryExchSonOrgin(OrganSelectParam vo, HttpServletRequest request) {
        List<OrganSelectResult> organSelectVo = iUseraccountMapper.queryExchSonOrgin(vo);
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), organSelectVo);
    }

    @Override
    public AjaxResult<WskhOpenaccountconfig> queryConfig(Long configid, HttpServletRequest request) {
        // 获取网上开户参数54:手持证件照是否显示
        WskhOpenaccountconfig config = iWskhOpenaccountconfigMapper.selectOne(new QueryWrapper<WskhOpenaccountconfig>().eq("configid", configid));
        if (config != null && StringUtils.isNotBlank(config.getConfigvalue())) {
            return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), config);
        }
        return AjaxResult.error(Constants.Success_Code_Design, MessageType.MESSAGE_ERROR_CODE_SYSTEM002.getCode(), request.getHeader("Accept-Language"));
    }

    @Override
    public AjaxResult<Taaccount> queryAccountIdForMarket(Long userid, HttpServletRequest request) {
        List<Enumdicitem> eiList = iEnumdicitemMapper.selectList(new QueryWrapper<Enumdicitem>().eq("enumdiccode", "currency"));
        List<Integer> integers = eiList.stream().map(Enumdicitem::getEnumitemname).collect(Collectors.toList());
        List<Taaccount> list = iTaaccountMapper.selectList(new QueryWrapper<Taaccount>()
                .eq("userid", userid).in("currencyid", integers));
        return AjaxResult.success(Constants.Success_Code_Design, MessageType.MESSAGE_CODE_SYSTEM001.getCode(), request.getHeader("Accept-Language"), list);
    }


    public List<TaAccountQueryResult> queryTAAccount(TaAccountReportParam param) {
        return iTaaccountMapper.queryTAAccount(param);
    }
}
