import { MainClient, USDMClient, type Kline as BinanceRestKline } from "binance";

import { logger } from "../../utils/logger";
import { exchange } from "../../config";
import { BaseRestClient } from "../base";
import type { Kline, MarketInfo, KlineInterval, PairType, FetchKlinesParams } from "../../types";

// ============================================================
// Binance REST K 线 → 本系统标准化 Kline 转换
// ============================================================

/**
 * Binance SDK Kline 元组格式（getKlines / getUIKlines 返回）：
 *   [0] openTime:         number           — 开盘时间（Unix ms）
 *   [1] open:             numberInString   — 开盘价
 *   [2] high:             numberInString   — 最高价
 *   [3] low:              numberInString   — 最低价
 *   [4] close:            numberInString   — 收盘价
 *   [5] volume:           numberInString   — 成交量（base 币种）
 *   [6] closeTime:        number           — 收盘时间（Unix ms）
 *   [7] quoteVolume:      numberInString   — 成交额（quote 币种）
 *   [8] tradeCount:       number           — 成交笔数
 *   [9] takerBuyBaseVol:  numberInString   — 主动买入成交量
 *   [10] takerBuyQuoteVol: numberInString  — 主动买入成交额
 *   [11] ignore:           numberInString  — 忽略字段
 *
 * numberInString = string | number，通过 String() 统一转换。
 *
 * 参考：node_modules/binance/lib/types/shared.d.ts:85-98
 */
function convertBinanceKline(
    raw: BinanceRestKline,
    symbol: string,
    interval: KlineInterval,
    type: PairType,
): Kline {
    const [
        openTime,
        open,
        high,
        low,
        close,
        volume,
        closeTime,
        quoteVolume,
        tradeCount,
        takerBuyBaseVol,
        takerBuyQuoteVol,
        // [11] ignore — 丢弃
    ] = raw;

    return {
        exchange: "binance",
        symbol,
        type,
        interval,
        openTime,
        closeTime,
        open: String(open),
        high: String(high),
        low: String(low),
        close: String(close),
        volume: String(volume),
        quoteVolume: String(quoteVolume),
        takerBuyBaseVol: String(takerBuyBaseVol),
        takerBuyQuoteVol: String(takerBuyQuoteVol),
        tradeCount: String(tradeCount),
        isClosed: true, // REST 返回的 K 线均为已闭合历史数据
    };
}

// ============================================================
// BinanceRestClient
// ============================================================

export class BinanceRestClient extends BaseRestClient {
    readonly exchange = "binance";

    private client: MainClient;

    constructor() {
        super();
        this.client = new MainClient(
            {
                api_key: exchange.binance.apiKey,
                api_secret: exchange.binance.apiSecret,
            },
            { timeout: 3000 },
        );
    }

    /**
     * 拉取 1m K 线并转换为本系统标准化 Kline。
     *
     * Binance 硬限制单次最多 1000 条，超限自动裁切。
     * 高周期 K 线通过 TimescaleDB 连续聚合视图生成。
     *
     * @param params - fetchKlines 统一参数对象
     */
    async fetchKlines(params: FetchKlinesParams): Promise<Kline[]> {
        const { symbol, startTime, limit, endTime, type } = params;
        const effectiveLimit = limit ?? this.config.defaultLimit;
        // Binance 硬限制：单次最多 1000 条
        const safeLimit = Math.min(effectiveLimit, 1000);

        // 限流
        await this.throttle(`${symbol}:1m`);

        const rawKlines = await this.client.getKlines({
            symbol,
            interval: "1m",
            startTime,
            endTime,
            limit: safeLimit,
        });

        logger.debug(
            { symbol, interval: "1m", startTime, endTime, limit: safeLimit },
            "[binance] fetchKlines 请求参数",
        );

        if (!rawKlines || rawKlines.length === 0) {
            return [];
        }

        // 按 openTime 升序排序（防御性），转换为标准化 Kline
        return rawKlines
            .map((k) => convertBinanceKline(k, symbol, "1m", type))
            .sort((a, b) => a.openTime - b.openTime);
    }

    async fetchMarkets(): Promise<MarketInfo[]> {
        // TODO: 调用 Binance /exchangeInfo 接口
        return [];
    }
}

// ============================================================
// BinanceFuturesRestClient — USDT-M 永续合约
// ============================================================

export class BinanceFuturesRestClient extends BaseRestClient {
    readonly exchange = "binance_futures";

    private client: USDMClient;

    constructor() {
        super();
        this.client = new USDMClient(
            {
                api_key: exchange.binanceFutures.apiKey,
                api_secret: exchange.binanceFutures.apiSecret,
            },
            { timeout: 3000 },
        );
    }

    /**
     * 拉取 USDT-M 永续合约 1m K 线。
     *
     * USDMClient.getKlines() 返回与 MainClient 同构的 12 元组，
     * convertBinanceKline 直接复用，type 由调用方通过 params 传入。
     */
    async fetchKlines(params: FetchKlinesParams): Promise<Kline[]> {
        const { symbol, startTime, limit, endTime, type } = params;
        const effectiveLimit = limit ?? this.config.defaultLimit;
        const safeLimit = Math.min(effectiveLimit, 1000);

        await this.throttle(`${symbol}:1m`);

        const rawKlines = await this.client.getKlines({
            symbol,
            interval: "1m",
            startTime,
            endTime,
            limit: safeLimit,
        });

        logger.debug(
            { symbol, interval: "1m", startTime, endTime, limit: safeLimit },
            "[binance_futures] fetchKlines 请求参数",
        );

        if (!rawKlines || rawKlines.length === 0) {
            return [];
        }

        return rawKlines
            .map((k) => convertBinanceKline(k, symbol, "1m", type))
            .sort((a, b) => a.openTime - b.openTime);
    }

    async fetchMarkets(): Promise<MarketInfo[]> {
        return [];
    }
}
