const cron = require('node-cron');
const axios = require('axios');
const { MarketPair, SymbolStats } = require('../models');

const RATES_URL = 'http://localhost:5001/api/v1/latest/rates/all';

/**
 * Fetch latest rates from the API.
 * Returns an array of rate objects, or null on failure.
 */
async function fetchRates() {
    try {
        const { data } = await axios.get(RATES_URL, { timeout: 15000 });
        const x = data?.data?.rates ?? data?.rates
       
        return Array.isArray(x) ? x : null;
    } catch (err) {
        console.error('[UpdateMarket] Failed to fetch rates:', err.message);
        return null;
    }
}

/**
 * Build an update payload from a rate object.
 * Fields whose source value is null are omitted so the DB column is untouched.
 */
function buildPayload(rate) {
    const map = {
        current_price:      rate.price,
        open24h:            rate.open24h,
        change24h:          rate.change24h,
        change_percent24h:  rate.changePercent,
        high24h:            rate.high24h,
        low24h:             rate.low24h,
        volume24h:          rate.volume24h,
    };

    // Drop any key whose value is null or undefined
    return Object.fromEntries(
        Object.entries(map).filter(([, v]) => v !== null && v !== undefined)
    );
}

/**
 * Core update logic — called by the cron job.
 */
async function updateMarketRates() {
    console.log('[UpdateMarket] Starting market update…');

    const rates = await fetchRates();
    
    if (!rates || rates.length === 0) {
        console.warn('[UpdateMarket] No rates received — skipping update.');
        return;
    }

    // Build a symbol → rate lookup for O(1) access
    const rateMap = Object.fromEntries(rates.map(r => [r.symbol, r]));

    // Load all market pairs in one query
    const pairs = await MarketPair.findAll();
    if (!pairs.length) {
        console.warn('[UpdateMarket] No market pairs found in DB.');
        return;
    }

    let updated = 0;
    let skipped = 0;
    let skippedSymbol = []
    let updateSymbol = []

    await Promise.all(
        pairs.map(async (pair) => {
            const rate = rateMap[pair.symbol]; // adjust field name if needed
            if (!rate) {
                skipped++;
                skippedSymbol.push(pair.symbol)
                return;
            }

            const payload = buildPayload(rate);
            if (Object.keys(payload).length === 0) {
                // Everything was null — nothing to write
                skipped++;
                return;
            }

            try {
                await SymbolStats.update(payload, {
                    where: { asset_id: pair.id },
                });
                updateSymbol.push(pair.symbol)
                updated++;
            } catch (err) {
                console.error(
                    `[UpdateMarket] Failed to update stats for pair ${pair.id} (${pair.symbol}):`,
                    err.message
                );
            }
        })
    );

    return {
        skipped,
        updated,
        skippedLength: skippedSymbol.length,
        updateLength: updateSymbol.length,
        skippedSymbol,
        updateSymbol
    }

    console.log(
        `[UpdateMarket] Done — ${updated} updated, ${skipped} skipped.`
    );
}

/**
 * Schedule: every 20 minutes.
 * Cron expression: "0,20,40 * * * *"
 */
function startMarketUpdateCron() {
    console.log('[UpdateMarket] Cron job registered — runs every 20 minutes.');

    // Run immediately on startup so you don't wait 20 min for the first update
    updateMarketRates();

    cron.schedule('0,20,40 * * * *', () => {
        updateMarketRates();
    });
}

module.exports = { startMarketUpdateCron, updateMarketRates };