package com.market.utils;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.market.entity.Kline;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * K 线工具类：常量 + Caffeine 内存缓存
 */
@Component
public class KlineUtils {

    // ------------------------------------------------------------------ 常量

    /** 支持的 K 线周期（与币安 stream 中的 interval 对应） */
    public static final String[] PERIODS = {
            "1m", "5m", "15m", "30m", "1h", "4h", "1d", "1mon", "1w"
    };

    /** 将内部 period 转换为币安 interval 参数（1mon → 1M，其余不变） */
    public static String toExchangeInterval(String period) {
        return "1mon".equals(period) ? "1M" : period;
    }

    /** 分表名前缀：futures_kline_{symbol} */
    public static final String TABLE_PREFIX = "futures_kline_";

    /** 缓存 key 分隔符 */
    public static final String CACHE_KEY_SEP = "_";

    /** WebSocket 主题前缀 */
    public static final String TOPIC_PREFIX = "market.";

    /** kline 主题类型 */
    public static final String TOPIC_KLINE  = "kline";
    public static final String TOPIC_TRADE  = "trade";
    public static final String TOPIC_TICKET = "ticket";
    public static final String TOPIC_MARK   = "mark";
    public static final String TOPIC_DEPTH  = "depth";

    /** aggTrade 限流间隔：500 ms */
    public static final long AGG_TRADE_THROTTLE_MS = 500L;

    /** kline / ticker / mark 限流间隔：1000 ms */
    public static final long THROTTLE_1S_MS = 1_000L;

    /** 资金费率写 Redis 间隔：1 分钟 */
    public static final long FUNDING_RATE_INTERVAL_MS = 60_000L;

    /** 币安 stream 后缀 */
    public static final String STREAM_AGG_TRADE    = "@aggTrade";
    public static final String STREAM_MARK_PRICE   = "@markPrice";
    public static final String STREAM_MINI_TICKER  = "@miniTicker";
    public static final String STREAM_KLINE_PREFIX = "@kline_";


    /**
     * 最新 K 线缓存，key = {symbol}_{interval}
     * 不设过期，symbol 退市时条目自然停止更新
     */
    public final Cache<String, Kline> KLINE_CACHE = Caffeine.newBuilder()
            .build();

    /**
     * 每个 key 最后一次写库的时间戳（ms）
     * 写库后 10 秒若无新数据自动驱逐（节省内存）
     */
    public final Cache<String, Long> LAST_FLUSH_TIME = Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.SECONDS)
            .build();

    /** aggTrade 最后推送时间，key=symbol，0.5s 限流 */
    public final Cache<String, Long> LAST_AGG_TRADE_TIME = Caffeine.newBuilder()
            .expireAfterWrite(2, TimeUnit.SECONDS)
            .build();

    /** kline 最后处理时间，key=symbol_interval，1s 限流 */
    public final Cache<String, Long> LAST_KLINE_TIME = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .build();

    /** 24hrMiniTicker 最后推送时间，key=symbol，1s 限流 */
    public final Cache<String, Long> LAST_TICKER_TIME = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .build();

    /** markPriceUpdate 最后推送时间，key=symbol，1s 限流 */
    public final Cache<String, Long> LAST_MARK_TIME = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .build();

    /** 资金费率最后写 Redis 时间，key=symbol，1 分钟限流 */
    public final Cache<String, Long> LAST_FUNDING_RATE_TIME = Caffeine.newBuilder()
            .expireAfterWrite(2, TimeUnit.MINUTES)
            .build();

    /** symbol（小写，无斜杠）→ contractId 映射，refreshAndConnect 时写入 */
    public final ConcurrentHashMap<String, Long> SYMBOL_ID_MAP = new ConcurrentHashMap<>();



    // ------------------------------------------------------------------ 工具方法

    /** 生成分表名，如 futures_kline_btcusdt */
    public static String tableName(String symbol) {
        return TABLE_PREFIX + symbol.toLowerCase();
    }

    /** 生成 kline 推送主题，如 market.btcusdt.kline.1m */
    public static String klineTopic(String symbol, String interval) {
        return TOPIC_PREFIX + symbol + "." + TOPIC_KLINE + "." + interval;
    }

    /** 生成 trade 推送主题，如 market.btcusdt.trade */
    public static String tradeTopic(String symbol) {
        return TOPIC_PREFIX + symbol + "." + TOPIC_TRADE;
    }

    /** 生成 ticket 推送主题，如 market.btcusdt.ticket */
    public static String ticketTopic(String symbol) {
        return TOPIC_PREFIX + symbol + "." + TOPIC_TICKET;
    }

    /** 生成标记价格推送主题，如 market.btcusdt.mark */
    public static String markTopic(String symbol) {
        return TOPIC_PREFIX + symbol + "." + TOPIC_MARK;
    }

    /** 生成盘口推送主题，如 market.btcusdt.depth */
    public static String depthTopic(String symbol) {
        return TOPIC_PREFIX + symbol + "." + TOPIC_DEPTH;
    }

    /** 生成 kline stream 名，如 btcusdt@kline_1m */
    public static String klineStream(String symbol, String interval) {
        return symbol + STREAM_KLINE_PREFIX + toExchangeInterval(interval);
    }
}
