package com.copy.trade.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.copy.trade.bean.RedisLock;
import com.copy.trade.constant.KafkaTopic;
import com.copy.trade.constant.RedisKey;
import com.copy.trade.consumer.MarketListener;
import com.copy.trade.dao.CopiedTradeMapper;
import com.copy.trade.entity.dto.*;
import com.copy.trade.entity.form.CopiedTradeForm;
import com.copy.trade.entity.po.*;
import com.copy.trade.entity.vo.CopiedTradeVo;
import com.copy.trade.enums.DirectionEnum;
import com.copy.trade.enums.EntrustStatusEnum;
import com.copy.trade.enums.EntrustTypeEnum;
import com.copy.trade.enums.FollowConfigEnum;
import com.copy.trade.enums.MessageTypeEnum;
import com.copy.trade.enums.PositionStatusEnum;
import com.copy.trade.enums.TraderEnum;
import com.copy.trade.service.*;

import java.math.RoundingMode;

import com.copy.trade.util.BeanCopior;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 跟单记录表 服务实现类
 * </p>
 *
 * @author wz
 * @since 2022-11-08
 */
@Service
public class CopiedTradeServiceImpl extends ServiceImpl<CopiedTradeMapper, CopiedTrade> implements ICopiedTradeService {

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

    private final String ORDER_NO_PREFIX = "COPY";

    @Autowired
    private ICustomerService customerServiceImpl;

    @Autowired
    private ICustomerFollowSymbolService customerFollowSymbolServiceImpl;

    @Autowired
    private ITraderSymbolService traderSymbolServiceImpl;

    @Autowired
    private IRiskControlService riskControlServiceImpl;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ICopiedTradeService copiedTradeService;

    @Autowired
    private IPositionService positionServiceImpl;

    @Autowired
    private MarketListener marketListener;

    @Autowired
    private ITraderLevelService traderLevelServiceImpl;

    @Autowired
    private IMessageService messageServiceImpl;

    @Autowired
    private IFollowConfigService followConfigServiceImpl;

