package com.bizzan.bitrade.service;

import com.bizzan.bitrade.entity.FuturesKline;
import com.bizzan.bitrade.entity.KLine;
import com.bizzan.bitrade.entity.KLinePeriod;
import com.bizzan.bitrade.mapper.market.FuturesKlineMapper;
import com.bizzan.bitrade.service.Base.BaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@Service
public class ContractMarketService extends BaseService {

    @Autowired(required = false)
    private FuturesKlineMapper futuresKlineMapper;

    private Logger logger = LoggerFactory.getLogger(ContractMarketService.class);

    // "BTC/USDT" → "futures_kline_btcusdt"
    private String toTableName(String symbol) {
        return "futures_kline_" + symbol.replace("/", "").toLowerCase();
    }

    // FuturesKline (MySQL) → KLine (业务对象)
    private KLine toKLine(FuturesKline f) {
        KLine k = new KLine();
        k.setOpenPrice(f.getOpen());
        k.setClosePrice(f.getClose());
        k.setHighestPrice(f.getHigh());
        k.setLowestPrice(f.getLow());
        k.setVolume(f.getVolume());
        k.setTurnover(f.getTurnover());
        // begin_time 毫秒 → KLine.time 秒
        k.setTime(f.getBeginTime() / 1000);
        k.setPeriod(f.getPeriod());
        return k;
    }

    public List<KLine> findAllKLine(String symbol, String peroid) {
        return futuresKlineMapper.findAllKLine(toTableName(symbol), peroid)
                .stream().map(this::toKLine).collect(Collectors.toList());
    }

    public List<KLine> findAllKLine(String symbol, long fromTime, long toTime, String period) {
        return futuresKlineMapper.findKLineRange(toTableName(symbol), period, fromTime * 1000, toTime * 1000)
                .stream().map(this::toKLine).collect(Collectors.toList());
    }

    public KLine findKLineBefore(String symbol, String period, int offset) {
        List<FuturesKline> rows = futuresKlineMapper.findKLineBefore(toTableName(symbol), period, offset);
        return rows.isEmpty() ? null : toKLine(rows.get(rows.size() - 1));
    }

    /**
     * 获取K最近一条K线的时间
     *
     * @param symbol
     * @param period
     * @return
     */
    public long findMaxTimestamp(String symbol, String period) {
        Long maxMs = futuresKlineMapper.findMaxBeginTime(toTableName(symbol), period);
        return maxMs != null ? maxMs / 1000 : 0;
    }

    public KLine findLatest(String symbol, String period) {
        FuturesKline f = futuresKlineMapper.findLatest(toTableName(symbol), period);
        return f != null ? toKLine(f) : null;
    }

    public long findTimeByPrice(String symbol, BigDecimal price, int length, boolean findLast) {
        List<KLine> result = findLatestKLine(symbol, length);

        for (KLine kLine : result) {
            if (kLine.getHighestPrice().compareTo(price) >= 0 && kLine.getLowestPrice().compareTo(price) <= 0) {
                Random random = new Random();
                return (kLine.getTime() + random.nextInt(60)) * 1000;
            }
        }
        if (findLast)
            return result.get(result.size() - 1).getTime() * 1000;
        else {
            Random random = new Random();
            return (result.get(0).getTime() + 60 + random.nextInt(60)) * 1000;
        }
    }

    public Long[] findStartAndEndTimeByPrice(String symbol, BigDecimal startPrice, BigDecimal endPrice, int length) {
        Long[] startAndEndTime = new Long[2];

        List<KLine> result = findLatestKLine(symbol, length);

        boolean endFound = false;
        for (KLine kLine : result) {
            if (endFound) {
                if (kLine.getHighestPrice().compareTo(startPrice) >= 0 && kLine.getLowestPrice().compareTo(startPrice) <= 0) {
                    Random random = new Random();
                    startAndEndTime[0] = (kLine.getTime() + random.nextInt(60)) * 1000;
                    return startAndEndTime;
                }
            } else {
                if (kLine.getHighestPrice().compareTo(endPrice) >= 0 && kLine.getLowestPrice().compareTo(endPrice) <= 0) {
                    Random random = new Random();
                    startAndEndTime[1] = (kLine.getTime() + random.nextInt(60)) * 1000;
                    endFound = true;
                }
            }
        }

        return startAndEndTime;
    }

    public long findStartTimeByPrice(String symbol, BigDecimal endPrice, int length) {
        List<KLine> result = findLatestKLine(symbol, length);

        for (KLine kLine : result) {
            if (kLine.getHighestPrice().compareTo(endPrice) >= 0 && kLine.getLowestPrice().compareTo(endPrice) <= 0) {
                Random random = new Random();
                return (kLine.getTime() + random.nextInt(60)) * 1000;
            }
        }

        return 0;
    }

    private List<KLine> findLatestKLine(String symbol, int length) {
        return futuresKlineMapper.findLatestKLine(toTableName(symbol), KLinePeriod.M1.getCode(), length)
                .stream().map(this::toKLine).collect(Collectors.toList());
    }

}
