package link.at17.mid.tushare.data.service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Function;

import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;

import link.at17.mid.tushare.annotation.UpdateMethod;
import link.at17.mid.tushare.dao.StockLimitDao;
import link.at17.mid.tushare.data.crawler.QueryWay;
import link.at17.mid.tushare.data.crawler.tushare.TushareCrawler;
import link.at17.mid.tushare.data.crawler.tushare.TushareCrawlerResult;
import link.at17.mid.tushare.data.crawler.tushare.TushareRequestBody;
import link.at17.mid.tushare.data.models.StockLimit;
import link.at17.mid.tushare.data.models.interfaces.ITsStockInfo;
import link.at17.mid.tushare.data.models.interfaces.ITsTradeDate;
import link.at17.mid.tushare.data.validator.AllowedEnum;
import link.at17.mid.tushare.service.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class StockLimitService extends BaseServiceImpl<StockLimitDao, StockLimit> implements ITsTradeDate {

    @Autowired
    RedissonClient redis;

    @Autowired
    TushareCrawler tushareCrawler;

    @Autowired
    StockInfoService stockInfoService;


    /**
     * <b><a href="https://waditu.com/document/2?doc_id=298">Tushare 涨跌停列表</a></b><br>
     * <ul>
     * <li>接口：limit_list_d<br>
     * <li>描述：获取沪深A股每日涨跌停、炸板数据情况，数据从2020年开始<br>
     * <li>限量：单次最大可以获取500条数据，可通过日期或者股票循环提取<br>
     * <li>积分：120积分可查看数据，5000积分每分钟可以请求200次，8000积分以上每分钟500次，具体请参阅积分获取办法<br>
     * </ul>
     */
    @UpdateMethod(name="涨跌停数据", order=5)
    public boolean updateData(
            @AllowedEnum({"ByDateUpdate", "ByStockCrossCheck", "ByDateAll"})
            QueryWay queryWay) {

        TushareRequestBody baseRequest = new TushareRequestBody("limit_list_d");
        Function<List<JSONObject>, Boolean> function = (t) -> {
            insertOrUpdateList(t);
            return true;
        };
        List<Future<TushareCrawlerResult>> executeResult;
        if (queryWay.compareTo(QueryWay.ByStock) >= 0) {
            executeResult = tushareCrawler.rollingQueryByStock(baseRequest, stockInfoService.list(), this,
                    function, 500L, queryWay, null);
        } else {
            executeResult = tushareCrawler.rollingQueryByDate(baseRequest, this, function, queryWay,
                    LocalDateTime.of(2019, 11, 28, 0, 0, 0));
        }
        log.info("涨跌停数据更新完成");
        for (Future<TushareCrawlerResult> f : executeResult) {
            try {
                TushareCrawlerResult result = f.get();
                JSONObject request = f.get().getRequest();
                if (result.isFatal()) {
                    log.error("涨跌停数据未获取，发生致命错误，将不会重试：{}", request.toJSONString());
                } else if (!result.isSuccess()) {
                    log.info("涨跌停数据未获取：{}", request.toJSONString());
                }
            } catch (InterruptedException | ExecutionException e) {
                log.error("检查涨跌停数据执行结果时发生错误", e);
            }
        }
        if (baseRequest.hasFingerprint()) {
            redis.getBucket(baseRequest.getFingerprint()).delete();
        }
        return true;
    }

    /**
     * 插入从 Tushare 抓取的内容
     * 
     * @param list
     * @return
     */
    public boolean insertOrUpdateList(List<JSONObject> list) {
        return SqlHelper.retBool(baseMapper.insertOrUpdateList(list));
    }

    @Override
    public LocalDateTime getLatestTradeDate(ITsStockInfo stockInfo) {
        return baseMapper.getLatestTradeDate(stockInfo);
    }

    @Override
    public List<LocalDateTime> getAllTradeDates(ITsStockInfo stockInfo) {
        return baseMapper.getAllTradeDates(stockInfo);
    }

    @Override
    public List<LocalDateTime> getAllMissingDates(ITsStockInfo stockInfo) {
        return baseMapper.getAllMissingDates(stockInfo);
    }

}
