package com.yingpai.stock.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.idev.excel.EasyExcel;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.read.listener.ReadListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yingpai.stock.domain.StockPool;
import com.yingpai.stock.domain.StockPoolHistory;
import com.yingpai.stock.domain.bo.StockPoolHistoryBo;
import com.yingpai.stock.domain.vo.StockPoolHistoryVo;
import com.yingpai.stock.mapper.StockPoolHistoryMapper;
import com.yingpai.stock.mapper.StockPoolMapper;
import com.yingpai.stock.service.IStockPoolHistoryService;
import com.yingpai.stock.service.IStockPoolService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 股票池历史服务实现类
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {

    private final StockPoolHistoryMapper baseMapper;
    private final StockPoolMapper stockPoolMapper;
    private final IStockPoolService stockPoolService;

    @Override
    public TableDataInfo<StockPoolHistoryVo> queryPageList(StockPoolHistoryBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<StockPoolHistory> lqw = buildQueryWrapper(bo);
        Page<StockPoolHistoryVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public List<StockPoolHistoryVo> queryList(StockPoolHistoryBo bo) {
        LambdaQueryWrapper<StockPoolHistory> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public StockPoolHistoryVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    @Override
    public Boolean insertByBo(StockPoolHistoryBo bo) {
        StockPoolHistory entity = BeanUtil.toBean(bo, StockPoolHistory.class);
        entity.setAdminId(LoginHelper.getUserId());
        boolean flag = baseMapper.insert(entity) > 0;
        if (flag) {
            bo.setId(entity.getId());
        }
        return flag;
    }

    @Override
    public Boolean updateByBo(StockPoolHistoryBo bo) {
        StockPoolHistory entity = BeanUtil.toBean(bo, StockPoolHistory.class);
        return baseMapper.updateById(entity) > 0;
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importData(MultipartFile file, String recordDate, Boolean updateSupport) throws Exception {
        // 解析记录日期
        LocalDate parsedRecordDate;
        try {
            parsedRecordDate = LocalDate.parse(recordDate);
        } catch (Exception e) {
            throw new RuntimeException("记录日期格式错误，请使用 yyyy-MM-dd 格式");
        }

        // 读取 Excel 数据
        String originalFilename = file.getOriginalFilename();
        log.info("导入文件名: {}, 文件大小: {} bytes", originalFilename, file.getSize());

        // 判断文件类型
        boolean isXls = originalFilename != null && originalFilename.toLowerCase().endsWith(".xls")
            && !originalFilename.toLowerCase().endsWith(".xlsx");
        log.info("文件类型: {}", isXls ? "xls (Excel 97-2003)" : "xlsx (Excel 2007+)");

        // 使用 Map 方式读取原始数据，避免类型转换问题
        List<Map<Integer, String>> rawDataList = new ArrayList<>();

        // 使用 BufferedInputStream 支持 mark/reset
        InputStream inputStream = new BufferedInputStream(file.getInputStream());

        try {
            if (isXls) {
                // .xls 文件使用 GBK 编码读取（解决中文乱码问题）
                log.info("使用 GBK 编码读取 .xls 文件");
                EasyExcel.read(inputStream, new ReadListener<Map<Integer, String>>() {
                    @Override
                    public void invoke(Map<Integer, String> data, AnalysisContext context) {
                        rawDataList.add(data);
                    }
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        log.info("Excel 读取完成，共 {} 行", rawDataList.size());
                    }
                }).charset(Charset.forName("GBK")).sheet().headRowNumber(1).doRead();
            } else {
                // .xlsx 文件让 EasyExcel 自动处理
                log.info("读取 .xlsx 文件");
                EasyExcel.read(inputStream, new ReadListener<Map<Integer, String>>() {
                    @Override
                    public void invoke(Map<Integer, String> data, AnalysisContext context) {
                        rawDataList.add(data);
                    }
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        log.info("Excel 读取完成，共 {} 行", rawDataList.size());
                    }
                }).sheet().headRowNumber(1).doRead();
            }
        } catch (Exception e) {
            log.error("Excel 读取失败: {}", e.getMessage());
            throw new RuntimeException("无法读取Excel文件，请确保文件格式正确（支持 .xls 和 .xlsx 格式）。错误: " + e.getMessage());
        }

        if (rawDataList.isEmpty()) {
            return "导入数据为空";
        }

        log.info("读取到 {} 条原始数据", rawDataList.size());

        // 输出前5条原始数据用于调试
        for (int i = 0; i < Math.min(5, rawDataList.size()); i++) {
            Map<Integer, String> row = rawDataList.get(i);
            log.info("=== 调试 - 第{}条原始数据（共{}列）===", i + 1, row.size());
            for (Map.Entry<Integer, String> entry : row.entrySet()) {
                String value = entry.getValue();
                log.info("  列{}: [{}] (长度:{})", entry.getKey(),
                    value != null && value.length() > 50 ? value.substring(0, 50) + "..." : value,
                    value != null ? value.length() : 0);
            }
        }

        // 检查是否所有数据都在一列中（可能是制表符分隔的文本）
        if (!rawDataList.isEmpty()) {
            Map<Integer, String> firstRow = rawDataList.get(0);
            if (firstRow.size() == 1) {
                // 只有一列数据，尝试按制表符分割
                log.warn("检测到只有1列数据，尝试按制表符分割...");
                List<Map<Integer, String>> splitDataList = new ArrayList<>();
                for (Map<Integer, String> row : rawDataList) {
                    String singleValue = row.get(0);
                    if (singleValue != null) {
                        String[] parts = singleValue.split("\t");
                        Map<Integer, String> newRow = new java.util.HashMap<>();
                        for (int j = 0; j < parts.length; j++) {
                            newRow.put(j, parts[j].trim());
                        }
                        splitDataList.add(newRow);
                    }
                }
                if (!splitDataList.isEmpty() && splitDataList.get(0).size() > 1) {
                    log.info("制表符分割成功，每行 {} 列", splitDataList.get(0).size());
                    rawDataList.clear();
                    rawDataList.addAll(splitDataList);

                    // 再次输出调试信息
                    for (int i = 0; i < Math.min(3, rawDataList.size()); i++) {
                        Map<Integer, String> row = rawDataList.get(i);
                        log.info("分割后第{}条: 列0=[{}], 列1=[{}], 列2=[{}]",
                            i + 1, row.get(0), row.get(1), row.get(2));
                    }
                }
            }
        }

        // 将原始数据转换为 StockPoolHistoryVo
        List<StockPoolHistoryVo> dataList = new ArrayList<>();
        for (Map<Integer, String> row : rawDataList) {
            StockPoolHistoryVo vo = new StockPoolHistoryVo();
            vo.setStockCode(getStringValue(row, 0));
            vo.setStockName(getStringValue(row, 1));
            vo.setChangePercent(getBigDecimalValue(row, 2));
            vo.setClosePrice(getBigDecimalValue(row, 3));
            vo.setTotalAmount(getBigDecimalValue(row, 4));
            vo.setStrengthScore(getBigDecimalValue(row, 5));
            vo.setCirculationMarketValue(getBigDecimalValue(row, 6));
            vo.setMainRisePeriod(getStringValue(row, 7));
            vo.setRecentRiseHand(getStringValue(row, 8));
            vo.setRecentLimitUp(getStringValue(row, 9));
            vo.setDayHighestPrice(getBigDecimalValue(row, 10));
            vo.setDayLowestPrice(getBigDecimalValue(row, 11));
            vo.setDayAvgPrice(getBigDecimalValue(row, 12));
            vo.setDayClosePrice(getBigDecimalValue(row, 13));
            dataList.add(vo);
        }

        log.info("转换后数据 {} 条", dataList.size());

        // 输出前5条转换后的数据用于调试
        for (int i = 0; i < Math.min(5, dataList.size()); i++) {
            StockPoolHistoryVo debugVo = dataList.get(i);
            log.info("转换后第{}条: 代码=[{}], 名称=[{}], 涨幅=[{}], 收盘=[{}]",
                i + 1, debugVo.getStockCode(), debugVo.getStockName(),
                debugVo.getChangePercent(), debugVo.getClosePrice());
        }

        // 如果是重复导入同一天的数据，先删除该日期的所有历史记录
        LambdaQueryWrapper<StockPoolHistory> deleteLqw = Wrappers.lambdaQuery();
        deleteLqw.eq(StockPoolHistory::getRecordDate, parsedRecordDate);
        int deletedCount = baseMapper.delete(deleteLqw);
        if (deletedCount > 0) {
            log.info("删除同一天的旧历史记录: {} 条", deletedCount);
        }

        int successNum = 0;
        int updateNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();

        // 批量查询已存在的记录
        List<String> stockCodes = dataList.stream()
            .map(StockPoolHistoryVo::getStockCode)
            .filter(StringUtils::isNotBlank)
            .distinct()
            .collect(java.util.stream.Collectors.toList());

        Map<String, StockPoolHistory> existingMap = new java.util.HashMap<>();
        if (!stockCodes.isEmpty()) {
            LambdaQueryWrapper<StockPoolHistory> lqw = Wrappers.lambdaQuery();
            lqw.in(StockPoolHistory::getStockCode, stockCodes)
                .eq(StockPoolHistory::getRecordDate, parsedRecordDate);
            List<StockPoolHistory> existingList = baseMapper.selectList(lqw);
            existingMap = existingList.stream()
                .collect(java.util.stream.Collectors.toMap(StockPoolHistory::getStockCode, e -> e));
        }

        // 准备批量插入和更新的列表
        List<StockPoolHistory> toInsertList = new ArrayList<>();
        List<StockPoolHistory> toUpdateList = new ArrayList<>();

        for (int i = 0; i < dataList.size(); i++) {
            StockPoolHistoryVo vo = dataList.get(i);
            try {
                // 处理股票代码（去除可能的引号和公式格式）
                String stockCode = vo.getStockCode();
                String stockName = vo.getStockName();

                if (stockCode != null) {
                    // 去除前后空格
                    stockCode = stockCode.trim();

                    // 调试日志：记录前几条数据的原始值
                    if (i < 5) {
                        log.info("第{}条数据 - 处理前代码: [{}], 长度: {}, 名称: [{}]",
                            i + 1, stockCode, stockCode.length(), stockName);
                    }

                    // 处理公式格式 ="000547"
                    if (stockCode.startsWith("=")) {
                        stockCode = stockCode.substring(1);
                    }

                    // 去除所有类型的引号（使用 Unicode 转义避免编码问题）
                    stockCode = stockCode.replace("\"", "");  // 双引号
                    stockCode = stockCode.replace("'", "");   // 单引号
                    stockCode = stockCode.replace("\u201C", "");  // 中文左双引号
                    stockCode = stockCode.replace("\u201D", "");  // 中文右双引号
                    stockCode = stockCode.replace("\u2018", "");  // 中文左单引号
                    stockCode = stockCode.replace("\u2019", "");  // 中文右单引号

                    // 去除所有空白字符（包括空格、制表符、换行符等）
                    stockCode = stockCode.replaceAll("\\s+", "");

                    // 只保留数字和字母（股票代码只应该包含这些字符）
                    stockCode = stockCode.replaceAll("[^0-9A-Za-z]", "");

                    // 确保长度不超过20个字符（数据库限制）
                    if (stockCode.length() > 20) {
                        log.warn("第{}条数据 - 股票代码过长，截取前20位: [{}] -> [{}]",
                            i + 1, stockCode, stockCode.substring(0, 20));
                        stockCode = stockCode.substring(0, 20);
                    }

                    // 调试日志：记录处理后的值
                    if (i < 5) {
                        log.info("第{}条数据 - 处理后代码: [{}], 长度: {}", i + 1, stockCode, stockCode.length());
                    }

                    vo.setStockCode(stockCode);
                }

                // 处理股票名称（去除可能的特殊字符）
                if (stockName != null) {
                    stockName = stockName.trim();
                    // 确保长度不超过50个字符（数据库限制）
                    if (stockName.length() > 50) {
                        log.warn("第{}条数据 - 股票名称过长，截取前50位: [{}]", i + 1, stockName);
                        stockName = stockName.substring(0, 50);
                    }
                    vo.setStockName(stockName);
                }

                // 检查必填字段 - 股票代码
                if (StringUtils.isBlank(vo.getStockCode())) {
                    failureNum++;
                    String displayName = vo.getStockName() != null ? vo.getStockName() : "未知";
                    String rowInfo = "第" + (i + 1) + "行";
                    if (StringUtils.isNotBlank(displayName) && !"未知".equals(displayName)) {
                        failureMsg.append("<br/>").append(failureNum).append("、").append(rowInfo)
                            .append("，股票名称: ").append(displayName).append("，代码为空");
                    } else {
                        failureMsg.append("<br/>").append(failureNum).append("、").append(rowInfo)
                            .append("，股票代码为空（可能是Excel列名不匹配，请检查Excel第一行是否包含'代码'列）");
                    }
                    continue;
                }

                // 验证股票代码格式（正常股票代码应该是6位数字）
                String code = vo.getStockCode();

                // 如果代码超过6位，可能是多列数据被拼接了，尝试提取前6位
                if (code.length() > 6) {
                    String originalCode = code;
                    // 尝试提取前6位作为股票代码
                    code = code.substring(0, 6);
                    log.info("第{}条数据 - 股票代码过长，尝试提取前6位: [{}] -> [{}]", i + 1, originalCode, code);
                    vo.setStockCode(code);
                }

                // 验证股票代码是否为纯6位数字
                if (!code.matches("^\\d{6}$")) {
                    log.warn("第{}条数据 - 股票代码不是6位数字，跳过: [{}]", i + 1, code);
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、第").append(i + 1)
                        .append("行，股票代码格式异常: ").append(code)
                        .append("（股票代码应为6位数字）");
                    continue;
                }

                // 检查必填字段 - 股票名称
                if (StringUtils.isBlank(vo.getStockName())) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、第").append(i + 1)
                        .append("行，股票代码: ").append(vo.getStockCode())
                        .append("，股票名称为空（请检查Excel数据）");
                    continue;
                }

                // 使用管理员指定的记录日期，而不是Excel中的日期
                vo.setRecordDate(parsedRecordDate);

                // 检查是否已存在
                StockPoolHistory existing = existingMap.get(vo.getStockCode());

                if (existing != null) {
                    if (updateSupport) {
                        // 更新所有字段
                        existing.setStockName(vo.getStockName());
                        existing.setChangePercent(vo.getChangePercent());
                        existing.setClosePrice(vo.getClosePrice());
                        existing.setTotalAmount(vo.getTotalAmount());
                        existing.setStrengthScore(vo.getStrengthScore());
                        existing.setCirculationMarketValue(vo.getCirculationMarketValue());
                        existing.setMainRisePeriod(vo.getMainRisePeriod());
                        existing.setRecentRiseHand(vo.getRecentRiseHand());
                        existing.setRecentLimitUp(vo.getRecentLimitUp());
                        existing.setDayHighestPrice(vo.getDayHighestPrice());
                        existing.setDayLowestPrice(vo.getDayLowestPrice());
                        existing.setDayAvgPrice(vo.getDayAvgPrice());
                        existing.setDayClosePrice(vo.getDayClosePrice());
                        toUpdateList.add(existing);
                        updateNum++;
                        successNum++;
                    } else {
                        failureNum++;
                        failureMsg.append("<br/>").append(failureNum).append("、股票 ")
                            .append(vo.getStockCode()).append(" 在 ")
                            .append(parsedRecordDate).append(" 的记录已存在");
                    }
                } else {
                    // 新增
                    StockPoolHistory entity = BeanUtil.toBean(vo, StockPoolHistory.class);
                    entity.setRecordDate(parsedRecordDate);
                    entity.setAdminId(LoginHelper.getUserId());
                    toInsertList.add(entity);
                    successNum++;
                }
            } catch (Exception e) {
                failureNum++;
                String code = vo.getStockCode() != null ? vo.getStockCode() : "未知";
                String msg = "<br/>" + failureNum + "、股票 " + code + " 导入失败：" + e.getMessage();
                failureMsg.append(msg);
                log.error(msg, e);
            }
        }

        // 批量计算最高涨幅
        log.info("开始批量计算最高涨幅，待插入: {} 条，待更新: {} 条", toInsertList.size(), toUpdateList.size());
        for (StockPoolHistory entity : toInsertList) {
            entity.setHighTrend(calculateHighTrend(entity.getStockCode(), parsedRecordDate, entity.getDayClosePrice()));
        }
        for (StockPoolHistory entity : toUpdateList) {
            entity.setHighTrend(calculateHighTrend(entity.getStockCode(), parsedRecordDate, entity.getDayClosePrice()));
        }

        // 批量插入
        if (!toInsertList.isEmpty()) {
            baseMapper.insertBatch(toInsertList);
            log.info("批量插入完成: {} 条", toInsertList.size());
        }

        // 批量更新
        if (!toUpdateList.isEmpty()) {
            baseMapper.updateBatchById(toUpdateList);
            log.info("批量更新完成: {} 条", toUpdateList.size());
        }

        // 将排名前十的股票加入强势池
        log.info("[强势池] 开始将排名前十的股票加入强势池，导入日期: {}", parsedRecordDate);
        addTopTenToStrongPool(parsedRecordDate);

        // 调用数据补全功能，将历史数据补全到stock_pool表
        try {
            log.info("[数据补全] 开始补全历史数据到stock_pool表，导入日期: {}", parsedRecordDate);
            String completeResult = stockPoolService.completeHistoryData(parsedRecordDate);
            log.info("[数据补全] 补全结果: {}", completeResult);
        } catch (Exception e) {
            log.error("[数据补全] 补全历史数据失败: {}", e.getMessage(), e);
        }

        if (failureNum > 0) {
            String message = String.format("导入完成！成功 %d 条（其中更新 %d 条），失败 %d 条。详细错误信息请查看服务器日志。",
                successNum, updateNum, failureNum);
            log.error("导入失败详情：{}", failureMsg.toString());
            return message;
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条（其中更新 " + updateNum + " 条）");
            return successMsg.toString();
        }
    }

    /**
     * 将排名前十的股票加入强势池（将之前的设为历史有效）
     */
    private void addTopTenToStrongPool(LocalDate recordDate) {
        try {
            // 1. 查询当天按强度评分排名前十的股票（Excel中的前10行）
            LambdaQueryWrapper<StockPoolHistory> lqw = Wrappers.lambdaQuery();
            lqw.eq(StockPoolHistory::getRecordDate, recordDate)
                .orderByAsc(StockPoolHistory::getId)  // 按ID升序，获取Excel中的前10行
                .last("LIMIT 10");
            List<StockPoolHistory> topTen = baseMapper.selectList(lqw);

            if (topTen.isEmpty()) {
                log.warn("[强势池] 未找到当天的历史数据，无法加入强势池");
                return;
            }

            log.info("[强势池] 查询到排名前十的股票: {}", topTen.stream()
                .map(h -> h.getStockCode() + "-" + h.getStockName())
                .collect(java.util.stream.Collectors.joining(", ")));

            // 2. 查询当天已存在的强势池数据
            LambdaQueryWrapper<StockPool> todayLqw = Wrappers.lambdaQuery();
            todayLqw.eq(StockPool::getPoolType, 2)
                    .eq(StockPool::getAddDate, recordDate)
                    .eq(StockPool::getStatus, 2);
            List<StockPool> todayPools = stockPoolMapper.selectList(todayLqw);
            Map<String, StockPool> todayPoolMap = todayPools.stream()
                .collect(java.util.stream.Collectors.toMap(StockPool::getStockCode, p -> p));

            // 3. 收集前十名的股票代码
            java.util.Set<String> topTenCodes = topTen.stream()
                .map(StockPoolHistory::getStockCode)
                .collect(java.util.stream.Collectors.toSet());

            // 4. 将当天存在但不在前十名中的股票状态改为1
            for (StockPool pool : todayPools) {
                if (!topTenCodes.contains(pool.getStockCode())) {
                    pool.setStatus(1);
                    stockPoolMapper.updateById(pool);
                }
            }

            // 5. 将其他日期的强势池数据状态改为1
            LambdaQueryWrapper<StockPool> otherDaysLqw = Wrappers.lambdaQuery();
            otherDaysLqw.eq(StockPool::getPoolType, 2)
                        .eq(StockPool::getStatus, 2)
                        .ne(StockPool::getAddDate, recordDate);
            List<StockPool> otherDaysPools = stockPoolMapper.selectList(otherDaysLqw);
            for (StockPool pool : otherDaysPools) {
                pool.setStatus(1);
                stockPoolMapper.updateById(pool);
            }

            // 6. 处理前十名：更新或插入
            Long adminId = LoginHelper.getUserId();
            List<StockPool> toInsert = new ArrayList<>();
            int updateCount = 0;

            for (StockPoolHistory history : topTen) {
                // 优先使用 closePrice，如果为空则使用 dayClosePrice
                BigDecimal addPrice = history.getClosePrice();
                if (addPrice == null) {
                    addPrice = history.getDayClosePrice();
                }

                // 如果两个价格都为空，跳过该记录
                if (addPrice == null) {
                    log.warn("[强势池] 股票 {} 的收盘价和当天收盘价都为空，跳过加入强势池", history.getStockCode());
                    continue;
                }

                String stockCode = history.getStockCode();
                StockPool existingPool = todayPoolMap.get(stockCode);

                if (existingPool != null) {
                    // 当天已存在该股票，更新数据
                    existingPool.setStockName(history.getStockName());
                    existingPool.setAddPrice(addPrice);
                    existingPool.setNextDayGain(history.getHighTrend());
                    existingPool.setStatus(2);
                    existingPool.setAdminId(adminId);
                    stockPoolMapper.updateById(existingPool);
                    updateCount++;
                } else {
                    // 当天不存在该股票，插入新记录
                    StockPool pool = new StockPool();
                    pool.setStockCode(stockCode);
                    pool.setStockName(history.getStockName());
                    pool.setPoolType(2);  // 强势池
                    pool.setAddPrice(addPrice);
                    pool.setAddDate(recordDate);
                    pool.setNextDayGain(history.getHighTrend());  // 设置最高涨幅
                    pool.setStatus(2);  // 当前有效
                    pool.setAdminId(adminId);
                    toInsert.add(pool);
                }
            }

            if (!toInsert.isEmpty()) {
                stockPoolMapper.insertBatch(toInsert);
                log.info("[强势池] 成功插入 {} 只股票到强势池", toInsert.size());
            }
            if (updateCount > 0) {
                log.info("[强势池] 成功更新 {} 只股票到强势池", updateCount);
            }

        } catch (Exception e) {
            log.error("[强势池] 加入强势池失败: {}", e.getMessage(), e);
        }
    }


    /**
     * 从 Map 中获取字符串值
     */
    private String getStringValue(Map<Integer, String> row, int index) {
        String value = row.get(index);
        if (value == null) {
            return null;
        }
        // 去除前后空格
        value = value.trim();
        // 去除可能的引号
        value = value.replace("\"", "").replace("'", "");
        // 去除公式前缀
        if (value.startsWith("=")) {
            value = value.substring(1);
            value = value.replace("\"", "").replace("'", "");
        }

        // 尝试修复编码问题（如果检测到乱码）
        if (containsGarbledText(value)) {
            value = tryFixEncoding(value);
        }

        return value.isEmpty() ? null : value;
    }

    /**
     * 检测是否包含乱码（简单检测）
     */
    private boolean containsGarbledText(String text) {
        if (text == null || text.isEmpty()) {
            return false;
        }
        // 检测是否包含常见的乱码特征
        // 乱码通常包含大量的特殊字符或不可打印字符
        int specialCharCount = 0;
        for (char c : text.toCharArray()) {
            // 检测是否是常见的乱码字符范围
            if (c > 0x7F && c < 0x4E00) {
                // 在 ASCII 扩展区但不在中文区
                specialCharCount++;
            }
        }
        // 如果超过30%的字符是特殊字符，可能是乱码
        return specialCharCount > text.length() * 0.3;
    }

    /**
     * 尝试修复编码问题
     */
    private String tryFixEncoding(String text) {
        if (text == null) {
            return null;
        }
        try {
            // 尝试将 ISO-8859-1 编码的字符串转换为 GBK
            byte[] bytes = text.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1);
            String gbkText = new String(bytes, java.nio.charset.Charset.forName("GBK"));
            if (!containsGarbledText(gbkText)) {
                log.debug("编码修复成功: [{}] -> [{}]", text, gbkText);
                return gbkText;
            }

            // 尝试将 UTF-8 编码的字符串转换为 GBK
            bytes = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
            gbkText = new String(bytes, java.nio.charset.Charset.forName("GBK"));
            if (!containsGarbledText(gbkText)) {
                log.debug("编码修复成功(UTF-8->GBK): [{}] -> [{}]", text, gbkText);
                return gbkText;
            }
        } catch (Exception e) {
            log.warn("编码转换失败: {}", e.getMessage());
        }
        return text;
    }

    /**
     * 从 Map 中获取 BigDecimal 值
     */
    private BigDecimal getBigDecimalValue(Map<Integer, String> row, int index) {
        String value = getStringValue(row, index);
        if (value == null || value.isEmpty()) {
            return null;
        }
        try {
            // 处理科学计数法
            return new BigDecimal(value);
        } catch (NumberFormatException e) {
            log.warn("无法解析数字: [{}]", value);
            return null;
        }
    }

    /**
     * 计算行情涨跌（最高涨幅）
     * 公式：(十日之内最高价 - 当天收盘价) / 当天收盘价 * 100
     * 如果找不到数据则返回0
     *
     * @param stockCode 股票代码
     * @param recordDate 当前记录日期
     * @param dayClosePrice 当天收盘价
     * @return 最高涨幅百分比，保留2位小数
     */
    private BigDecimal calculateHighTrend(String stockCode, LocalDate recordDate, BigDecimal dayClosePrice) {
        if (dayClosePrice == null || dayClosePrice.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        // 查询十日内最高价
        BigDecimal tenDaysHighestPrice = baseMapper.selectTenDaysHighestPrice(stockCode, recordDate);

        if (tenDaysHighestPrice == null) {
            // 找不到十日内数据，返回0
            return BigDecimal.ZERO;
        }

        // 计算最高涨幅：(十日之内最高价 - 当天收盘价) / 当天收盘价 * 100
        return tenDaysHighestPrice.subtract(dayClosePrice)
            .divide(dayClosePrice, 4, RoundingMode.HALF_UP)
            .multiply(new BigDecimal("100"))
            .setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapper<StockPoolHistory> buildQueryWrapper(StockPoolHistoryBo bo) {
        LambdaQueryWrapper<StockPoolHistory> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtil.isNotNull(bo.getId()), StockPoolHistory::getId, bo.getId());
        lqw.like(StringUtils.isNotBlank(bo.getStockCode()), StockPoolHistory::getStockCode, bo.getStockCode());
        lqw.like(StringUtils.isNotBlank(bo.getStockName()), StockPoolHistory::getStockName, bo.getStockName());
        lqw.eq(ObjectUtil.isNotNull(bo.getRecordDate()), StockPoolHistory::getRecordDate, bo.getRecordDate());
        lqw.ge(ObjectUtil.isNotNull(bo.getStartDate()), StockPoolHistory::getRecordDate, bo.getStartDate());
        lqw.le(ObjectUtil.isNotNull(bo.getEndDate()), StockPoolHistory::getRecordDate, bo.getEndDate());
        // 先按日期降序，同一天内按ID升序（保持与Excel导入顺序一致）
        lqw.orderByDesc(StockPoolHistory::getRecordDate);
        lqw.orderByAsc(StockPoolHistory::getId);
        return lqw;
    }
}