    @Override
    @Transactional
    public Boolean copyTrade(ContractOrderEntrust traderOrder) {
        log.info("copyTrade:老师开仓成功,老师memberId:{},order数据:{}", traderOrder.getMemberId(), JSON.toJSONString(traderOrder));
        //1.验证是否是交易员
        Customer trader = customerServiceImpl.getByMemberId(traderOrder.getMemberId());
        if (trader == null || !trader.getTrader().equals(TraderEnum.TRADER.getStatus())) {
            return true;
        }
        //获取交易员的分润比例
        TraderLevel traderLevel = traderLevelServiceImpl.getById(trader.getTraderLevelId());
        //2.验证是否开启跟单
        TraderSymbol traderSymbol = traderSymbolServiceImpl.getByTraderAndSymbol(trader.getId(), traderOrder.getSymbol());
        if (traderSymbol == null) {
            return true;
        }
        boolean lock = redisLock.lock(RedisKey.LOCK_UNFOLLOW, trader.getId().toString(), 100);
        if (!lock) {
            return false;
        }
        List<CustomerFollowSymbol> customerFollowSymbolList = customerFollowSymbolServiceImpl.listByTraderAndSymbol(trader.getId(), traderSymbol.getSymbol());
        redisLock.unlock(RedisKey.LOCK_UNFOLLOW, trader.getId().toString());

        //保存交易员订单
        CopiedTrade traderEntrust = new CopiedTrade();
        traderEntrust.setCustomerId(trader.getId());
        traderEntrust.setContractOrderEntrustId(traderOrder.getContractOrderEntrustId());
        traderEntrust.setSymbol(traderOrder.getSymbol());
        traderEntrust.setContractSymbolId(traderSymbol.getContractSymbolId());
        traderEntrust.setOrderType(TRADER_ORDER);
        traderEntrust.setType(EntrustTypeEnum.getByTypeStr(traderOrder.getType()).ordinal());
        traderEntrust.setDirection(DirectionEnum.getByDirectionStr(traderOrder.getDirection()).ordinal());
        traderEntrust.setEntrustPrice(traderOrder.getEntrustPrice());
        traderEntrust.setVolume(traderOrder.getVolume());
        traderEntrust.setTriggerPrice(traderOrder.getTriggerPrice());
        traderEntrust.setLeverage(traderOrder.getLeverage());
        traderEntrust.setStopLossPrice(traderOrder.getLossPrice());
        traderEntrust.setStopProfitPrice(traderOrder.getProfitPrice());
        traderEntrust.setPrincipalAmount(traderOrder.getPrincipalAmount());
        traderEntrust.setTraderId(trader.getId());
        traderEntrust.setStatus(EntrustStatusEnum.ENTRUST_SUCCESS.getStatus());
        traderEntrust.setOpenPrice(traderOrder.getTradedPrice());
        traderEntrust.setPositionId(traderOrder.getPositionId());
        //traderEntrust.setTradedPrice(traderOrder.getTradedPrice());
        /*
         * //查询持仓是否已经有记录更新委托状态 Position position =
         * positionServiceImpl.getByContractOrderEntrustId(traderOrder.
         * getContractOrderEntrustId()); if(position == null){
         * traderEntrust.setStatus(EntrustStatusEnum.getByStatusStr(traderOrder.
         * getStatus()).ordinal()); }else{
         * traderEntrust.setStatus(EntrustStatusEnum.ENTRUST_SUCCESS.getStatus()); }
         */
        copiedTradeService.save(traderEntrust);

        //保存老师的跟单持仓   
        positionServiceImpl.entrustOrderSuccess(traderOrder.getPositionId(), traderOrder, trader.getId(), trader.getId(), null);

        boolean isSpecialTrader = trader.getTraderLevelId() == 4;
        boolean isMTrader = trader.getTraderLevelId() == 5;

        //3.获取跟单用户，批量收集所有跟单员委托，最后统一发送
        List<ContractOrderEntrust> batchOpenList = new ArrayList<>();
        customerFollowSymbolList.forEach(customerFollowSymbol -> {
            if (customerFollowSymbol.getUpdatedTime().getTime() > traderOrder.getUsdtOpenTime()) {
                log.info("不跟随, 学生id:{}, createTime={}, openTime={}", customerFollowSymbol.getCustomerId(), customerFollowSymbol.getUpdatedTime().getTime(), traderOrder.getUsdtOpenTime());
                return;
            }

            //跟特级的时候 IsSpecial 值等于2时，需要判断他有没有跟单仓位  没有的话就不要跟
            //Integer isSpecial = traderOrder.getIsSpecial();
            //if(isSpecialTrader && isSpecial != null && isSpecial == 2 ) {
            if (traderOrder.getIsAdd() != null && traderOrder.getIsAdd() == 1) {
                //Integer studentPositionCount = positionServiceImpl.getStudentPositionCount(customerFollowSymbol.getCustomerId(),trader.getId(),traderOrder.getSymbol());
                Integer studentPositionCount = positionServiceImpl.getStudentPositionCount(customerFollowSymbol.getCustomerId(), traderOrder.getPositionId());
                if (studentPositionCount == null || studentPositionCount == 0) {
                    log.info("学生没有仓位不跟随加仓");
                    //没有跟单仓位不要跟
                    return;
                }
            }
            //根据老师的仓位ID找到学生的持仓记录,如果没有记录或者有记录时没有全部平仓   才给学生开仓.
        	/*Position studentPosition = null;
			try {
				studentPosition = positionServiceImpl.getStudentPositionByTraderPositionId(traderOrder.getPositionId(),customerFollowSymbol.getCustomerId());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				log.info("查询学生仓位发生异常" + e.getMessage().toString());
				return ;
			}
        	log.info("copyTrade:老师开仓成功,老师memberId:{},跟随学生id:{},学生目前持仓情况:{}",traderOrder.getMemberId(),customerFollowSymbol.getCustomerId(),JSON.toJSONString(studentPosition));
        	if(studentPosition == null ||  (studentPosition != null && studentPosition.getStatus() != PositionStatusEnum.DONE.getStatus())) {
	        	*/
            log.info("copyTrade:老师开仓成功,老师memberId:{},跟随学生id:{}", traderOrder.getMemberId(), customerFollowSymbol.getCustomerId());
            if (true) {
                //4.获取用户跟单参数
                RiskControl riskControl = riskControlServiceImpl.getById(customerFollowSymbol.getRiskControlId());
                //杠杆倍数
                Integer leverage = riskControl.getLeverage() == null ? traderOrder.getLeverage() : riskControl.getLeverage();
                //数量/金额
                Integer tradingMode = riskControl.getTradingMode();
                BigDecimal tradingAmount = riskControl.getTradingAmount();
                if (tradingAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    log.warn("用户:{}跟随金额为0", customerFollowSymbol.getCustomerId());
                    return;
                }
                //固定比例
                BigDecimal volume = null;
                if (tradingMode.equals(10)) {
                    //tradingAmount = traderOrder.getPrincipalAmount().multiply(tradingAmount.divide(new BigDecimal("100"),BigDecimal.ROUND_CEILING));
                    volume = traderOrder.getVolume().multiply(tradingAmount.divide(new BigDecimal("100"), 8, RoundingMode.CEILING));
                    tradingAmount = (traderOrder.getTradedPrice().multiply(volume)).divide(new BigDecimal(leverage), BigDecimal.ROUND_CEILING);
                }
                BigDecimal maxCopiedAmount = riskControl.getMaxCopiedAmount();
                if (maxCopiedAmount != null) {
                    //验证是否超过最大跟随
                    //下单数量*当前价格/杠杆 = 保证金

                    //查询持仓所占有的资金,1,查询出所有持仓中合约,2,根据当前价格算出所有合约占用的资金
                    BigDecimal positionAmount = new BigDecimal("0");
                    List<Position> positionList = positionServiceImpl.sumPositionList(customerFollowSymbol.getCustomerId(), trader.getId());
                    if (positionList != null && positionList.size() > 0) {
                        for (Position position : positionList) {
                            BigDecimal currentPosition = position.getCurrentPosition();
                            BigDecimal currentPrice = marketListener.getCurrentPriceMap().get(position.getSymbol());
                            Integer leverage2 = position.getLeverage();
                            BigDecimal divide = (currentPrice.multiply(currentPosition)).divide(new BigDecimal(Integer.parseInt(leverage2.toString())), BigDecimal.ROUND_CEILING);
                            positionAmount = positionAmount.add(divide);
                        }

                    }

                    if (maxCopiedAmount.compareTo(tradingAmount.add(positionAmount)) < 0) {
                        //超过最大跟单金额
                        log.warn("用户:{}跟单金额超过最大限制,持仓占用保证金:{},交易员委托单号:{}",
                                customerFollowSymbol.getCustomerId(), positionAmount.toPlainString(), traderOrder.getContractOrderEntrustId());

                        return;
                    }
                }
                BigDecimal stopLossPrice = null;
                BigDecimal stopProfitPrice = null;
                //止盈比
                BigDecimal stopProfitPercentage = riskControl.getStopProfitPercentage();
                //止损比
                BigDecimal stopLossPercentage = riskControl.getStopLossPercentage();
                switch (EntrustTypeEnum.getByTypeStr(traderOrder.getType())) {
                    case MARKET_PRICE:
                        Map<String, BigDecimal> marketStopPrice = getStopPrice(stopProfitPercentage, stopLossPercentage, tradingAmount, traderOrder.getTradedPrice(), leverage, DirectionEnum.getByDirectionStr(traderOrder.getDirection()).ordinal());
                        stopLossPrice = marketStopPrice.get("stopLossPrice");
                        stopProfitPrice = marketStopPrice.get("stopProfitPrice");
                        break;
                    case LIMIT_PRICE:
                        //同计划委托计算方式一样

                    case TRIGGER:
                        Map<String, BigDecimal> stopPrice = getStopPrice(stopProfitPercentage, stopLossPercentage, tradingAmount, traderOrder.getEntrustPrice(), leverage, DirectionEnum.getByDirectionStr(traderOrder.getDirection()).ordinal());
                        stopLossPrice = stopPrice.get("stopLossPrice");
                        stopProfitPrice = stopPrice.get("stopProfitPrice");
                        break;
                }
                if (stopLossPrice == null) {
                    stopLossPrice = traderEntrust.getStopLossPrice();
                }

                if (stopProfitPrice == null) {
                    stopProfitPrice = traderEntrust.getStopProfitPrice();
                }
                //6.保存跟单
                Customer customer = customerServiceImpl.getById(customerFollowSymbol.getCustomerId());
                CopiedTrade copiedTrade = new CopiedTrade();
                copiedTrade.setCopyContractOrderEntrustId(traderOrder.getContractOrderEntrustId());
                copiedTrade.setCustomerId(customer.getId());
                copiedTrade.setDirection(DirectionEnum.getByDirectionStr(traderOrder.getDirection()).ordinal());
                copiedTrade.setEntrustPrice(traderOrder.getEntrustPrice());
                copiedTrade.setLeverage(leverage);
                copiedTrade.setOrderType(COPY_ORDER);
                copiedTrade.setPrincipalAmount(tradingAmount);
                copiedTrade.setStopLossPrice(stopLossPrice);
                copiedTrade.setStopProfitPrice(stopProfitPrice);
                copiedTrade.setTraderId(trader.getId());
                copiedTrade.setType(EntrustTypeEnum.getByTypeStr(traderOrder.getType()).ordinal());
                copiedTrade.setTriggerPrice(traderOrder.getTriggerPrice());
                copiedTrade.setSymbol(traderOrder.getSymbol());
                copiedTrade.setContractSymbolId(traderOrder.getContractId());
                copiedTrade.setStatus(EntrustStatusEnum.ENTRUST_ING.getStatus());
                copiedTradeService.save(copiedTrade);

                //5.拼装下单参数
                ContractOrderEntrust followEntrust = BeanCopior.map(traderOrder, ContractOrderEntrust.class);
                //followEntrust.setContractId(customerFollowSymbol.getContractSymbolId());
                //followEntrust.setSymbol(customerFollowSymbol.getSymbol());
                //followEntrust.setEntrustType(traderOrder.getEntrustType());
                //followEntrust.setDirection(traderOrder.getDirection());
                //followEntrust.setEntrustPrice(traderOrder.getEntrustPrice());
                //followEntrust.setType(traderOrder.getType());
                followEntrust.setLeverage(leverage);
                followEntrust.setMemberId(customer.getMemberId());
                followEntrust.setLossPrice(stopLossPrice);
                followEntrust.setProfitPrice(stopProfitPrice);
                followEntrust.setPrincipalAmount(tradingAmount);
                followEntrust.setVolume(volume);
                if (tradingMode.equals(10)) {
                    followEntrust.setPrincipalAmount(null);
                }
                followEntrust.setTriggerPrice(traderOrder.getTriggerPrice());
                followEntrust.setFollowId(traderOrder.getId());
                followEntrust.setFollowSystemId(copiedTrade.getId());
                followEntrust.setDividendPercent(traderLevel.getDividendPercent());
                followEntrust.setIsPercentage(1);
                //7.发送消息委托下单
                //如果是超级交易员就其他的参数使用order的,
                if (isSpecialTrader || isMTrader) {
                    followEntrust.setLeverage(traderOrder.getLeverage());
                    followEntrust.setMemberId(customer.getMemberId());
                    followEntrust.setPrincipalAmount(traderOrder.getPrincipalAmount());
                    followEntrust.setVolume(traderOrder.getVolume());
                    followEntrust.setLossPrice(traderOrder.getLossPrice());
                    followEntrust.setProfitPrice(traderOrder.getProfitPrice());
                    followEntrust.setMaxFollowAmount(trader.getMaxPrincipalAmount());
                    if (trader.getMinFollowAmount() != null)
                        followEntrust.setMinFollowAmount(BigDecimal.valueOf(trader.getMinFollowAmount()));
                    followEntrust.setIsSpecial(1);
                }
                log.info("学生跟单订单信息{}跟随的老师订单{}", followEntrust, traderOrder.getContractOrderEntrustId());
                // 加入批量列表，不再逐条发送
                batchOpenList.add(followEntrust);
            }
        });

        // 批量发送，不设上限，doge 侧直接以交易员价格开仓，不走匹配引擎
        if (!batchOpenList.isEmpty()) {
            // 记录本次跟单员数量，供 triggerBatchFollowClose 校验跟单员仓位是否全部建立
            stringRedisTemplate.opsForValue().set(
                    RedisKey.CT_FOLLOW_BATCH_SIZE + traderOrder.getPositionId(),
                    String.valueOf(batchOpenList.size()),
                    Duration.ofMinutes(1)
            );
            try {
                kafkaTemplate.send("follow-batch-open", JSON.toJSONString(batchOpenList)).get();
            } catch (Exception e) {
                log.error("follow-batch-open 发送失败, size={}", batchOpenList.size(), e);
            }
        }
        return true;
    }

