package quant.rich.emoney.service.postgre;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;

import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.annotation.ResponseDecodeExtension;
import quant.rich.emoney.config.PostgreMybatisConfig;
import quant.rich.emoney.entity.postgre.StockStrategy;
import quant.rich.emoney.mapper.postgre.StockStrategyMapper;
import quant.rich.emoney.util.DateUtils;

@DS("postgre")
@Service
@Slf4j
public class StockStrategyService extends PostgreServiceImpl<StockStrategyMapper, StockStrategy> {
    
    /**
     * 从请求响应的 JsonNode 转换出个股日策略标记信息列表
     * @param jsonNode
     * @return
     */
    public List<StockStrategy> parseJsonToList(JsonNode jsonNode) {
        
        if (jsonNode == null) {
            log.warn("试图获取 StockStrategy list, 但提供的响应 json 为空");
            return List.of();
        }
        
        JsonNode goodsIdNode = jsonNode.at("/data/input/goodsId");
        if (goodsIdNode.isMissingNode() || !goodsIdNode.isInt()) {
            log.warn("试图获取 StockStrategy list, 但 goodsId node 缺失或不为 integer");
            return List.of();
        }
        
        Integer goodsId = goodsIdNode.asInt();
        log.debug("StockStrategy json with goodsId: {}", goodsId);
        
        JsonNode output = jsonNode.at("/data/output");
        if (output.getNodeType() != JsonNodeType.ARRAY) {
            log.warn("试图获取 StockStrategy list, 但提供的响应 json.data.output 为 null 或不为 ARRAY");
            return List.of();
        }
        
        List<StockStrategy> stockStrategies = new ArrayList<>();
        String[] types = new String[] {"band", "tech", "val"}; // 波段/技术/基本面(价值)
        for (JsonNode node : output) {
            JsonNode dateNode = node.get("date");
            if (dateNode == null) {
                log.warn("试图获取 StockStrategy node, 但缺失日期 date 节点");
                continue;
            }
            LocalDateTime date = DateUtils.parse(String.valueOf(dateNode.asInt()), "yyyyMMdd").atStartOfDay();
            for (String type : types) {
                JsonNode strategies = node.get(type);
                if (strategies != null && strategies.getNodeType() == JsonNodeType.ARRAY) {
                    for (JsonNode simpleStrategy : strategies) {
                        StockStrategy stockStrategy = new StockStrategy();
                        stockStrategy.setGoodsId(goodsId);
                        stockStrategy.setDate(date);
                        stockStrategy.setStrategyName(simpleStrategy.get("strategyName").asText());
                        stockStrategy.setStrategyId(simpleStrategy.get("strategyId").asInt());
                        stockStrategy.setPoolName(simpleStrategy.get("poolName").asText());
                        stockStrategy.setPoolId(simpleStrategy.get("poolId").asInt());
                        stockStrategy.setType(type);
                        stockStrategies.add(stockStrategy);
                    }
                }
            }
        }
        log.debug("共载入 {} 条 StockStrategy 数据", stockStrategies.size());
        return stockStrategies;
    }
    
    /**
     * 从 jsonNode 节点直接更新到数据库内
     * @param jsonNode
     * @return
     */
    @ResponseDecodeExtension(protocolId="9400")
    @Async
    public Future<Boolean> updateByQueryResponseAsync(JsonNode jsonNode) {
        List<StockStrategy> stockStrategies = parseJsonToList(jsonNode);
        return CompletableFuture.completedFuture(saveOrUpdateBatch(stockStrategies));
    }
    
    @Override
    @Transactional(transactionManager = PostgreMybatisConfig.POSTGRE_TRANSACTION_MANAGER, rollbackFor = Exception.class)
    public boolean saveOrUpdateBatch(Collection<StockStrategy> entityList, int batchSize) {
        return SqlHelper.retBool(baseMapper.insertOrUpdateBatch(entityList, batchSize));
    }
    
}
