package com.yingpai.stock.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
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.StockQuoteData;
import com.yingpai.stock.domain.bo.StockPoolBo;
import com.yingpai.stock.domain.vo.StockPoolVo;
import com.yingpai.stock.mapper.StockPoolHistoryMapper;
import com.yingpai.stock.mapper.StockPoolMapper;
import com.yingpai.stock.service.IStockPoolService;
import com.yingpai.stock.service.IStockQuoteService;
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 java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 股票池服务实现类
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class StockPoolServiceImpl implements IStockPoolService {

    private final StockPoolMapper baseMapper;
    private final IStockQuoteService stockQuoteService;
    private final StockPoolHistoryMapper stockPoolHistoryMapper;

    @Override
    public TableDataInfo<StockPoolVo> queryPageList(StockPoolBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<StockPool> lqw = buildQueryWrapper(bo);
        Page<StockPoolVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        // 填充实时数据
        fillRealTimeData(result.getRecords());

        return TableDataInfo.build(result);
    }

    @Override
    public List<StockPoolVo> queryList(StockPoolBo bo) {
        LambdaQueryWrapper<StockPool> lqw = buildQueryWrapper(bo);
        List<StockPoolVo> list = baseMapper.selectVoList(lqw);

        // 填充实时数据
        fillRealTimeData(list);

        return list;
    }

    @Override
    public StockPoolVo queryById(Long id) {
        StockPoolVo vo = baseMapper.selectVoById(id);
        if (vo != null) {
            fillRealTimeData(List.of(vo));
        }
        return vo;
    }

    @Override
    public Boolean insertByBo(StockPoolBo bo) {
        LocalDate addDate = bo.getAddDate() != null ? bo.getAddDate() : LocalDate.now();
        LocalDate today = LocalDate.now();

        // 根据日期确定状态：当天=2（当前有效），历史=1（历史有效）
        Integer targetStatus = addDate.equals(today) ? 2 : 1;

        log.info("[添加股票到池] stockCode={}, poolType={}, addDate={}, status={}",
            bo.getStockCode(), bo.getPoolType(), addDate, targetStatus);

        // 1. 如果要加入为当前有效（status=2），检查是否已存在其他当前有效的记录
        if (targetStatus == 2) {
            LambdaQueryWrapper<StockPool> activeWrapper = Wrappers.lambdaQuery();
            activeWrapper.eq(StockPool::getStockCode, bo.getStockCode())
                .eq(StockPool::getPoolType, bo.getPoolType())
                .eq(StockPool::getStatus, 2);
            if (baseMapper.selectCount(activeWrapper) > 0) {
                log.warn("[添加股票到池] 股票已存在: {}", bo.getStockCode());
                throw new RuntimeException("该股票已在池中");
            }
        }

        // 2. 检查指定日期是否已有记录（任何状态），如果有则修改状态
        LambdaQueryWrapper<StockPool> dateWrapper = Wrappers.lambdaQuery();
        dateWrapper.eq(StockPool::getStockCode, bo.getStockCode())
            .eq(StockPool::getPoolType, bo.getPoolType())
            .eq(StockPool::getAddDate, addDate);
        StockPool existing = baseMapper.selectOne(dateWrapper);

        if (existing != null) {
            // 指定日期已有记录，修改状态
            existing.setStatus(targetStatus);
            existing.setAdminId(LoginHelper.getUserId());
            existing.setUpdateTime(LocalDateTime.now());

            // 从历史信息中查询收盘价
            BigDecimal closePrice = fetchClosePriceFromHistory(bo.getStockCode(), addDate);
            existing.setClosePrice(closePrice);

            // 如果不是今天，尝试计算隔日数据
            if (!addDate.equals(today)) {
                calculateNextDayData(existing, addDate);
            }

            return baseMapper.updateById(existing) > 0;
        }

        // 3. 插入新记录
        StockPool pool = new StockPool();
        pool.setStockCode(bo.getStockCode());
        pool.setStockName(bo.getStockName());
        pool.setPoolType(bo.getPoolType());
        pool.setAddDate(addDate);
        pool.setStatus(targetStatus);  // 使用计算出的状态
        pool.setAdminId(LoginHelper.getUserId());
        pool.setCreateTime(LocalDateTime.now());
        pool.setUpdateTime(LocalDateTime.now());

        // 从历史信息中查询收盘价
        BigDecimal closePrice = fetchClosePriceFromHistory(bo.getStockCode(), addDate);
        pool.setClosePrice(closePrice);

        // 如果是今天，获取实时价格作为入池价
        if (addDate.equals(today)) {
            BigDecimal currentPrice = fetchCurrentPrice(bo.getStockCode());
            pool.setAddPrice(currentPrice != null ? currentPrice : BigDecimal.ZERO);
        } else {
            // 如果是历史日期，使用收盘价作为入池价
            pool.setAddPrice(closePrice != null ? closePrice : BigDecimal.ZERO);
            // 计算隔日数据
            calculateNextDayData(pool, addDate);
        }

        return baseMapper.insert(pool) > 0;
    }

    /**
     * 计算隔日最高价和隔日涨幅
     */
    private void calculateNextDayData(StockPool pool, LocalDate addDate) {
        // 查询下一个交易日的历史数据（向后查找最多7天）
        for (int i = 1; i <= 7; i++) {
            LocalDate nextDate = addDate.plusDays(i);
            LambdaQueryWrapper<StockPoolHistory> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(StockPoolHistory::getStockCode, pool.getStockCode())
                   .eq(StockPoolHistory::getRecordDate, nextDate)
                   .last("LIMIT 1");
            StockPoolHistory nextDayHistory = stockPoolHistoryMapper.selectOne(wrapper);

            if (nextDayHistory != null) {
                // 找到下一个交易日的数据
                BigDecimal nextDayHigh = nextDayHistory.getDayHighestPrice();
                if (nextDayHigh == null) {
                    nextDayHigh = nextDayHistory.getClosePrice();
                }

                if (nextDayHigh != null && pool.getClosePrice() != null &&
                    pool.getClosePrice().compareTo(BigDecimal.ZERO) > 0) {
                    // 计算隔日涨幅
                    BigDecimal nextDayGain = nextDayHigh.subtract(pool.getClosePrice())
                        .divide(pool.getClosePrice(), 4, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100"))
                        .setScale(2, RoundingMode.HALF_UP);

                    pool.setNextDayHigh(nextDayHigh);
                    pool.setNextDayGain(nextDayGain);

                    log.info("[计算隔日数据] 股票={}, 加入日期={}, 下一交易日={}, 隔日最高={}, 隔日涨幅={}%",
                        pool.getStockCode(), addDate, nextDate, nextDayHigh, nextDayGain);
                }
                break;
            }
        }
    }

    @Override
    public Boolean updateByBo(StockPoolBo bo) {
        StockPool entity = BeanUtil.toBean(bo, StockPool.class);
        entity.setUpdateTime(LocalDateTime.now());
        return baseMapper.updateById(entity) > 0;
    }

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

    @Override
    public Boolean softDeleteByIds(Collection<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        // 批量更新状态为0（已移除）
        return baseMapper.update(null, Wrappers.<StockPool>lambdaUpdate()
            .set(StockPool::getStatus, 0)
            .set(StockPool::getUpdateTime, LocalDateTime.now())
            .in(StockPool::getId, ids)) > 0;
    }

    @Override
    public Boolean removeByCodeAndType(String stockCode, Integer poolType) {
        LambdaQueryWrapper<StockPool> lqw = Wrappers.lambdaQuery();
        lqw.eq(StockPool::getStockCode, stockCode)
            .eq(StockPool::getPoolType, poolType)
            .eq(StockPool::getStatus, 2);
        StockPool pool = baseMapper.selectOne(lqw);
        if (pool != null) {
            pool.setStatus(0);
            return baseMapper.updateById(pool) > 0;
        }
        return false;
    }

    @Override
    public Boolean updateStatus(Long id, Integer status) {
        StockPool pool = baseMapper.selectById(id);
        if (pool == null) {
            throw new RuntimeException("记录不存在");
        }

        // 如果要修改为当前有效（status=2），需要检查是否已有其他当前有效的记录
        if (status == 2) {
            LambdaQueryWrapper<StockPool> activeWrapper = Wrappers.lambdaQuery();
            activeWrapper.eq(StockPool::getStockCode, pool.getStockCode())
                .eq(StockPool::getPoolType, pool.getPoolType())
                .eq(StockPool::getStatus, 2)
                .ne(StockPool::getId, id);  // 排除当前记录

            if (baseMapper.selectCount(activeWrapper) > 0) {
                throw new RuntimeException("该股票已在池中，不能同时存在多条当前有效记录");
            }
        }

        pool.setStatus(status);
        pool.setUpdateTime(LocalDateTime.now());
        return baseMapper.updateById(pool) > 0;
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapper<StockPool> buildQueryWrapper(StockPoolBo bo) {
        LambdaQueryWrapper<StockPool> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtil.isNotNull(bo.getId()), StockPool::getId, bo.getId());
        lqw.like(StringUtils.isNotBlank(bo.getStockCode()), StockPool::getStockCode, bo.getStockCode());
        lqw.like(StringUtils.isNotBlank(bo.getStockName()), StockPool::getStockName, bo.getStockName());
        lqw.eq(ObjectUtil.isNotNull(bo.getPoolType()), StockPool::getPoolType, bo.getPoolType());
        // 如果指定了status则按指定值查询，否则默认查询status为1和2的记录
        if (ObjectUtil.isNotNull(bo.getStatus())) {
            lqw.eq(StockPool::getStatus, bo.getStatus());
        } else {
            lqw.in(StockPool::getStatus, 1, 2);
        }
        lqw.ge(ObjectUtil.isNotNull(bo.getStartDate()), StockPool::getAddDate, bo.getStartDate());
        lqw.le(ObjectUtil.isNotNull(bo.getEndDate()), StockPool::getAddDate, bo.getEndDate());
        lqw.orderByDesc(StockPool::getAddDate);
        return lqw;
    }

    /**
     * 填充实时数据（使用多线程服务）
     */
    private void fillRealTimeData(List<StockPoolVo> list) {
        if (list == null || list.isEmpty()) {
            return;
        }

        List<String> codes = list.stream()
            .map(StockPoolVo::getStockCode)
            .collect(Collectors.toList());

        // 使用多线程行情服务
        Map<String, StockQuoteData> quoteMap = stockQuoteService.batchFetchQuotesParallel(codes);

        for (StockPoolVo vo : list) {
            // 设置池类型名称
            vo.setPoolTypeName(vo.getPoolType() == 1 ? "超短池" : "强势池");

            StockQuoteData quote = quoteMap.get(vo.getStockCode());
            if (quote != null) {
                vo.setCurrentPrice(quote.getCurrentPrice());
                vo.setYesterdayClose(quote.getYesterdayClose());
                vo.setChangeAmount(quote.getChangeAmount());
                vo.setChangePercent(quote.getChangePercent());
                vo.setTurnoverRate(quote.getTurnoverRate());
                vo.setTradeAmount(quote.getTradeAmount());

                // 计算入池收益率
                if (vo.getAddPrice() != null && vo.getCurrentPrice() != null
                    && vo.getAddPrice().compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal profit = vo.getCurrentPrice().subtract(vo.getAddPrice())
                        .divide(vo.getAddPrice(), 4, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100"));
                    vo.setProfitPercent(profit.setScale(2, RoundingMode.HALF_UP));
                }
            }
        }
    }

    /**
     * 获取单个股票当前价格
     */
    private BigDecimal fetchCurrentPrice(String code) {
        Map<String, StockQuoteData> quotes = stockQuoteService.batchFetchQuotesParallel(List.of(code));
        StockQuoteData quote = quotes.get(code);
        return quote != null ? quote.getCurrentPrice() : null;
    }

    /**
     * 从历史信息中查询收盘价
     */
    private BigDecimal fetchClosePriceFromHistory(String stockCode, LocalDate recordDate) {
        LambdaQueryWrapper<StockPoolHistory> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StockPoolHistory::getStockCode, stockCode)
               .eq(StockPoolHistory::getRecordDate, recordDate)
               .last("LIMIT 1");
        StockPoolHistory history = stockPoolHistoryMapper.selectOne(wrapper);
        return history != null ? history.getClosePrice() : null;
    }

    @Override
    public String completeHistoryData(LocalDate importDate) throws Exception {
        log.info("[补全历史数据] 开始补全，导入日期: {}", importDate);

        // 查找离导入日期最近的一个交易日（从stock_pool_history表确定，向前查找最多30天）
        LocalDate previousDate = null;
        List<StockPool> previousDayData = new java.util.ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            LocalDate checkDate = importDate.minusDays(i);
            LambdaQueryWrapper<StockPoolHistory> checkWrapper = Wrappers.lambdaQuery();
            checkWrapper.eq(StockPoolHistory::getRecordDate, checkDate).last("LIMIT 1");
            if (stockPoolHistoryMapper.selectCount(checkWrapper) > 0) {
                previousDate = checkDate;
                previousDayData = baseMapper.selectByDateAndType(checkDate, 1);
                log.info("[补全历史数据] 找到最近的交易日: {}", previousDate);
                break;
            }
        }

        if (previousDate == null) {
            log.warn("[补全历史数据] 未找到最近7天内的交易数据");
        }

        // 查询当天的历史数据（从stock_pool_history表）
        LambdaQueryWrapper<StockPoolHistory> historyWrapper = Wrappers.lambdaQuery();
        historyWrapper.eq(StockPoolHistory::getRecordDate, importDate);
        List<StockPoolHistory> historyData = stockPoolHistoryMapper.selectList(historyWrapper);

        if (historyData == null || historyData.isEmpty()) {
            String message = "当天(" + importDate + ")没有历史数据(stock_pool_history)，无法补全";
            log.warn("[补全历史数据] {}", message);
            return message;
        }

        // 将历史数据转换为Map，key为股票代码
        Map<String, StockPoolHistory> historyMap = historyData.stream()
            .collect(Collectors.toMap(StockPoolHistory::getStockCode, h -> h));

        // 查询当天的超短池数据（用于补全当天收盘价；即使为空也不应阻断前一天隔日补全）
        List<StockPool> currentDayData = baseMapper.selectByDateAndType(importDate, 1);
        if (currentDayData.isEmpty()) {
            log.warn("[补全历史数据] 当天({})没有超短池数据(stock_pool)，将跳过当天收盘价补全，但仍会尝试补全前一天隔日数据", importDate);
        }

        int currentDayUpdated = 0;
        int previousDayUpdated = 0;

        // 1. 补全当天的收盘价（从stock_pool_history表获取）
        for (StockPool currentPool : currentDayData) {
            StockPoolHistory history = historyMap.get(currentPool.getStockCode());
            if (history != null && history.getClosePrice() != null) {
                currentPool.setClosePrice(history.getClosePrice());
                currentPool.setUpdateTime(LocalDateTime.now());
                baseMapper.updateById(currentPool);
                currentDayUpdated++;
                log.debug("[补全历史数据] 股票 {} 当天收盘价补全: {}",
                    currentPool.getStockCode(), history.getClosePrice());
            }
        }

        // 2. 补全前一天的隔日最高价和隔日涨幅
        if (!previousDayData.isEmpty()) {
            for (StockPool previousPool : previousDayData) {
                String stockCode = previousPool.getStockCode();
                StockPoolHistory currentHistory = historyMap.get(stockCode);

                if (currentHistory == null) {
                    log.debug("[补全历史数据] 股票 {} 在当天历史数据中没有记录，跳过前一天补全", stockCode);
                    continue;
                }

                // 补全前一天的隔日最高价（使用当天历史数据的最高价）
                BigDecimal nextDayHigh = currentHistory.getDayHighestPrice();
                if (nextDayHigh == null) {
                    // 如果没有最高价，使用收盘价
                    nextDayHigh = currentHistory.getClosePrice();
                }

                if (nextDayHigh == null) {
                    log.debug("[补全历史数据] 股票 {} 当天历史数据中没有最高价和收盘价，跳过", stockCode);
                    continue;
                }

                // 计算隔日涨幅：(当天最高价 - 前一天收盘价) / 前一天收盘价 * 100
                BigDecimal nextDayGain = BigDecimal.ZERO;
                BigDecimal previousClosePrice = previousPool.getClosePrice();

                if (previousClosePrice != null && previousClosePrice.compareTo(BigDecimal.ZERO) > 0) {
                    nextDayGain = nextDayHigh.subtract(previousClosePrice)
                        .divide(previousClosePrice, 4, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100"))
                        .setScale(2, RoundingMode.HALF_UP);
                }

                // 更新前一天的数据
                previousPool.setNextDayHigh(nextDayHigh);
                previousPool.setNextDayGain(nextDayGain);
                previousPool.setUpdateTime(LocalDateTime.now());

                baseMapper.updateById(previousPool);
                previousDayUpdated++;

                log.debug("[补全历史数据] 股票 {} 前一天补全成功，隔日最高: {}, 隔日涨幅: {}%",
                    stockCode, nextDayHigh, nextDayGain);
            }
        }

        String message = String.format("补全完成！当天收盘价补全 %d 条，前一天隔日数据补全 %d 条",
            currentDayUpdated, previousDayUpdated);
        log.info("[补全历史数据] {}", message);
        return message;
    }

    @Override
    public String updateStrongPoolTenDayGain(LocalDate importDate) {
        log.info("[强势池10天涨幅] 开始更新，导入日期: {}", importDate);

        // 查询10天内入池的强势池股票（poolType=2）
        LocalDate tenDaysAgo = importDate.minusDays(10);
        LambdaQueryWrapper<StockPool> lqw = Wrappers.lambdaQuery();
        lqw.eq(StockPool::getPoolType, 2)
           .ge(StockPool::getAddDate, tenDaysAgo)
           .lt(StockPool::getAddDate, importDate)
           .in(StockPool::getStatus, 1, 2);

        List<StockPool> poolsToUpdate = baseMapper.selectList(lqw);

        if (poolsToUpdate.isEmpty()) {
            String message = "没有需要更新的强势池股票（10天内入池）";
            log.info("[强势池10天涨幅] {}", message);
            return message;
        }

        log.info("[强势池10天涨幅] 找到 {} 只需要更新的股票", poolsToUpdate.size());

        int updatedCount = 0;
        int skippedCount = 0;

        for (StockPool pool : poolsToUpdate) {
            try {
                String stockCode = pool.getStockCode();
                LocalDate addDate = pool.getAddDate();
                BigDecimal closePrice = pool.getClosePrice();

                if (closePrice == null || closePrice.compareTo(BigDecimal.ZERO) == 0) {
                    log.warn("[强势池10天涨幅] 股票 {} 收盘价为空或为0，跳过", stockCode);
                    skippedCount++;
                    continue;
                }

                // 查询从入池日到当前导入日的最高价
                BigDecimal maxHighPrice = stockPoolHistoryMapper.selectMaxHighPriceInRange(
                    stockCode, addDate, importDate);

                if (maxHighPrice == null) {
                    log.warn("[强势池10天涨幅] 股票 {} 在 [{}, {}] 范围内没有历史数据，跳过",
                        stockCode, addDate, importDate);
                    skippedCount++;
                    continue;
                }

                // 计算涨幅：(最高价 - 入池收盘价) / 入池收盘价 * 100
                BigDecimal tenDayGain = maxHighPrice.subtract(closePrice)
                    .divide(closePrice, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))
                    .setScale(2, RoundingMode.HALF_UP);

                pool.setNextDayGain(tenDayGain);
                pool.setNextDayHigh(maxHighPrice);
                pool.setUpdateTime(LocalDateTime.now());
                baseMapper.updateById(pool);

                updatedCount++;

                log.debug("[强势池10天涨幅] 股票 {} 更新成功，入池日: {}, 跟踪天数: {}, 最高价: {}, 涨幅: {}%",
                    stockCode, addDate, importDate.toEpochDay() - addDate.toEpochDay() + 1,
                    maxHighPrice, tenDayGain);

            } catch (Exception e) {
                log.error("[强势池10天涨幅] 股票 {} 更新失败: {}",
                    pool.getStockCode(), e.getMessage(), e);
                skippedCount++;
            }
        }

        String message = String.format("更新完成！成功 %d 条，跳过 %d 条", updatedCount, skippedCount);
        log.info("[强势池10天涨幅] {}", message);
        return message;
    }
}
