package com.simuwang.base.common.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.simuwang.base.common.conts.AccountingItems;
import com.simuwang.base.common.conts.AccountingNewItems;
import com.simuwang.base.common.conts.HoldingType;
import com.simuwang.base.common.enums.MarketTradIngCodeEnum;
import com.simuwang.base.pojo.dos.FundPositionDetailDO;
import com.simuwang.base.pojo.dos.ValuationTableDO;
import com.simuwang.base.pojo.valuation.AssetsValuationInfo;
import com.simuwang.base.pojo.valuation.CmValuationTableAttribute;
import com.smppw.utils.BigDecimalUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public final class ValuationTableParseUtil {

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

    /**
     * 多头
     */
    public final static Integer BULL_LONG_SHORT = 1;

    /**
     * 空头
     */
    public final static Integer BEAR_LONG_SHORT = 2;

    private final static Map<String, Integer> CURRENCY_CODE_MAP = MapUtil.newHashMap();

    static {
        // 1-人民币，2-美元，3-港元
        CURRENCY_CODE_MAP.put("CNY", 1);
        CURRENCY_CODE_MAP.put("USD", 2);
        CURRENCY_CODE_MAP.put("HKD", 3);
    }

    /**
     * 特殊连接符(用户证券名称的识别剔除)
     */
    private final static List<String> SPECIAL_CODE = CollUtil.toList("-", "_", ".");

    public static List<FundPositionDetailDO> parseDataNew(List<CmValuationTableAttribute> attrList, ValuationTableDO file,
                                                          List<String> marketCodeList) {
        // 汇总类数据map
        Map<String, Integer> tailCode = new HashMap<>();
        // 区分"科目代码"列为明细类和汇总类数据
        boolean isFooterRow;
        // 返回结果(持仓明细对象)
        List<FundPositionDetailDO> dataList = new ArrayList<>();

        // 识别科目代码层级关系
        handleSubjectCodeLevel(attrList);

        // 兼容存在重复的数据(兼容updateValuationPositionDetailType任务)
        Map<String, String> originalCodePreOriginalCodeMap = attrList.stream().filter(e -> StrUtil.isNotBlank(e.getPreOriginalSubjectCode()))
                .collect(Collectors.toMap(CmValuationTableAttribute::getOriginalSubjectCode, CmValuationTableAttribute::getPreOriginalSubjectCode,
                        (oldValue, newValue) -> newValue));

        for (int i = 0; i < attrList.size(); i++) {
            CmValuationTableAttribute attr = attrList.get(i);
            if (attr.getSubjectCode() == null) {
                continue;
            }
            // 估值表解析到的数据 -> 持仓明细对象
            FundPositionDetailDO data = toDetail(attr, file);
            // 判断数据为明细类 or 汇总类数据(给字段isFooterRow赋值)
            isFooterRow = dealDetailOrSummary(data);
            if (data.getSubjectCode() == null) {
                continue;
            }
            // 汇总类数据("基金投资合计","实收资本"等字段)
            if (isFooterRow) {
                handleSummaryData(data, tailCode);
            }
            // 持仓明细类数据
            if (!isFooterRow) {
                // 从科目代码识别出明细证券代码securitiesCode
                String securitiesCode = dealSecuritiesCode(attr.getSubjectCode(), attr.getPreOriginalSubjectCode(), attr.getLevel());
                data.setSecuritiesCode(securitiesCode);

                // 处理证券名称(剔除上一科目名称)
                String preOriginalSubjectCode = originalCodePreOriginalCodeMap.get(attr.getOriginalSubjectCode());
                String preSecuritiesName = attrList.stream().filter(e -> e.getOriginalSubjectCode().equals(preOriginalSubjectCode))
                        .findFirst().map(CmValuationTableAttribute::getSubjectName).orElse(null);
                String securitiesName = handleSecuritiesName(data.getLevel(), data.getSecuritiesName(), preSecuritiesName);
                data.setSecuritiesName(securitiesName);

                // data.subjectCode字段保存估值表中的原始科目代码
                data.setSubjectCode(attr.getOriginalSubjectCode());
                // 资产类型，1资产类，2负债类，3共同类，4所有者权益类，6损益类(根据科目代码编码规则可得)
                data.setSubjectType(Integer.valueOf(data.getSubjectCode().substring(0, 1)));
            }
            data.setIsvalid(1);
            data.setCreateTime(new Date());
            dataList.add(data);
        }

        // 推断持仓明细类型
        dealAssetTypeNew(dataList, originalCodePreOriginalCodeMap, marketCodeList);
        return dataList;
    }

    /**
     * 初步处理证券名称(剔除上一科目名称)
     * 如:场外_已上市_开放式_货币_成本-平安财富宝货币A
     * 准确的证券名称应该为:平安财富宝货币A
     *
     * @param level                  持仓明细层级
     * @param originalSecuritiesName 当前明细的证券名称
     * @param preSecuritiesName      上一级的证券名称
     * @return 处理后的证券名称
     */
    private static String handleSecuritiesName(Integer level, String originalSecuritiesName, String preSecuritiesName) {
        if (StrUtil.isBlank(preSecuritiesName) || StrUtil.isBlank(originalSecuritiesName) || !originalSecuritiesName.contains(preSecuritiesName) || level == null || level < 4) {
            return originalSecuritiesName;
        }
        String securitiesName = originalSecuritiesName.replace(preSecuritiesName, "");
        for (String specialCode : SPECIAL_CODE) {
            if (securitiesName.startsWith(specialCode)) {
                securitiesName = securitiesName.substring(1);
            }
        }
        return securitiesName;
    }

    /**
     * 获取明细证券代码
     *
     * @param subjectCode            估值表科目代码(去掉".","_")
     * @param preOriginalSubjectCode 上一级科目代码
     * @param level                  层级
     * @return 明细证券代码
     */
    private static String dealSecuritiesCode(String subjectCode, String preOriginalSubjectCode, Integer level) {
        String securitiesCode = null;
        // 一级科目的证券代码 等于 估值表原始科目代码
        if (level == null) {
            return null;
        }
        if (level == 1) {
            securitiesCode = subjectCode;
            return securitiesCode;
        }
        // 二级或三级科目的证券代码为空
        if (level == 2 || level == 3) {
            return null;
        }
        if (StrUtil.isNotBlank(preOriginalSubjectCode) && level >= 4) {
            String preSubjectCode = preOriginalSubjectCode.replaceAll("[\\.\\s_-]", "");
            securitiesCode = subjectCode.substring(preSubjectCode.length());
        }
        return securitiesCode;
    }

    private static void handleSummaryData(FundPositionDetailDO data, Map<String, Integer> tailCode) {
        data.setSecType(100);
        String subjectName = data.getSecuritiesName();

        if (StringUtils.isNotEmpty(subjectName)) {
            if (subjectName.startsWith("-") || Character.isDigit(subjectName.toCharArray()[0])) {
                //如果科目名称是数字
                data.setSecuritiesAmount(BigDecimalUtils.toBigDecimal((subjectName.replace("%", "").replace(",", ""))));
                data.setSecuritiesName(data.getSubjectCode());
            } else {
                data.setSecuritiesName(data.getSubjectCode() + subjectName);
            }
        } else {
            data.setSecuritiesName(data.getSubjectCode());
        }
        String subjectCode = getTypeNo(data.getSubjectCode());
        if (subjectCode == null) {
            subjectCode = "1000";
        } else {
            if (tailCode.containsKey(subjectCode)) {
                int num = tailCode.get(subjectCode);
                tailCode.put(subjectCode, num + 1);
                subjectCode = subjectCode + ":" + num;
            } else {
                tailCode.put(subjectCode, 1);
            }
        }

        data.setSecuritiesCode(subjectCode);
        data.setSubjectCode(subjectCode);
        data.setLevel(0);
    }

    private static boolean dealDetailOrSummary(FundPositionDetailDO data) {
        boolean isFooterRow = false;
        if (!Character.isDigit(data.getSubjectCode().toCharArray()[0])) {
            isFooterRow = true;
        }
        if (!isFooterRow && ValuationDataUtils.hasChinese(data.getSubjectCode(), false)) {
            String code = data.getSubjectCode();
            if (data.getSecuritiesName() != null) {
                code = code.replace(data.getSecuritiesName(), "");
            }
            if (ValuationDataUtils.hasChinese(code, false)) {
                int endIndex = getSubjectCodeEndIndex(data.getSubjectCode());
                String subCode = code.substring(0, endIndex);
                if (subCode.length() < 4 && data.getSecuritiesName() == null) {
                    isFooterRow = true;
                } else {
                    data.setSubjectCode(subCode);
                    if (data.getSecuritiesName() == null) {
                        data.setSecuritiesName(code.substring(endIndex));
                    }
                }
            } else {
                data.setSubjectCode(code);
            }
        }
        return isFooterRow;
    }

    /**
     * 识别科目代码的层级
     *
     * @param valuationDataList 估值表解析到的数据
     */
    private static void handleSubjectCodeLevel(List<CmValuationTableAttribute> valuationDataList) {
        // 先过滤出一级科目(一级科目长度一定是4位)
        List<CmValuationTableAttribute> levelOneCodeList = valuationDataList.stream()
                .filter(e -> StrUtil.isNotBlank(e.getOriginalSubjectCode()) && e.getOriginalSubjectCode().length() == 4
                        && StrUtil.isNumeric(e.getOriginalSubjectCode()))
                .sorted(Comparator.comparing(CmValuationTableAttribute::getOriginalSubjectCode)).collect(Collectors.toList());
        if (CollUtil.isEmpty(levelOneCodeList)) {
            return;
        }
        levelOneCodeList.forEach(levelOneCodeData -> {
            String parentCode = levelOneCodeData.getOriginalSubjectCode();
            levelOneCodeData.setLevel(1);
            List<CmValuationTableAttribute> subSubjectList = valuationDataList.stream()
                    .filter(e -> StrUtil.isNotBlank(e.getOriginalSubjectCode()) && e.getOriginalSubjectCode().startsWith(parentCode) && e.getLevel() == null)
                    .sorted(Comparator.comparing(e -> e.getOriginalSubjectCode().length())).collect(Collectors.toList());
            handSubSubjectLevel(subSubjectList, parentCode, 1);
        });
    }

    /**
     * 递归找出子类科目的层级
     *
     * @param subjectList 子类科目数据
     * @param parentLevel 父类层级
     */
    private static void handSubSubjectLevel(List<CmValuationTableAttribute> subjectList, String parentCode, Integer parentLevel) {
        if (CollUtil.isEmpty(subjectList)) {
            return;
        }
        subjectList.forEach(e -> e.setPreOriginalSubjectCode(parentCode));
        for (CmValuationTableAttribute parentData : subjectList) {
            if (parentData.getLevel() != null) {
                continue;
            }
            String subParentCode = parentData.getOriginalSubjectCode();
            parentData.setLevel(parentLevel + 1);
            parentData.setPreOriginalSubjectCode(parentCode);
            List<CmValuationTableAttribute> subSubjectList = subjectList.stream()
                    .filter(e -> StrUtil.isNotBlank(e.getOriginalSubjectCode()) && e.getOriginalSubjectCode().startsWith(subParentCode)
                            && !e.getOriginalSubjectCode().equals(subParentCode) && e.getLevel() == null)
                    .sorted(Comparator.comparing(e -> e.getOriginalSubjectCode().length())).collect(Collectors.toList());
            handSubSubjectLevel(subSubjectList, subParentCode, parentLevel + 1);
        }
    }

    private static FundPositionDetailDO toDetail(CmValuationTableAttribute attr, ValuationTableDO userValuationTableDo) {
        FundPositionDetailDO detail = new FundPositionDetailDO();
        detail.setFundId(userValuationTableDo.getFundId());
        detail.setValuationDate(userValuationTableDo.getValuationDate());
        detail.setCurrency(getCurrencyCode(attr.getCurrency()));
        detail.setExchangeRate(attr.getExchangeRate());
        detail.setSecuritiesName(attr.getSubjectName());
        detail.setSecuritiesAmount(attr.getSecuritiesAmount());
        detail.setMarketValue(attr.getMarketValue());
        // [权重](市值占净值比)如果不能从估值表中读取时,市值占净值比=市值/资产净值
        BigDecimal marketValueRatio = attr.getMarketValueRatio();
        if (marketValueRatio == null || marketValueRatio.compareTo(BigDecimal.ZERO) == 0) {
            BigDecimal netAssetMarketValue = userValuationTableDo.getNetAssetsValue();
            if (attr.getMarketValue() != null && netAssetMarketValue != null && netAssetMarketValue.compareTo(BigDecimal.ZERO) != 0) {
                marketValueRatio = BigDecimalUtils.divide(attr.getMarketValue(), netAssetMarketValue);
            }
        }
        detail.setMarketValueRatio(marketValueRatio);
        detail.setNetCost(attr.getNetCost());
        detail.setNetCostRatio(attr.getNetCostRatio());
        BigDecimal increment = attr.getIncrement();
        detail.setIncrement(increment);
        // [估值增值]如果不能从估值表中读取时,估值增值=市值-成本
        if (increment != null && increment.compareTo(BigDecimal.ZERO) == 0) {
            increment = BigDecimalUtils.subtract(attr.getMarketValue(), attr.getNetCost());
        }
        detail.setIncrement(increment);
        detail.setHaltInfo(attr.getHaltInfo());
        detail.setNature(1);// 默认为多
        detail.setSubjectCode(attr.getSubjectCode());
        detail.setLevel(attr.getLevel());
        detail.setMarketPrice(attr.getMarketPrice());
        detail.setUnitCost(attr.getUnitCost());
        return detail;
    }

    private static Integer getCurrencyCode(String currency) {
        if (StrUtil.isBlank(currency)) {
            return null;
        }
        for (Map.Entry<String, Integer> entry : CURRENCY_CODE_MAP.entrySet()) {
            if (entry.getKey().equals(currency)) {
                return entry.getValue();
            }
        }
        return null;
    }

    private static String getTypeNo(String name) {
        if (name.contains("合计") && name.contains("证券")) {
            return "100";
        }
        if (name.startsWith("其中")) {
            if (name.contains("股票")) {
                return "101";
            }
            if (name.contains("债券")) {
                return "102";
            }
            if (name.contains("基金")) {
                return "103";
            }
            if (name.contains("权证")) {
                return "104";
            }
            if (name.contains("衍生")) {
                return "105";
            }
            return null;
        }

        if (name.contains("头寸")) {
            return "106";
        }
        boolean isPaidInCapital = isPaidInCapital(name);
        if (isPaidInCapital) {
            return "107";
        }
        if (name.contains("损益平准金")) {
            if (name.contains("未")) {
                return "109";
            }
            return "108";
        }
        if (name.contains("合计") && name.contains("资产")) {
            return "110";
        }
        if (name.contains("合计") && name.contains("负债")) {
            return "111";
        }
        if (name.contains("资产") && name.contains("净值")) {
            return "112";
        }
        if (name.contains("单位") && name.contains("净值")) {
            String trimName = name.trim();
            if (trimName.length() == 5) {
                // 去掉末尾的符号
                trimName = trimName.substring(0, 4);
            }
            if ("单位净值".equals(trimName) || name.contains("今日") || name.contains("基金")) {
                return "201";
            }
            if (name.contains("累计")) {
                return "202";
            }

            if (name.contains("期初")) {
                return "203";
            }
            if (name.contains("昨日")) {
                return "204";
            }
            if (name.contains("年初")) {
                return "205";
            }
            if (name.contains("期初")) {
                return "206";
            }
            if (name.contains("周初")) {
                return "207";
            }
            if (name.contains("月初")) {
                return "208";
            }
            return null;
        }

        if (name.contains("可分配") && (name.contains("收益") || name.contains("利润"))) {
            if (name.contains("单位")) {
                return "212";
            }
            return "213";
        }
        if (name.contains("现金类占")) {
            return "210";
        }
        if (name.contains("累计派现")) {
            return "211";
        }

        return null;
    }

    private static boolean isPaidInCapital(String name) {
        return name.contains("实收") && name.contains("资本")
                || name.contains("实收") && name.contains("信托");
    }

    /**
     * 识别证券类型,多头空头,交易场所
     *
     * @param dataList                       估值表数据对象
     * @param originalCodePreOriginalCodeMap 当前科目代码 -上一级科目代码映射关系
     * @param marketCodeList                 交易场所code列表
     */
    public static void dealAssetTypeNew(List<FundPositionDetailDO> dataList, Map<String, String> originalCodePreOriginalCodeMap, List<String> marketCodeList) {
        if (CollUtil.isEmpty(dataList)) {
            return;
        }
        Map<String, String> securitiesCodeNameMap = MapUtil.newHashMap();
        // 查询交易场所code
        for (int i = 0; i < dataList.size(); i++) {
            FundPositionDetailDO fundPositionDetail = dataList.get(i);
            // 汇总类数据("基金投资合计","实收资本"等字段)不需要处理
            if (fundPositionDetail.getSecType() != null && fundPositionDetail.getSecType() == 100) {
                continue;
            }
            // 获取二级、三级、四级科目名称
            List<String> securitiesNameList = CollUtil.toList("", "", "");
            getPreSecuritiesName(fundPositionDetail, dataList, originalCodePreOriginalCodeMap, securitiesNameList);
            String secondSecuritiesName = securitiesNameList.get(0);
            String thirdSecuritiesName = securitiesNameList.get(1);
            String fourSecuritiesName = fundPositionDetail.getLevel() != null && fundPositionDetail.getLevel() > 4 ? securitiesNameList.get(2) : "";
            // 标识证券类型
            addStockTypeNew(fundPositionDetail, secondSecuritiesName, thirdSecuritiesName, fourSecuritiesName);

            // 识别空头多头(识别过程中已经默认为 1-多头)
            addLongShort(fundPositionDetail);
            // 空头类或正回购的市值入库时应该为负数
            if (fundPositionDetail.getNature() == 2 && fundPositionDetail.getMarketValue() != null
                    && fundPositionDetail.getMarketValue().compareTo(BigDecimal.ZERO) > 0
                    || (fundPositionDetail.getSubType() != null && fundPositionDetail.getSubType().equals(HoldingType.BondBackRepo.getId()))) {
                fundPositionDetail.setMarketValue(BigDecimalUtils.multiply(fundPositionDetail.getMarketValue(), BigDecimalUtils.toBigDecimal("-1")));
            }

            // 识别交易场所
            addMarketIdNew(fundPositionDetail, secondSecuritiesName + thirdSecuritiesName + fourSecuritiesName);

            // 识别证券代码(过滤掉交易场所code)
            filterSecuritiesCode(fundPositionDetail, marketCodeList);

            // 用于后面识别估值增值和应计利息子类
            if (fundPositionDetail.getLevel() != null && fundPositionDetail.getLevel() >= 4) {
                securitiesCodeNameMap.put(fundPositionDetail.getSubjectCode(), securitiesNameList.get(1));
            }

        }

        // 划分估值增值和应计利息明细数据的sub_type
        for (int i = 0; i < dataList.size(); i++) {
            FundPositionDetailDO info = dataList.get(i);
            Integer secType = info.getSecType();
            if (secType == null || secType == 100 || (info.getLevel() != null && info.getLevel() == 0)) {
                continue;
            }
            // 二级,三级期货,期权,其他衍生品的子类 -> sub_type=20
            if (info.getLevel() > 1 && info.getLevel() < 4) {
                if ((secType == HoldingType.Derivatives.getId() || secType == HoldingType.Future.getId() || secType == HoldingType.Option.getId())) {
                    info.setSubType(HoldingType.CostCash.getId());
                }
            }
            // 四级以上的明细,如果成本或数量为空或为0
            if (info.getLevel() >= 4) {
                if (((info.getNetCost() == null || info.getNetCost().compareTo(BigDecimal.ZERO) == 0.0)
                        || (info.getSecuritiesAmount() == null || info.getSecuritiesAmount().compareTo(BigDecimal.ZERO) == 0.0))) {
                    String thirdSecuritiesName = securitiesCodeNameMap.get(info.getSubjectCode());
                    // 正逆回购(目前存在应计利息,不存在估值增值)
                    if (info.getSecType() == HoldingType.BondBack.getId()) {
                        if (StrUtil.isNotBlank(thirdSecuritiesName) && thirdSecuritiesName.contains("利息")) {
                            info.setSubType(HoldingType.Interest.getId());
                        }
                        continue;
                    }
                    // 其他衍生品不做这个限制
                    if (info.getSecType() == HoldingType.Derivatives.getId()) {
                        continue;
                    }

                    // 三级科目名称包含"利息" -> sub_type=22
                    if (StrUtil.isNotBlank(thirdSecuritiesName) && thirdSecuritiesName.contains("利息")) {
                        info.setSubType(HoldingType.Interest.getId());
                        continue;
                    }
                    info.setSubType(HoldingType.CostCash.getId());
                }
            }
        }
    }

    /**
     * 识别证券代码
     *
     * @param fundPositionDetail 持仓明细数据
     * @param marketCodeList     交易场所code列表
     */
    public static void filterSecuritiesCode(FundPositionDetailDO fundPositionDetail, List<String> marketCodeList) {
        if (fundPositionDetail.getLevel() == null || fundPositionDetail.getLevel() < 4) {
            return;
        }
        // 识别证券代码
        String securitiesCode = getSecuritiesCode(fundPositionDetail.getSecuritiesCode(), marketCodeList);
        fundPositionDetail.setSecuritiesCode(securitiesCode);
    }

    /**
     * 识别证券代码(去掉交易场所code)
     *
     * @param originalSecuritiesCode 原始证券代码
     * @param marketCodeList         交易场所code列表
     * @return 去掉交易场所code的证券代码
     */
    private static String getSecuritiesCode(String originalSecuritiesCode, List<String> marketCodeList) {
        String securitiesCode = originalSecuritiesCode;
        if (StrUtil.isBlank(originalSecuritiesCode)) {
            return securitiesCode;
        }
        for (String marketCode : marketCodeList) {
            if (originalSecuritiesCode.endsWith(marketCode)) {
                int length = originalSecuritiesCode.length();
                if (length > marketCode.length()) {
                    securitiesCode = originalSecuritiesCode.substring(0, length - marketCode.length());
                    break;
                }
            }
        }
        return securitiesCode;
    }

    /**
     * 标识证券类型
     *
     * @param info                 持仓明细对象
     * @param secondSecuritiesName 二级证券名称
     * @param thirdSecuritiesName  三级证券名称
     * @param fourSecuritiesName   四级证券名称
     */
    public static void addStockTypeNew(FundPositionDetailDO info, String secondSecuritiesName, String thirdSecuritiesName, String fourSecuritiesName) {
        // 无证券名称或市值的数据不识别证券类型
        if (info.getSecuritiesName() == null || info.getMarketValue() == null) {
            return;
        }
        Integer level = info.getLevel();
        String subjectCode = info.getSubjectCode();

        // 一.现金类
        if (startWith(AccountingNewItems.CASH, subjectCode)) {
            info.setSecType(HoldingType.Cash.getId());
            info.setSubType(HoldingType.Cash.getId());
            return;
        }

        // 二.股票类
        if (startWith(AccountingNewItems.EQUITY_LIST, subjectCode)) {
            // 1."1102"开头
            if (subjectCode.startsWith("1102") || level < 4) {
                info.setSecType(HoldingType.Stock.getId());
                Integer subType = dealStockSubType(secondSecuritiesName, thirdSecuritiesName);
                info.setSubType(subType);
                return;
            }
            // 2."2101"开头 并且 二级或三级或四级科目有"存托凭证"or"股票"的 四级及以上科目
            boolean is2101StockType = subjectCode.startsWith("2101") && (secondSecuritiesName.contains("存托凭证") || secondSecuritiesName.contains("股票")
                    || thirdSecuritiesName.contains("存托凭证") || thirdSecuritiesName.contains("股票")
                    || fourSecuritiesName.contains("存托凭证") || fourSecuritiesName.contains("股票"));
            if (is2101StockType) {
                info.setSecType(HoldingType.Stock.getId());
                Integer subType = dealStockSubType(secondSecuritiesName, thirdSecuritiesName);
                info.setSubType(subType);
                return;
            }
        }
        // 3."1101"开头并且层级 >=4 并且二级科目或三级或四级科目含有"股票"
        boolean is1101StockType = subjectCode.startsWith("1101") && level >= 4 &&
                (secondSecuritiesName.contains("股票") || thirdSecuritiesName.contains("股票") || fourSecuritiesName.contains("股票"));
        if (is1101StockType) {
            info.setSecType(HoldingType.Stock.getId());
            Integer subType = dealStockSubType(secondSecuritiesName, thirdSecuritiesName);
            info.setSubType(subType);
            return;
        }

        // 三.债券类
        if (startWith(AccountingNewItems.BOND_LIST, subjectCode)) {
            // 1."1103","1104"开头
            if (subjectCode.startsWith("1103") || subjectCode.startsWith("1104") || level < 4) {
                info.setSecType(HoldingType.Bond.getId());
                info.setSubType(HoldingType.Bond.getId());
                return;
            }
            // 2.子类"正逆回购" -> 证券名称以"GC"开头 或  证券名称包含"-0"
            if (info.getSecuritiesName().startsWith("GC") || info.getSecuritiesName().contains("-0")) {
                info.setSecType(HoldingType.Bond.getId());
                info.setSubType(HoldingType.BondBack.getId());
                return;
            }
        }
        // 3."2101"开头并且层级 >=4 并且二级或三级或四级科目含有"债券"
        boolean is2101BondType = subjectCode.startsWith("2101") && level >= 4 &&
                (secondSecuritiesName.contains("债券") || thirdSecuritiesName.contains("债券") || fourSecuritiesName.contains("债券"));
        if (is2101BondType) {
            info.setSecType(HoldingType.Bond.getId());
            info.setSubType(HoldingType.Bond.getId());
            return;
        }
        // 4."1101"开头并且层级 >=4 并且二级或三级或四级科目含有"债券"或"债"
        boolean is1101BondType = subjectCode.startsWith("1101") && level >= 4 &&
                (secondSecuritiesName.contains("债券") || secondSecuritiesName.contains("债")
                        || thirdSecuritiesName.contains("债券") || thirdSecuritiesName.contains("债")
                        || fourSecuritiesName.contains("债券") || fourSecuritiesName.contains("债"));
        if (is1101BondType) {
            info.setSecType(HoldingType.Bond.getId());
            info.setSubType(HoldingType.Bond.getId());
            return;
        }
        // 5.1108开头并且层级 >=4 并且二级或三级或四级科目带有“债”
        boolean is1108BondType = subjectCode.startsWith("1108") && level >= 4
                && (secondSecuritiesName.contains("债") || thirdSecuritiesName.contains("债") || fourSecuritiesName.contains("债"));
        if (is1108BondType) {
            info.setSecType(HoldingType.Bond.getId());
            info.setSubType(HoldingType.Bond.getId());
            return;
        }

        // 正逆回购类
        if (startWith(AccountingNewItems.BOND_BACK_LIST, subjectCode)) {
            info.setSecType(HoldingType.BondBack.getId());
            // 2202-正回购
            if (subjectCode.startsWith("2202")) {
                info.setSubType(HoldingType.BondBackRepo.getId());
            }
            // 1202-逆回购
            if (subjectCode.startsWith("1202")) {
                info.setSubType(HoldingType.BondBackReverseRepo.getId());
            }
            return;
        }

        // 四.基金类
        if (startWith(AccountingNewItems.FUND_LIST, subjectCode)) {
            // "1108"开头并且非“债券类型”才归为基金(先识别债券再识别基金)
            // 1."1105","1107","1109","1110"开头
            info.setSecType(HoldingType.Fund.getId());
            info.setSubType(HoldingType.Fund.getId());
            return;
        }
        // 2."1101"开头并且层级<4 或 "1101"开头并且二级或三级或四级科目含有"基金"或"理财"
        boolean is1101FundType = subjectCode.startsWith("1101") && level < 4 || (subjectCode.startsWith("1101") &&
                (secondSecuritiesName.contains("基金") || secondSecuritiesName.contains("理财")
                        || thirdSecuritiesName.contains("基金") || thirdSecuritiesName.contains("理财")
                        || fourSecuritiesName.contains("基金") || fourSecuritiesName.contains("理财")));
        if (is1101FundType) {
            info.setSecType(HoldingType.Fund.getId());
            info.setSubType(HoldingType.Fund.getId());
            return;
        }
        // 3.2101开头并且层级>=4,二级或三级科目名称包含“ETF”
        boolean is2101FundType = subjectCode.startsWith("2101") && level >= 4
                && (secondSecuritiesName.contains("ETF") || thirdSecuritiesName.contains("ETF") || fourSecuritiesName.contains("ETF"));
        if (is2101FundType) {
            info.setSecType(HoldingType.Fund.getId());
            info.setSubType(HoldingType.Fund.getId());
            return;
        }

        // 五.期货、期权类
        if (startWith(AccountingNewItems.DERIVATIVES, subjectCode)) {
            // 其他衍生品
            boolean isDerivatives = secondSecuritiesName.contains("收益互换") || thirdSecuritiesName.contains("收益互换") || fourSecuritiesName.contains("收益互换");
            boolean isOptionType = secondSecuritiesName.contains("期权") || thirdSecuritiesName.contains("期权") || fourSecuritiesName.contains("期权");
            if (level < 4) {
                // 层级小于4,并且二级或三级科目包含“期权” -> 期权
                if (isOptionType) {
                    info.setSecType(HoldingType.Option.getId());
                    info.setSubType(HoldingType.Option.getId());
                    return;
                }
                // 层级小于4,并且非期权非其他衍生品 -> 期货
                if (!isDerivatives) {
                    info.setSecType(HoldingType.Future.getId());
                    info.setSubType(HoldingType.Future.getId());
                    return;
                }
                // 层级小于4,并且二级或三级科目包含“收益互换” -> 其他衍生品
                info.setSecType(HoldingType.Derivatives.getId());
                info.setSubType(HoldingType.Derivatives.getId());
                return;
            }

            // 标识子类类型
            String securitiesName = info.getSecuritiesName();
            if (isOptionType) {
                info.setSecType(HoldingType.Option.getId());
                // 期权通用判断
                boolean isCmdtOption = securitiesName.contains("购") || securitiesName.contains("沽") || securitiesName.contains("C") || securitiesName.contains("P");
                // ETF期权
                boolean isETFOption = (securitiesName.contains("ETF") || securitiesName.contains("科创50") || securitiesName.contains("科创板50"))
                        && isCmdtOption;
                // 股指期权
                boolean isIndexOption = (securitiesName.contains("上证50") || securitiesName.contains("沪深300") || securitiesName.contains("中证1000"))
                        && isCmdtOption;
                if (isETFOption) {
                    info.setSubType(HoldingType.ETFOption.getId());
                    return;
                }
                if (isIndexOption) {
                    info.setSubType(HoldingType.IndexOption.getId());
                    return;
                }
                if (isCmdtOption) {
                    info.setSubType(HoldingType.CmdtOption.getId());
                    return;
                }
                // 归为其他期权
                info.setSubType(HoldingType.Other.getId());
                return;
            }

            // 非期权和非其他衍生品 -> 期货类
            if (!isDerivatives) {
                String stockCode = info.getSecuritiesCode();
                info.setSecuritiesCode(stockCode);
                info.setSecType(HoldingType.Future.getId());
                if (startWith(AccountingNewItems.INDEX_FUTRUE, stockCode)) {
                    // 股指期货
                    info.setSubType(HoldingType.IndexFuture.getId());
                    return;
                }
                if (startWith(AccountingItems.BOND_FUTRUE, stockCode) || info.getSecuritiesName().contains("国债")) {
                    if (stockCode.startsWith("TA")) {
                        //  国债期货(T),商品期货(TA)存在冲突,先识别商品期货,再识别国债期货
                        info.setSubType(HoldingType.CmdtFuture.getId());
                        return;
                    }
                    // 国债期货
                    info.setSubType(HoldingType.BondFuture.getId());
                    return;
                }
                if (startWith(AccountingItems.CMDT_FUTRUE, stockCode)) {
                    // 商品期货
                    info.setSubType(HoldingType.CmdtFuture.getId());
                    return;
                }
                // 归为其他期货
                info.setSubType(HoldingType.Other.getId());
                return;
            }
            // 其他衍生品
            info.setSecType(HoldingType.Derivatives.getId());
            // 二三四级科目是否包含"冲抵" -> 冲抵现金
            if (secondSecuritiesName.contains("冲抵") || thirdSecuritiesName.contains("冲抵") || fourSecuritiesName.contains("冲抵")) {
                info.setSubType(HoldingType.CostCash.getId());
            } else {
                info.setSubType(HoldingType.Derivatives.getId());
            }
            return;
        }

        // 以3199开头 -> 其他衍生品
        if (subjectCode.startsWith("3199")) {
            info.setSecType(HoldingType.Derivatives.getId());
            info.setSubType(HoldingType.Derivatives.getId());
            return;
        }

        // 七.其他类
        if (startWith(AccountingNewItems.OTHER, subjectCode)) {
            info.setSecType(HoldingType.Other.getId());
            info.setSubType(HoldingType.Other.getId());
            return;
        }
        // 其他资产类
        if (startWith(AccountingNewItems.OTHER_ASSET, subjectCode)) {
            info.setSecType(HoldingType.Other.getId());
            info.setSubType(HoldingType.OTHER_ASSET.getId());
            return;
        }
        // 其他负债类
        if (startWith(AccountingNewItems.OTHER_DEBT, subjectCode)) {
            info.setSecType(HoldingType.Other.getId());
            info.setSubType(HoldingType.OTHER_DEBT.getId());
            return;
        }

        // 八.兜底策略
        if (info.getSecType() == null && StrUtil.isNotBlank(secondSecuritiesName) && StrUtil.isNotBlank(thirdSecuritiesName)) {
            if (secondSecuritiesName.contains("资产") || thirdSecuritiesName.contains("资产")) {
                info.setSecType(HoldingType.Cash.getId());
                info.setSubType(HoldingType.Cash.getId());
                return;
            }
            if (secondSecuritiesName.contains("股票") || thirdSecuritiesName.contains("股")) {
                info.setSecType(HoldingType.Stock.getId());
                info.setSubType(HoldingType.Stock.getId());
                return;
            }
            if (secondSecuritiesName.contains("基金") || thirdSecuritiesName.contains("基金")) {
                info.setSecType(HoldingType.Other.getId());
                info.setSubType(HoldingType.Other.getId());
                return;
            }
            if ((secondSecuritiesName.contains("理财") || thirdSecuritiesName.contains("理财"))
                    && (info.getSubjectCode().startsWith("1101.08") || info.getSubjectCode().startsWith("1101.09"))) {
                info.setSecType(HoldingType.Other.getId());
                info.setSubType(HoldingType.Other.getId());
                return;
            }
            if (secondSecuritiesName.contains("债") || thirdSecuritiesName.contains("债")) {
                if (!secondSecuritiesName.contains("负债") && !thirdSecuritiesName.contains("负债")) {
                    info.setSecType(HoldingType.Bond.getId());
                    info.setSubType(HoldingType.Bond.getId());
                } else {
                    info.setSecType(HoldingType.Other.getId());
                    info.setSubType(HoldingType.Other.getId());
                }
            }
        }

    }

    /**
     * 股票类子类识别:沪港通,深港通,港股通
     *
     * @param secondSecuritiesName 二级证券名称
     * @param thirdSecuritiesName  三级证券名称
     * @return 股票子类
     */
    private static Integer dealStockSubType(String secondSecuritiesName, String thirdSecuritiesName) {
        if (secondSecuritiesName.contains("沪港通") || thirdSecuritiesName.contains("沪港通")) {
            return HoldingType.StockSHH.getId();
        }
        if ((secondSecuritiesName.contains("深港通") || thirdSecuritiesName.contains("深港通"))) {
            return HoldingType.StockSZH.getId();
        }
        if ((secondSecuritiesName.contains("港股通") || thirdSecuritiesName.contains("港股通"))) {
            return HoldingType.StockHGT.getId();
        }
        return HoldingType.Stock.getId();
    }

    /**
     * 多头、空头识别
     *
     * @param fundPositionDetail 持仓明细对象
     */
    public static void addLongShort(FundPositionDetailDO fundPositionDetail) {
        Integer secType = fundPositionDetail.getSecType();
        if (secType == null) {
            return;
        }
        String subjectCode = fundPositionDetail.getSubjectCode();
        // 股票类：归属于1102,1101下的股票为多头；归属于2101下的股票为空头
        if (secType == HoldingType.Stock.getId()) {
            if (subjectCode.startsWith("1102") || subjectCode.startsWith("1101")) {
                fundPositionDetail.setNature(BULL_LONG_SHORT);
                return;
            }
            if (subjectCode.startsWith("2101")) {
                fundPositionDetail.setNature(BEAR_LONG_SHORT);
                return;
            }
        }
        // 债券类：归属于1101,1103,1104下的债券为多头；归属于2101下的债券为空头
        if (secType == HoldingType.Bond.getId()) {
            if (subjectCode.startsWith("110") || subjectCode.startsWith("1102") || subjectCode.startsWith("1104")) {
                fundPositionDetail.setNature(BULL_LONG_SHORT);
                return;
            }
            if (subjectCode.startsWith("2101")) {
                fundPositionDetail.setNature(BEAR_LONG_SHORT);
                return;
            }
        }
        // 期货,期权,衍生品类
        if (secType == HoldingType.Future.getId() || secType == HoldingType.Option.getId() || secType == HoldingType.Derivatives.getId()) {
            BigDecimal netCost = fundPositionDetail.getNetCost();
            Integer longShort = inferFutureOptionLongShort(netCost, fundPositionDetail.getLevel(), fundPositionDetail.getMarketValue());
            fundPositionDetail.setNature(longShort);
        }
        // 正回购 -> 空头
        if (secType == HoldingType.Bond.getId() && fundPositionDetail.getSubjectCode().startsWith("2202")) {
            fundPositionDetail.setNature(BEAR_LONG_SHORT);
        }
        // 2101下的基金 -> 空头
        if (secType == HoldingType.Fund.getId() && fundPositionDetail.getSubjectCode().startsWith("2101")) {
            fundPositionDetail.setNature(BEAR_LONG_SHORT);
        }
        // 其他资产 -> 多头, 其他负债 -> 空头
        if (secType == HoldingType.Other.getId() && fundPositionDetail.getSubType() != null && fundPositionDetail.getSubType().equals(HoldingType.OTHER_DEBT.getId())) {
            fundPositionDetail.setNature(BEAR_LONG_SHORT);
        }
    }

    /**
     * 获取持仓明细的二、三级、四级证券名称
     *
     * @param fundPositionDetail             持仓明细
     * @param dataList                       估值表持仓明细数据
     * @param originalCodePreOriginalCodeMap 科目代码-上一级科目代码映射关系
     * @param securitiesNameList
     * @return 持仓明细的二、三级、四级证券名称
     */
    private static void getPreSecuritiesName(FundPositionDetailDO fundPositionDetail, List<FundPositionDetailDO> dataList,
                                             Map<String, String> originalCodePreOriginalCodeMap, List<String> securitiesNameList) {
        Integer level = fundPositionDetail.getLevel();
        String preOriginalCode = originalCodePreOriginalCodeMap.get(fundPositionDetail.getSubjectCode());
        if (StrUtil.isBlank(preOriginalCode) || level == null || level == 1) {
            return;
        }
        if (level == 2) {
            securitiesNameList.set(0, fundPositionDetail.getSecuritiesName());
        }
        if (level == 3) {
            String secondSecuritiesName = dataList.stream().filter(e -> e.getSubjectCode().equals(preOriginalCode))
                    .findFirst().map(FundPositionDetailDO::getSecuritiesName).orElse("");
            securitiesNameList.set(0, secondSecuritiesName);
            securitiesNameList.set(1, fundPositionDetail.getSecuritiesName());
        }
        if (level == 4) {
            securitiesNameList.set(2, fundPositionDetail.getSecuritiesName());
        }
        if (level >= 4) {
            FundPositionDetailDO preFundPositionDetail = dataList.stream().filter(e -> e.getSubjectCode().equals(preOriginalCode))
                    .findFirst().orElse(null);
            if (preFundPositionDetail != null) {
                getPreSecuritiesName(preFundPositionDetail, dataList, originalCodePreOriginalCodeMap, securitiesNameList);
            }
        }
    }

    /**
     * 识别交易场所
     * MarketTradIngCodeEnum
     *
     * @param info       持仓明细对象数据
     * @param marketName 二级、三级证券名称
     */
    public static void addMarketIdNew(FundPositionDetailDO info, String marketName) {
        if (info.getSecType() == null) {
            return;
        }
        // 股票交易场所
        if (info.getSecType() == HoldingType.Stock.getId()) {
            addStockMarketId(info, marketName);
        }
        // 债券交易场所
        if (info.getSecType() == HoldingType.Bond.getId() || info.getSecType() == HoldingType.BondBack.getId()) {
            addBondMarketId(info, marketName);
        }
        // 期货、期权交易场所
        if (info.getSecType() == HoldingType.Future.getId() || info.getSecType() == HoldingType.Option.getId()) {
            addFutureOptionMarketId(info, marketName);
        }
    }

    private static void addBondMarketId(FundPositionDetailDO info, String marketName) {
        if (marketName.contains("上交") || marketName.contains("上海")) {
            // 二级或三级科目包含"上交"或"上海" -> 上交所
            info.setMarketId(MarketTradIngCodeEnum.SSE.getMarketId());
            return;
        }
        if (marketName.contains("深交") || marketName.contains("深圳")) {
            // 二级或三级科目包含"深交"或"深圳" -> 深交所
            info.setMarketId(MarketTradIngCodeEnum.SZSE.getMarketId());
            return;
        }
        if (marketName.contains("北交") || marketName.contains("北京")) {
            //  二级或三级科目包含“北交”或“北京”-> 北交所
            info.setMarketId(MarketTradIngCodeEnum.NEEQ.getMarketId());
            return;
        }
        if (marketName.contains("银行间")) {
            //  二级或三级科目包含“银行间”-> 银行间
            info.setMarketId(MarketTradIngCodeEnum.IBM.getMarketId());
            return;
        }
        // 兜底策略:交易场所为场外(OTC)
        if (info.getMarketId() == null) {
            info.setMarketId(MarketTradIngCodeEnum.OTC.getMarketId());
        }
    }

    /**
     * 识别期货、期权交易场所
     *
     * @param info       持仓明细对象数据
     * @param marketName 二级、三级证券名称
     */
    private static void addFutureOptionMarketId(FundPositionDetailDO info, String marketName) {
        if (marketName.contains("上交") || (marketName.contains("上海")
                && !marketName.contains("上海能源") && !marketName.contains("上海商品") && !marketName.contains("上海期货"))) {
            // 二级或三级科目包含"上交"或"上海"并且不包含"上海能源"和"上海商品"和"上海期货" -> 上交所
            info.setMarketId(MarketTradIngCodeEnum.SSE.getMarketId());
            return;
        }
        if (marketName.contains("深交") || marketName.contains("深圳")) {
            // 二级或三级科目包含"深交"或"深圳" -> 深交所
            info.setMarketId(MarketTradIngCodeEnum.SZSE.getMarketId());
            return;
        }
        if (marketName.contains("中金所") && info.getSecType() != null && info.getSecType().equals(HoldingType.Future.getId())) {
            // 二级或三级科目包含"中金所" -> 中国金融期货交易所(期货-20,期权-51)
            info.setMarketId(MarketTradIngCodeEnum.CFFEX_FUTURE.getMarketId());
            return;
        }
        if (marketName.contains("中金所") && info.getSecType() != null && info.getSecType().equals(HoldingType.Option.getId())) {
            // 二级或三级科目包含"中金所" -> 中国金融期货交易所(期货-20,期权-51)
            info.setMarketId(MarketTradIngCodeEnum.CFFEX_OPTION.getMarketId());
            return;
        }
        if (marketName.contains("广州商品") || marketName.contains("广期所") || marketName.contains("广州期货")) {
            // 二级或三级科目包含"广州商品"或"广期所"或"广州期货”-> 广州期货交易所
            info.setMarketId(MarketTradIngCodeEnum.GZFE.getMarketId());
            return;
        }
        if (marketName.contains("郑州商品") || marketName.contains("郑商所") || marketName.contains("郑州期货")) {
            // 二级或三级科目包含"郑州商品"或"郑商所"或"郑州期货”-> 郑州期货交易所
            info.setMarketId(MarketTradIngCodeEnum.CZC.getMarketId());
            return;
        }
        if (marketName.contains("大连商品") || marketName.contains("大商所") || marketName.contains("大连期货")) {
            // 二级或三级科目包含"大连商品"或"大商所"或"大连期货”-> 大连期货交易所
            info.setMarketId(MarketTradIngCodeEnum.DCE.getMarketId());
            return;
        }
        if (marketName.contains("上海能源")) {
            // 二级或三级科目包含"上海能源" -> 上海国际能源交易中心
            info.setMarketId(MarketTradIngCodeEnum.INE.getMarketId());
            return;
        }
        if (marketName.contains("上海商品") || marketName.contains("上期所") || marketName.contains("上海期货")) {
            // 二级或三级科目包含"上海商品"或"上期所"或"上海期货”-> 上海期货交易所
            info.setMarketId(MarketTradIngCodeEnum.SHFE.getMarketId());
            return;
        }
        // 兜底策略:交易场所为场外(OTC)
        if (info.getMarketId() == null) {
            info.setMarketId(MarketTradIngCodeEnum.OTC.getMarketId());
        }
    }

    /**
     * 识别股票交易场所
     *
     * @param info       持仓明细对象数据
     * @param marketName 二级、三级证券名称
     */
    private static void addStockMarketId(FundPositionDetailDO info, String marketName) {
        if (marketName.contains("场外") || marketName.contains("新三板")) {
            // 二级或三级科目包含“场外“或”新三板 -> 新三板
            info.setMarketId(MarketTradIngCodeEnum.NTBC.getMarketId());
            return;
        }
        if (marketName.contains("上交") || marketName.contains("上海")) {
            // 二级或三级科目包含"上交"或"上海" -> 上交所
            info.setMarketId(MarketTradIngCodeEnum.SSE.getMarketId());
            return;
        }
        if (marketName.contains("深交") || marketName.contains("深圳")) {
            // 二级或三级科目包含"深交"或"深圳" -> 深交所
            info.setMarketId(MarketTradIngCodeEnum.SZSE.getMarketId());
            return;
        }
        if (marketName.contains("北交") || marketName.contains("北京")) {
            //  二级或三级科目包含“北交”或“北京”-> 北交所
            info.setMarketId(MarketTradIngCodeEnum.NEEQ.getMarketId());
            return;
        }
        if (marketName.contains("港") || marketName.contains("港股通")) {
            // 二级或三级科目包含"港"或"港股通" -> 港交所
            info.setMarketId(MarketTradIngCodeEnum.HKEX.getMarketId());
            if (info.getSecuritiesCode() != null && info.getSecuritiesCode().startsWith("H")) {
                info.setSecuritiesCode(info.getSecuritiesCode().replace("H", ""));
            }
        }
        if (marketName.contains("沪港通")) {
            if (info.getSecuritiesCode() != null) {
                if (info.getSecuritiesCode().startsWith("6")) {
                    info.setMarketId(MarketTradIngCodeEnum.SSE.getMarketId());
                } else if (info.getSecuritiesCode().startsWith("H")) {
                    info.setSecuritiesCode(info.getSecuritiesCode().replace("H", ""));
                }
            }
        } else if (marketName.contains("深港通")) {
            if (info.getSecuritiesCode() != null) {
                if (!info.getSecuritiesCode().startsWith("H")) {
                    info.setMarketId(MarketTradIngCodeEnum.SZSE.getMarketId());
                } else {
                    info.setSecuritiesCode(info.getSecuritiesCode().replace("H", ""));
                }
            }
        }
        // 兜底策略:交易场所为场外(OTC)
        if (info.getMarketId() == null) {
            info.setMarketId(MarketTradIngCodeEnum.OTC.getMarketId());
        }
    }

    /**
     * 期货及衍生品空头、多头识别逻辑
     *
     * @param netCost     成本
     * @param level       层级
     * @param marketValue 市值
     * @return 1-多头 或 2-空头
     */
    private static Integer inferFutureOptionLongShort(BigDecimal netCost, int level, BigDecimal marketValue) {
        //1.期货及衍生品的一级,二级,三级科目的多头空头识别逻辑:通过市值正负确认,正则为多头,反之空头
        Integer inferByMarketValue = marketValue != null && marketValue.compareTo(BigDecimal.ZERO) > 0 ? BULL_LONG_SHORT : BEAR_LONG_SHORT;
        if (level <= 3) {
            return inferByMarketValue;
        }
        //成本为空时,识别为多头(在持仓分析的时候,会过滤掉成本为空的数据,因此无意义的,但为了防止空指针,默认为多头)
        if (netCost == null) {
            return BULL_LONG_SHORT;
        }
        //2.期货及衍生品的四级以上科目:1-如果成本小于0为空头;2-等于0时,市值为正则为多头,反之空头;3-成本大于0为多头
        if (netCost.compareTo(BigDecimal.ZERO) < 0) {
            return BEAR_LONG_SHORT;
        }
        if (netCost.compareTo(BigDecimal.ZERO) == 0) {
            return inferByMarketValue;
        }
        return BULL_LONG_SHORT;
    }

    private static boolean startWith(Collection<String> codeSet, String subCode) {
        for (String code : codeSet) {
            if (subCode.startsWith(code)) {
                return true;
            }
        }
        return false;
    }

    public static int getSubjectCodeEndIndex(String str) {
        char[] cArr = str.toCharArray();
        if (!Character.isDigit(cArr[0])) {
            return 0;
        }
        int startIndex = 0;
        for (int i = 0; i < cArr.length; i++) {
            int index = cArr[i];
            if ((index >= 48 && index <= 57) || (index >= 65 && index <= 90) || (index >= 97 && index <= 122)) {
                continue;
            }
            startIndex = i;
            break;
        }
        return startIndex;
    }

    public static List<CmValuationTableAttribute> getAttrList(List<AssetsValuationInfo> dataList) {
        List<CmValuationTableAttribute> attrList = new ArrayList<>(dataList.size());
        for (AssetsValuationInfo info : dataList) {
            CmValuationTableAttribute attr = new CmValuationTableAttribute();
            attr.setUserid(info.getUserId());
            attr.setSubjectCode(info.getSubjectCode());

            attr.setOriginalSubjectCode(info.getOriginalSubjectCode());
            attr.setSubjectName(info.getSubjectName());
            attr.setSecuritiesAmount(BigDecimalUtils.toBigDecimal(info.getSecuritiesAmount()));
            attr.setUnitCost(BigDecimalUtils.toBigDecimal(info.getUnitCost()));
            attr.setNetCost(BigDecimalUtils.toBigDecimal(info.getNetCost()));
            attr.setNetCostRatio(BigDecimalUtils.toBigDecimal(info.getNetCostRatio()));
            attr.setMarketValue(BigDecimalUtils.toBigDecimal(info.getMarketValue()));
            attr.setMarketValueRatio(BigDecimalUtils.toBigDecimal(info.getMarketValueRatio()));
            attr.setIncrement(BigDecimalUtils.toBigDecimal(info.getIncrement()));
            attr.setHaltInfo(info.getHaltInfo());
            attr.setRightsInterestsInfo(info.getRightsInterestsInfo());
            attr.setMarketPrice(BigDecimalUtils.toBigDecimal(info.getMarketPrice()));
            attr.setCurrency(info.getCurrency());
            if (info.getExchangeRate() != null) {
                attr.setExchangeRate(BigDecimalUtils.toBigDecimal(info.getExchangeRate()));
            }
            attr.setOCurrencyCost(BigDecimalUtils.toBigDecimal(info.getOriCurrencyCost()));
            attr.setOCurrencyMarketValue(BigDecimalUtils.toBigDecimal(info.getOriCurrencyMarketValue()));
            attr.setOCurrencyValueAdded(BigDecimalUtils.toBigDecimal(info.getOriCurrencyValueAdded()));
            attrList.add(attr);
        }
        return attrList;
    }
}