    private Map<String, BigDecimal> getStopPrice(BigDecimal stopProfitPercentage, BigDecimal stopLossPercentage, BigDecimal principalAmount, BigDecimal entrustPrice, Integer leverage, Integer orderDirection) {
        Map<String, BigDecimal> stopPriceMap = new HashMap<>();
        if (stopProfitPercentage != null) {
            BigDecimal percentage = stopProfitPercentage.divide(new BigDecimal("100"), BigDecimal.ROUND_CEILING);
            BigDecimal stopProfitPrice = null;
            if (DirectionEnum.BUY.getDirection().equals(orderDirection)) {
                //计算止盈价
                stopProfitPrice = getBuyStopPrice(principalAmount, percentage, entrustPrice, leverage);
            } else {
                stopProfitPrice = getSellStopPrice(principalAmount, percentage, entrustPrice, leverage);
            }
            stopPriceMap.put("stopProfitPrice", stopProfitPrice);
        }

        if (stopLossPercentage != null) {
            //计算止损价
            BigDecimal percentage = stopLossPercentage.divide(new BigDecimal("100"), BigDecimal.ROUND_CEILING).multiply(new BigDecimal("-1"));
            BigDecimal stopLossPrice = null;
            if (DirectionEnum.BUY.getDirection().equals(orderDirection)) {
                stopLossPrice = getBuyStopPrice(principalAmount, percentage, entrustPrice, leverage);
            } else {
                stopLossPrice = getSellStopPrice(principalAmount, percentage, entrustPrice, leverage);
            }
            stopPriceMap.put("stopLossPrice", stopLossPrice);
        }
        return stopPriceMap;
    }


