/**
 * Market Analysis Routes
 * Exposes deep stock analysis for top 50 universe
 * All data from free sources (Yahoo Finance, Finviz, SEC EDGAR RSS)
 */

import express from 'express';
import NodeCache from 'node-cache';
import { UNIVERSE, getSymbolMeta, classifyCapTier } from '../services/stockUniverseService.js';
import { fetchBasicQuote, fetchQuoteSummary, fetchTechnicals, fetchFullAnalysis, fetchMacroPerformance } from '../services/fundamentalsService.js';
import { fetchInstitutionalHolders, fetchInsiderTransactions } from '../services/institutionalHoldersService.js';
import { fetchNewsForSymbol, fetchMarketNews } from '../services/newsService.js';
import { scoreSuitability } from '../services/scoringEngine.js';
import { classifyRegime } from '../services/regimeService.js';
import { logSignals } from '../services/signalLogger.js';
const router = express.Router();
const universeCache = new NodeCache({ stdTTL: 60 });

/**
 * GET /api/market/universe
 * Returns full top-50 list with price, change, cap tier
 * Optional: ?cap=large|mid|small|etf  ?sector=Technology
 */
router.get('/universe', async (req, res) => {
  try {
    const { cap, sector } = req.query;
    const cacheKey = `universe_${cap || 'all'}_${sector || 'all'}`;
    const cached = universeCache.get(cacheKey);
    if (cached) {
      return res.json({ success: true, data: cached, cached: true, updatedAt: new Date().toISOString() });
    }

    // Fetch quotes for all symbols concurrently (batched)
    const CONCURRENCY = 8;
    const results = [];

    for (let i = 0; i < UNIVERSE.length; i += CONCURRENCY) {
      const batch = UNIVERSE.slice(i, i + CONCURRENCY);
      const batchResults = await Promise.allSettled(
        batch.map(async (entry) => {
          const quote = await fetchBasicQuote(entry.symbol);
          const capTier = classifyCapTier(quote?.market_cap ?? null, entry.isETF);
          return {
            symbol: entry.symbol,
            name: entry.name,
            sector: entry.sector,
            isETF: entry.isETF,
            capTier,
            price: quote?.price ?? null,
            change: quote?.change ?? null,
            change_pct: quote?.change_pct ?? null,
            market_cap: quote?.market_cap ?? null,
            volume: quote?.volume ?? null,
            high_52w: null,  // populated by quoteSummary if needed
            low_52w: null,
            market_state: quote?.market_state ?? null,
          };
        })
      );

      batchResults.forEach(r => {
        if (r.status === 'fulfilled' && r.value) results.push(r.value);
      });

      // Small delay between batches
      if (i + CONCURRENCY < UNIVERSE.length) {
        await new Promise(r => setTimeout(r, 150));
      }
    }

    // Apply filters
    let filtered = results;
    if (cap) {
      const capUpper = cap.toUpperCase();
      filtered = filtered.filter(r => r.capTier === capUpper);
    }
    if (sector) {
      filtered = filtered.filter(r => r.sector.toLowerCase() === sector.toLowerCase());
    }

    // Sort: ETFs last, then by market cap desc
    filtered.sort((a, b) => {
      if (a.isETF !== b.isETF) return a.isETF ? 1 : -1;
      return (b.market_cap || 0) - (a.market_cap || 0);
    });

    universeCache.set(cacheKey, filtered);
    res.json({ success: true, data: filtered, count: filtered.length, updatedAt: new Date().toISOString() });
  } catch (err) {
    console.error('[market/universe]', err);
    res.status(500).json({ success: false, error: err.message });
  }
});

/**
 * GET /api/market/stock/:symbol
 * Full deep analysis: quote + fundamentals + technicals
 */
router.get('/stock/:symbol', async (req, res) => {
  try {
    const symbol = req.params.symbol.toUpperCase();
    const meta = getSymbolMeta(symbol);
    const analysis = await fetchFullAnalysis(symbol);

    const profile = await getSingleFactorProfile(symbol);

    res.json({
      success: true,
      data: {
        ...analysis,
        meta,
        capTier: classifyCapTier(analysis.quote?.market_cap ?? null, meta?.isETF ?? false),
        profile,
      }
    });
  } catch (err) {
    console.error(`[market/stock/${req.params.symbol}]`, err);
    res.status(500).json({ success: false, error: err.message });
  }
});

/**
 * GET /api/market/stock/:symbol/news
 * Financial news for a symbol from multiple free sources
 */
router.get('/stock/:symbol/news', async (req, res) => {
  try {
    const symbol = req.params.symbol.toUpperCase();
    const news = await fetchNewsForSymbol(symbol);
    res.json({ success: true, data: news, count: news.length, symbol });
  } catch (err) {
    console.error(`[market/news/${req.params.symbol}]`, err);
    res.status(500).json({ success: false, error: err.message });
  }
});

/**
 * GET /api/market/stock/:symbol/holders
 * Institutional holders + insider transactions
 */
router.get('/stock/:symbol/holders', async (req, res) => {
  try {
    const symbol = req.params.symbol.toUpperCase();
    const [institutional, insiders] = await Promise.allSettled([
      fetchInstitutionalHolders(symbol),
      fetchInsiderTransactions(symbol),
    ]);

    res.json({
      success: true,
      data: {
        institutional: institutional.status === 'fulfilled' ? institutional.value : null,
        insiders: insiders.status === 'fulfilled' ? insiders.value : null,
        symbol,
        fetchedAt: new Date().toISOString(),
      }
    });
  } catch (err) {
    console.error(`[market/holders/${req.params.symbol}]`, err);
    res.status(500).json({ success: false, error: err.message });
  }
});

