package com.yingpai.stock.service.impl;

import cn.hutool.http.HttpUtil;
import com.yingpai.stock.domain.StockQuoteData;
import com.yingpai.stock.service.IStockQuoteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 股票行情服务实现类（多线程优化）
 */
@Slf4j
@Service
public class StockQuoteServiceImpl implements IStockQuoteService {

    private final ThreadPoolTaskExecutor executor;

    private static final int BATCH_SIZE = 50;
    // 腾讯股票行情接口
    private static final String BATCH_QUOTE_URL = "http://qt.gtimg.cn/q=%s";

    public StockQuoteServiceImpl(@Qualifier("stockQuoteExecutor") ThreadPoolTaskExecutor executor) {
        this.executor = executor;
    }

    @Override
    public Map<String, StockQuoteData> batchFetchQuotesParallel(List<String> codes) {
        if (codes == null || codes.isEmpty()) {
            return Collections.emptyMap();
        }

        long startTime = System.currentTimeMillis();
        log.info("[行情获取] 开始多线程获取，股票数量: {}", codes.size());

        // 1. 数据分片
        List<List<String>> batches = partition(codes, BATCH_SIZE);
        log.info("[行情获取] 分为 {} 个批次", batches.size());

        // 2. 并行请求
        List<CompletableFuture<Map<String, StockQuoteData>>> futures = new ArrayList<>();
        for (List<String> batch : batches) {
            CompletableFuture<Map<String, StockQuoteData>> future = CompletableFuture.supplyAsync(
                () -> fetchBatchQuotes(batch),
                executor
            );
            futures.add(future);
        }

        // 3. 等待所有任务完成并合并结果
        Map<String, StockQuoteData> result = new ConcurrentHashMap<>();

        try {
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            for (CompletableFuture<Map<String, StockQuoteData>> future : futures) {
                try {
                    result.putAll(future.get());
                } catch (Exception e) {
                    log.warn("[行情获取] 部分批次失败: {}", e.getMessage());
                }
            }
        } catch (Exception e) {
            log.error("[行情获取] 多线程执行异常: {}", e.getMessage());
        }

        long costTime = System.currentTimeMillis() - startTime;
        log.info("[行情获取] 完成，获取到 {} 条数据，耗时 {}ms", result.size(), costTime);

        return result;
    }

    /**
     * 获取单批次行情（最多50只股票）
     */
    private Map<String, StockQuoteData> fetchBatchQuotes(List<String> batch) {
        Map<String, StockQuoteData> result = new HashMap<>();
        try {
            // 构建腾讯API格式的股票代码列表：sh600519,sz000001
            String codes = batch.stream()
                .map(this::getTencentCode)
                .filter(Objects::nonNull)
                .collect(Collectors.joining(","));

            if (codes.isEmpty()) return result;

            String body = HttpUtil.createGet(String.format(BATCH_QUOTE_URL, codes))
                .timeout(10000)
                .execute()
                .body();

            if (body != null && !body.isEmpty()) {
                String[] lines = body.split(";");

                for (String line : lines) {
                    line = line.trim();
                    if (line.isEmpty()) continue;

                    // 解析腾讯API返回格式: v_sh600519="1~贵州茅台~600519~2076.91~..."
                    int startIndex = line.indexOf("=\"");
                    int endIndex = line.lastIndexOf("\"");

                    if (startIndex != -1 && endIndex != -1 && endIndex > startIndex) {
                        String data = line.substring(startIndex + 2, endIndex);
                        String[] fields = data.split("~");

                        if (fields.length > 38) {
                            String code = fields[2];  // 股票代码

                            StockQuoteData quote = StockQuoteData.builder()
                                .stockCode(code)
                                .currentPrice(parseBigDecimal(fields[3]))      // 当前价格 [3]
                                .yesterdayClose(parseBigDecimal(fields[4]))    // 昨收 [4]
                                .changeAmount(parseBigDecimal(fields[31]))     // 涨跌额 [31]
                                .changePercent(parseBigDecimal(fields[32]))    // 涨跌幅 [32]
                                .turnoverRate(parseBigDecimal(fields[38]))     // 换手率 [38]
                                .build();

                            // 成交额（万元）转换为亿
                            BigDecimal amount = parseBigDecimal(fields[37]);
                            if (amount != null) {
                                quote.setTradeAmount(amount.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP));
                            }

                            result.put(code, quote);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("[批量行情] 获取失败: {}", e.getMessage());
        }
        return result;
    }

    /**
     * 数据分片
     */
    private <T> List<List<T>> partition(List<T> list, int size) {
        List<List<T>> partitions = new ArrayList<>();
        for (int i = 0; i < list.size(); i += size) {
            partitions.add(new ArrayList<>(list.subList(i, Math.min(i + size, list.size()))));
        }
        return partitions;
    }

    /**
     * 获取腾讯API格式的股票代码（sh600519, sz000001）
     */
    private String getTencentCode(String code) {
        if (code == null || code.length() != 6) return null;
        if (code.startsWith("6")) return "sh" + code;
        if (code.startsWith("0") || code.startsWith("3")) return "sz" + code;
        return null;
    }

    /**
     * 解析BigDecimal（从字符串）
     */
    private BigDecimal parseBigDecimal(String value) {
        if (value == null || value.isEmpty() || "-".equals(value)) return null;
        try {
            return new BigDecimal(value);
        } catch (Exception e) {
            return null;
        }
    }
}
