import type { Candle, ExchangeCapabilities, IExchangeConnector } from '../../connectors/types.js';
import type { BacktestTimeframe, HistoricalDataset } from '../types.js';

const asBacktestTimeframe = (timeframe: string): BacktestTimeframe => {
    const normalized = String(timeframe || '').trim().toLowerCase();
    if (normalized === '1m' || normalized === '1min') return '1m';
    if (normalized === '15m' || normalized === '15min') return '15m';
    if (normalized === '1h' || normalized === '60m') return '1h';
    if (normalized === '4h' || normalized === '240m') return '4h';
    throw new Error(`Unsupported replay timeframe: ${timeframe}`);
};

export class ReplayExchangeConnector implements IExchangeConnector {
    private cursorTimestamp: number | null = null;
    private calls = {
        fetchOHLCV: 0,
        placeOrder: 0,
        getPosition: 0
    };

    constructor(private readonly dataset: HistoricalDataset) { }

    public setCursorTimestamp(timestamp: number): void {
        this.cursorTimestamp = timestamp;
    }

    public getCallCounts(): { fetchOHLCV: number; placeOrder: number; getPosition: number } {
        return { ...this.calls };
    }

    public getCapabilities(): ExchangeCapabilities {
        return {
            fetchOpenOrders: false,
            fetchClosedOrders: false,
            shorting: true,
            margin: false,
            leverage: false,
            tradingWindow: false
        };
    }

    public getCandleCountUpTo(symbol: string, timeframe: BacktestTimeframe, timestamp: number): number {
        const normalizedSymbol = String(symbol || '').trim().toUpperCase();
        const candles = this.dataset[normalizedSymbol]?.[timeframe] || [];
        return candles.filter((candle) => candle.timestamp <= timestamp).length;
    }

    public getCandleAtOrBefore(symbol: string, timeframe: BacktestTimeframe, timestamp: number): Candle | null {
        const normalizedSymbol = String(symbol || '').trim().toUpperCase();
        const candles = this.dataset[normalizedSymbol]?.[timeframe] || [];
        let selected: Candle | null = null;
        for (const candle of candles) {
            if (candle.timestamp <= timestamp) {
                selected = candle;
                continue;
            }
            break;
        }
        return selected;
    }

    public async fetchOHLCV(symbol: string, timeframe: string, limit?: number): Promise<Candle[]> {
        this.calls.fetchOHLCV += 1;
        const normalizedSymbol = String(symbol || '').trim().toUpperCase();
        const normalizedTf = asBacktestTimeframe(timeframe);
        const candles = this.dataset[normalizedSymbol]?.[normalizedTf] || [];
        const cursor = this.cursorTimestamp ?? Number.POSITIVE_INFINITY;
        const scoped = candles.filter((candle) => candle.timestamp <= cursor);
        const boundedLimit = Number.isFinite(Number(limit)) && Number(limit) > 0
            ? Math.floor(Number(limit))
            : scoped.length;
        if (boundedLimit <= 0) return [];
        if (scoped.length <= boundedLimit) return scoped;
        return scoped.slice(-boundedLimit);
    }

    public async placeOrder(): Promise<any> {
        this.calls.placeOrder += 1;
        throw new Error('Backtest safety violation: placeOrder is forbidden in replay mode.');
    }

    public async getPosition(): Promise<any> {
        this.calls.getPosition += 1;
        return null;
    }
}