    private BigDecimal getBuyStopPrice(BigDecimal principalAmount, BigDecimal percentage, BigDecimal entrustPrice, Integer leverage) {
        /**多单止盈/止损价格计算公式
         *  (保证金*盈利比+(杠杆倍数*保证金))/(杠杆倍数*保证金)*委托价格 = 止盈价
         *  (保证金*亏损比*-1+(杠杆倍数*保证金))/(杠杆倍数*保证金)*委托价格 =止损价
         */
        BigDecimal totalAmount = new BigDecimal(leverage).multiply(principalAmount);
        return principalAmount.multiply(percentage)
                .add(totalAmount)
                .divide(totalAmount, BigDecimal.ROUND_CEILING)
                .multiply(entrustPrice);
    }

    private BigDecimal getSellStopPrice(BigDecimal principalAmount, BigDecimal percentage, BigDecimal entrustPrice, Integer leverage) {
        /**空单止盈/止损价格计算公式
         * ((杠杆倍数*保证金)-保证金*盈利比) / (杠杆倍数*保证金)*委托价格= 止盈价
         * ((杠杆倍数*保证金)-保证金*亏损比*-1) / (杠杆倍数*保证金)*委托价格= 止损价
         */
        BigDecimal totalAmount = new BigDecimal(leverage).multiply(principalAmount);
        return totalAmount.subtract(principalAmount.multiply(percentage))
                .divide(totalAmount, BigDecimal.ROUND_CEILING)
                .multiply(entrustPrice);
    }