/**
 * GET /api/market/news
 * Market-wide news (SPY, macro, broad market)
 */
router.get('/news', async (req, res) => {
  try {
    const news = await fetchMarketNews();
    res.json({ success: true, data: news, count: news.length });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});

/**
 * GET /api/market/leaderboard
 * Top movers and worst performers from the universe
 */
router.get('/leaderboard', async (req, res) => {
  try {
    const cacheKey = 'leaderboard';
    const cached = universeCache.get(cacheKey);
    if (cached) return res.json({ success: true, data: cached });

    const CONCURRENCY = 8;
    const quotes = [];

    for (let i = 0; i < UNIVERSE.length; i += CONCURRENCY) {
      const batch = UNIVERSE.slice(i, i + CONCURRENCY);
      const batchResults = await Promise.allSettled(
        batch.map(async (entry) => {
          const q = await fetchBasicQuote(entry.symbol);
          return q ? { symbol: entry.symbol, name: entry.name, isETF: entry.isETF, ...q } : null;
        })
      );
      batchResults.forEach(r => {
        if (r.status === 'fulfilled' && r.value) quotes.push(r.value);
      });
      if (i + CONCURRENCY < UNIVERSE.length) await new Promise(r => setTimeout(r, 100));
    }

    const validQuotes = quotes.filter(q => q.change_pct != null);
    const sorted = [...validQuotes].sort((a, b) => b.change_pct - a.change_pct);

    const result = {
      top_gainers: sorted.slice(0, 5),
      top_losers: sorted.slice(-5).reverse(),
      most_active: [...validQuotes].sort((a, b) => (b.volume || 0) - (a.volume || 0)).slice(0, 5),
    };

    universeCache.set(cacheKey, result);
    res.json({ success: true, data: result, updatedAt: new Date().toISOString() });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});

import { buildFactorProfiles, getSingleFactorProfile } from '../factorlab/descriptiveLens.js';

/**
 * GET /api/market/screener
 * Returns the descriptive factor profiles for the entire universe.
 * Strictly descriptive. No predictive claims.
 */
router.get('/screener', async (req, res) => {
  try {
    const cacheKey = 'screener';
    const cached = universeCache.get(cacheKey);
    if (cached) return res.json({ success: true, data: cached, cached: true });

    // Fetch the descriptive factor profiles
    const profiles = await buildFactorProfiles();
    
    const data = {
      profiles: profiles,
      updatedAt: new Date().toISOString(),
    };

    universeCache.set(cacheKey, data, 120); // 120s cache
    res.json({ success: true, data });
  } catch (err) {
    console.error('[market/screener]', err);
    res.status(500).json({ success: false, error: err.message });
  }
});

/**
 * GET /api/market/search/:symbol
 * Search ANY ticker (not just universe). Returns full analysis + suitability.
 */
router.get('/search/:symbol', async (req, res) => {
  try {
    const symbol = req.params.symbol.toUpperCase().trim();
    const meta = getSymbolMeta(symbol); // may be null for out-of-universe tickers

    const analysis = await fetchFullAnalysis(symbol);
    if (!analysis.quote) {
      return res.status(404).json({ success: false, error: `No data found for symbol ${symbol}` });
    }

    const suitability = scoreSuitability({
      quote: analysis.quote,
      technicals: analysis.technicals,
      fundamentals: analysis.fundamentals,
      regime: { trend: 'neutral', vol: 'normal', breadth: 'mixed', raw: {} },
      dataAgeSec: 15
    });

    const capTier = classifyCapTier(
      analysis.quote?.market_cap ?? analysis.fundamentals?.market_cap ?? null,
      meta?.isETF ?? false
    );

    const profile = await getSingleFactorProfile(symbol);

    res.json({
      success: true,
      data: { ...analysis, meta, capTier, suitability, profile },
    });
  } catch (err) {
    console.error(`[market/search/${req.params.symbol}]`, err);
    res.status(500).json({ success: false, error: err.message });
  }
});
/**
 * GET /api/market/macro
 * Global Macro Indicators (Descriptive Context)
 */
router.get('/macro', async (req, res) => {
  try {
    const cacheKey = 'macro_indicators';
    const cached = universeCache.get(cacheKey);
    if (cached) return res.json({ success: true, data: cached });

    const MACRO_SYMBOLS = [
      { symbol: '^VIX', name: 'Volatility (VIX)' },
      { symbol: 'DX-Y.NYB', name: 'US Dollar (DXY)' },
      { symbol: '^TNX', name: '10-Yr Yield' },
      { symbol: 'GC=F', name: 'Gold' },
      { symbol: 'SI=F', name: 'Silver' },
      { symbol: 'EWJ', name: 'Japan (EWJ)' },
      { symbol: 'FXI', name: 'China (FXI)' },
      { symbol: 'INDA', name: 'India (INDA)' },
      { symbol: 'VGK', name: 'Europe (VGK)' },
      { symbol: 'BTC-USD', name: 'Bitcoin' },
    ];

    const results = await Promise.allSettled(
      MACRO_SYMBOLS.map(async (entry) => {
        const q = await fetchMacroPerformance(entry.symbol);
        return q ? { symbol: entry.symbol, name: entry.name, ...q } : null;
      })
    );

    const data = results
      .filter(r => r.status === 'fulfilled' && r.value)
      .map(r => r.value);

    universeCache.set(cacheKey, data, 60); // Cache for 60 seconds
    res.json({ success: true, data, updatedAt: new Date().toISOString() });
  } catch (err) {
    console.error('[market/macro]', err);
    res.status(500).json({ success: false, error: err.message });
  }
});

export default router;
