import type { Candle } from '../connectors/types.js';

function normalizeCryptoProductId(symbol: string): string {
    const upper = String(symbol || '').trim().toUpperCase();
    if (!upper) return upper;
    if (upper.includes('/')) return upper.replace('/', '-');
    if (upper.endsWith('USDT')) return `${upper.slice(0, -4)}-USDT`;
    if (upper.endsWith('USD')) return `${upper.slice(0, -3)}-USD`;
    return upper;
}

function toCoinbaseGranularity(timeframe: string): number {
    const normalized = String(timeframe || '').trim().toLowerCase();
    switch (normalized) {
        case '1m':
        case '1min':
            return 60;
        case '5m':
        case '5min':
            return 300;
        case '15m':
        case '15min':
            return 900;
        case '1h':
        case '1hour':
            return 3600;
        case '4h':
        case '4hour':
            return 3600;
        case '1d':
        case '1day':
            return 86400;
        case '1w':
        case '1week':
            return 86400;
        case '1month':
            return 86400;
        default:
            return 3600;
    }
}

function aggregateBars(candles: Candle[], factor: number): Candle[] {
    const aggregated: Candle[] = [];
    for (let i = 0; i < candles.length; i += factor) {
        const chunk = candles.slice(i, i + factor);
        if (!chunk.length) continue;
        aggregated.push({
            timestamp: chunk[0].timestamp,
            open: chunk[0].open,
            high: Math.max(...chunk.map((c) => c.high)),
            low: Math.min(...chunk.map((c) => c.low)),
            close: chunk[chunk.length - 1].close,
            volume: chunk.reduce((sum, c) => sum + c.volume, 0),
        });
    }
    return aggregated;
}

export async function fetchCoinbaseCryptoCandles(params: {
    symbol: string;
    timeframe: string;
    start?: string;
    end?: string;
    limit?: number;
}): Promise<Candle[]> {
    const productId = normalizeCryptoProductId(params.symbol);
    const granularity = toCoinbaseGranularity(params.timeframe);
    const query = new URLSearchParams({
        granularity: String(granularity),
    });
    if (params.start) query.set('start', params.start);
    if (params.end) query.set('end', params.end);

    const response = await fetch(`https://api.exchange.coinbase.com/products/${encodeURIComponent(productId)}/candles?${query.toString()}`);
    if (!response.ok) {
        const txt = await response.text().catch(() => '');
        throw new Error(`Coinbase candles fetch failed: ${response.status} ${txt || response.statusText}`);
    }

    const payload = await response.json() as any[];
    const candles: Candle[] = Array.isArray(payload)
        ? payload.map((row: any) => ({
            timestamp: Number(row[0]) * 1000,
            low: Number(row[1]),
            high: Number(row[2]),
            open: Number(row[3]),
            close: Number(row[4]),
            volume: Number(row[5] || 0),
        }))
        : [];

    const sorted = candles
        .filter((c) => Number.isFinite(c.timestamp) && Number.isFinite(c.open) && Number.isFinite(c.high) && Number.isFinite(c.low) && Number.isFinite(c.close))
        .sort((a, b) => a.timestamp - b.timestamp);

    const normalizedTimeframe = String(params.timeframe || '').trim().toLowerCase();
    const aggregated = normalizedTimeframe === '4h' || normalizedTimeframe === '4hour'
        ? aggregateBars(sorted, 4)
        : sorted;

    if (params.limit && params.limit > 0 && aggregated.length > params.limit) {
        return aggregated.slice(-params.limit);
    }

    return aggregated;
}