    @Override
    @Transactional
    public Boolean entrustCallback(ContractOrderEntrust entrustCallback) {
        log.info("copyTrade:学生开仓成功,学生memberId:{},order数据:{}", entrustCallback.getMemberId(), JSON.toJSONString(entrustCallback));
        if (entrustCallback.getFollowSystemId() == null) {
            return false;
        }
        // 防并发锁：异步场景下同一 followSystemId 可能被多线程同时处理
        String lockKey = "LOCK_ENTRUST_CALLBACK:" + entrustCallback.getFollowSystemId();
        //学生的更新跟单记录表和保存跟单持仓表.
        CopiedTrade copiedTrade = getById(entrustCallback.getFollowSystemId());
        if (copiedTrade == null) {
            return false;
        }
        // 订单和仓位已存在则跳过，避免重复处理
        if (EntrustStatusEnum.ENTRUST_SUCCESS.getStatus().equals(copiedTrade.getStatus()) && copiedTrade.getPositionId() != null) {
            log.info("entrustCallback: 订单和仓位已存在，跳过, followSystemId:{}, positionId:{}", entrustCallback.getFollowSystemId(), copiedTrade.getPositionId());
            return true;
        }
        copiedTrade.setVolume(entrustCallback.getVolume());
        copiedTrade.setStatus(EntrustStatusEnum.ENTRUST_SUCCESS.getStatus());
        copiedTrade.setPrincipalAmount(entrustCallback.getPrincipalAmount());
        copiedTrade.setTriggerPrice(entrustCallback.getTradedPrice());
        copiedTrade.setContractOrderEntrustId(entrustCallback.getContractOrderEntrustId());
        copiedTrade.setOpenPrice(entrustCallback.getTradedPrice());
        copiedTrade.setPositionId(entrustCallback.getPositionId());
        Long customerId = copiedTrade.getCustomerId();
        Long traderId = copiedTrade.getTraderId();
        //保存学生的跟单持仓
        positionServiceImpl.entrustOrderSuccess(entrustCallback.getPositionId(), entrustCallback, customerId, traderId, entrustCallback.getFollowId());
        try {
            updateById(copiedTrade);
            return true;
        }catch (Exception e){
            log.info("修改信息失败{}",copiedTrade.getId(),e);
            return false;
        }
    }

