import type { BacktestRequest, HistoricalDataset, HistoricalLoadResult } from '../types.js';
import { InlineReplayAdapter } from './exchangeReplayAdapter.js';
import { loadDatasetFromCsv } from './csvLoader.js';
import { loadDatasetFromJsonPayload } from './jsonLoader.js';
import { loadDatasetFromKraken } from './krakenLoader.js';
import { selectDatasetForReplayWindow } from './normalize.js';

const parseIsoDate = (value: string, field: string): number => {
    const timestamp = Date.parse(String(value || '').trim());
    if (!Number.isFinite(timestamp)) {
        throw new Error(`Invalid ${field} date: ${value}`);
    }
    return timestamp;
};

const loadBaseDataset = async (request: BacktestRequest): Promise<HistoricalDataset> => {
    const source = request.dataSource;
    if (source.type === 'csv') {
        return loadDatasetFromCsv(source.payload);
    }
    if (source.type === 'json') {
        return loadDatasetFromJsonPayload(source.payload);
    }
    if (source.type === 'replay') {
        const adapter = new InlineReplayAdapter(source.payload);
        return await adapter.loadHistoricalDataset();
    }
    if (source.type === 'kraken') {
        const fromTs = parseIsoDate(request.dateRange.from, 'from');
        const toTs = parseIsoDate(request.dateRange.to, 'to');
        const includeOneMinute = request.timeframe === '1m'
            || request.execution?.triggerTimeframe === '1m';
        return loadDatasetFromKraken({
            symbols: request.symbols,
            fromTs,
            toTs,
            lookbackCandles: source.payload?.lookbackCandles,
            limitPerRequest: source.payload?.limitPerRequest,
            includeOneMinute,
            disableCache: source.payload?.disableCache === true
        });
    }
    throw new Error(`Unsupported backtest data source: ${(source as { type?: string })?.type || 'unknown'}`);
};

export const loadHistoricalData = async (request: BacktestRequest): Promise<HistoricalLoadResult> => {
    const fromTs = parseIsoDate(request.dateRange.from, 'from');
    const toTs = parseIsoDate(request.dateRange.to, 'to');
    if (toTs < fromTs) {
        throw new Error('dateRange.to must be greater than or equal to dateRange.from.');
    }
    const baseDataset = await loadBaseDataset(request);
    const dataset = selectDatasetForReplayWindow(baseDataset, request.symbols, fromTs, toTs);
    return {
        dataset,
        source: request.dataSource.type,
        window: {
            fromTimestamp: fromTs,
            toTimestamp: toTs,
            fromIso: new Date(fromTs).toISOString(),
            toIso: new Date(toTs).toISOString(),
            timezone: 'UTC'
        }
    };
};