    @Override
    @Transactional
    public Boolean entrustCallbackBatch(List<ContractOrderEntrust> orders) {
        if (orders == null || orders.isEmpty()) return true;

        // 1. 批量查询 CopiedTrade，避免每条单独查库
        List<Long> followSystemIds = orders.stream()
                .map(ContractOrderEntrust::getFollowSystemId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (followSystemIds.isEmpty()) return true;

        Map<Long, CopiedTrade> ctMap = listByIds(followSystemIds).stream()
                .collect(Collectors.toMap(CopiedTrade::getId, ct -> ct));

        List<CopiedTrade> toUpdate = new ArrayList<>();
        List<com.copy.trade.entity.po.Position> newPositions = new ArrayList<>();
        List<com.copy.trade.entity.po.Message> newMessages = new ArrayList<>();

        for (ContractOrderEntrust order : orders) {
            if (order.getFollowSystemId() == null) continue;
            CopiedTrade ct = ctMap.get(order.getFollowSystemId());
            if (ct == null) {
                log.warn("entrustCallbackBatch: CopiedTrade not found, followSystemId={}", order.getFollowSystemId());
                continue;
            }
            // 已处理则跳过
            if (EntrustStatusEnum.ENTRUST_SUCCESS.getStatus().equals(ct.getStatus()) && ct.getPositionId() != null) {
                log.info("entrustCallbackBatch: 已存在，跳过, followSystemId={}, positionId={}", order.getFollowSystemId(), ct.getPositionId());
                continue;
            }

            // 更新 CopiedTrade 字段
            ct.setVolume(order.getVolume());
            ct.setStatus(EntrustStatusEnum.ENTRUST_SUCCESS.getStatus());
            ct.setContractOrderEntrustId(order.getContractOrderEntrustId());
            ct.setPrincipalAmount(order.getPrincipalAmount());
            ct.setTriggerPrice(order.getTradedPrice());
            ct.setOpenPrice(order.getTradedPrice());
            ct.setPositionId(order.getPositionId());
            toUpdate.add(ct);

            // 构建 Position（批量开仓均为新建仓位，不走 entrustOrderSuccess 内的锁+查询逻辑）
            com.copy.trade.entity.po.Position pos = new com.copy.trade.entity.po.Position();
            pos.setCustomerId(ct.getCustomerId());
            pos.setPositionId(order.getPositionId());
            pos.setTraderId(ct.getTraderId());
            pos.setSymbol(order.getSymbol());
            pos.setDirection(DirectionEnum.getByDirectionStr(order.getDirection()).getDirection());
            pos.setLeverage(order.getLeverage());
            pos.setOpenPrice(order.getTradedPrice());
            pos.setTotalPosition(order.getVolume());
            pos.setTotalPrincipalAmount(order.getPrincipalAmount());
            pos.setAvailablePosition(order.getVolume());
            pos.setCurrentPosition(order.getVolume());
            pos.setPrincipalAmount(order.getPrincipalAmount());
            pos.setContractOrderEntrustId(order.getContractOrderEntrustId());
            pos.setStatus(PositionStatusEnum.STARTED.getStatus());
            pos.setTransactionFee(order.getOpenFee() != null ? order.getOpenFee() : BigDecimal.ZERO);
            pos.setOpenTime(order.getDealTime());
            pos.setTraderPositionId(order.getFollowId());
            newPositions.add(pos);
        }

        // 2. 批量写库
        if (!toUpdate.isEmpty()) {
            updateBatchById(toUpdate);
        }
        if (!newPositions.isEmpty()) {
            positionServiceImpl.saveBatch(newPositions);
        }
        log.info("entrustCallbackBatch: 批量处理完成, total={}, updated={}, positions={}", orders.size(), toUpdate.size(), newPositions.size());
        return true;
    }

    @Override
    public Boolean entrustFollowOpenfail(ContractOrderEntrust entrustCallback) {
        log.info("copyTrade:学生开仓失败,学生memberId:{},order数据:{}", entrustCallback.getMemberId(), JSON.toJSONString(entrustCallback));
        CopiedTrade copiedTrade = getById(entrustCallback.getFollowSystemId());
        if (copiedTrade == null) {
            log.info("跟单记录为null");
            return true;
        }
        copiedTrade.setStatus(EntrustStatusEnum.ENTRUST_FAILURE.getStatus());
        log.info("跟单记录不为null,已更新" + JSON.toJSONString(copiedTrade));

        return updateById(copiedTrade);
    }

    @Override
    public CopiedTrade getByContractOrderEntrustId(String contractOrderEntrustId) {
        QueryWrapper<CopiedTrade> copiedTradeQueryWrapper = new QueryWrapper<>();
        copiedTradeQueryWrapper.eq("contract_order_entrust_id", contractOrderEntrustId);
        CopiedTrade copiedTrade = getOne(copiedTradeQueryWrapper);
        return copiedTrade;
    }

    @Override
    public Boolean entrustCancel(EntrustCancel entrustCancel) {
        //更新委托状态
        CopiedTrade copiedTrade = getByContractOrderEntrustId(entrustCancel.getContractOrderEntrustId());
        if (copiedTrade == null) {
            return true;
        }
        copiedTrade.setStatus(EntrustStatusEnum.ENTRUST_CANCEL.getStatus());
        updateById(copiedTrade);
        if (copiedTrade.getCopyContractOrderEntrustId() != null) {
            return true;
        }
        //查询跟单
        List<CopiedTrade> copiedEntrustList = listByCopyContractOrderEntrustId(entrustCancel.getContractOrderEntrustId());
        copiedEntrustList.forEach(copiedEntrust -> {
            //发送撤单消息
            kafkaTemplate.send(KafkaTopic.FOLLOW_ENTRUST_CANCEL, copiedEntrust.getContractOrderEntrustId());
        });
        return true;
    }

    public List<CopiedTrade> listByCopyContractOrderEntrustId(String contractOrderEntrustId) {
        QueryWrapper<CopiedTrade> copiedTradeQueryWrapper = new QueryWrapper<>();
        copiedTradeQueryWrapper.eq("copy_contract_order_entrust_id", contractOrderEntrustId)
                .eq("status", EntrustStatusEnum.ENTRUST_ING.getStatus());
        return list(copiedTradeQueryWrapper);
    }

    public Page<CopiedTradeVo> list(CopiedTradeForm copiedTradeForm) {
        Page page = copiedTradeForm.newFormPage();
        List<CopiedTradeVo> list = ((CopiedTradeMapper) baseMapper).page(page, copiedTradeForm);
        page.setRecords(list);
        return page;
    }

}
