/**
 * Yahoo Finance Service
 * Fetches latest stock price data from Yahoo Finance API
 */

/**
 * Normalize symbol for Yahoo Finance API
 * Converts dots to hyphens (e.g., BRK.B -> BRK-B)
 * @param {string} symbol - Stock symbol
 * @returns {string} Normalized symbol
 */
function normalizeYahooSymbol(symbol) {
  if (!symbol) return symbol;
  // Convert dots to hyphens for Yahoo Finance API
  // BRK.B -> BRK-B
  return symbol.toUpperCase().replace(/\./g, '-');
}

/**
 * Fetch latest stock data from Yahoo Finance for a single symbol
 * @param {string} symbol - Stock symbol (e.g., 'AAPL')
 * @returns {Promise<Object|null>} Stock price data or null if failed
 */
export async function fetchYahooFinanceData(symbol) {
  try {
    // Normalize symbol for Yahoo Finance API (e.g., BRK.B -> BRK-B)
    const normalizedSymbol = normalizeYahooSymbol(symbol);
    const url = `https://query1.finance.yahoo.com/v8/finance/chart/${normalizedSymbol}?interval=1d&range=5d`;
    const response = await fetch(url);
    
    if (!response.ok) {
      // If 404, try with original symbol in case normalization was wrong
      if (response.status === 404 && normalizedSymbol !== symbol.toUpperCase()) {
        console.warn(`Yahoo Finance API error for ${symbol} (tried ${normalizedSymbol}): ${response.status} ${response.statusText}`);
      } else {
        console.warn(`Yahoo Finance API error for ${symbol}: ${response.status} ${response.statusText}`);
      }
      return null;
    }
    
    const data = await response.json();
    
    if (data.chart?.result?.[0]) {
      const result = data.chart.result[0];
      const meta = result.meta;
      const quotes = result.indicators?.quote?.[0];
      const timestamps = result.timestamp || [];
      
      // Extract historical volume data (last 5 days)
      const volumeHistory = [];
      if (quotes && quotes.volume && timestamps.length > 0) {
        const volumes = quotes.volume || [];
        const closes = quotes.close || [];
        const opens = quotes.open || [];
        const highs = quotes.high || [];
        const lows = quotes.low || [];
        
        // Get the last 5 days (or all available if less than 5)
        const startIdx = Math.max(0, timestamps.length - 5);
        for (let i = startIdx; i < timestamps.length; i++) {
          if (volumes[i] !== null && volumes[i] !== undefined) {
            const timestamp = timestamps[i];
            const date = new Date(timestamp * 1000);
            const open = opens[i] || 0;
            const high = highs[i] || 0;
            const low = lows[i] || 0;
            const close = closes[i] || 0;
            
            // Calculate VWAP (Volume Weighted Average Price)
            // For daily bars, use Typical Price: (High + Low + Close) / 3
            const typicalPrice = (high + low + close) / 3;
            const vwap = typicalPrice; // For daily bars, VWAP = Typical Price
            
            volumeHistory.push({
              date: date.toISOString().split('T')[0], // Convert to YYYY-MM-DD
              volume: Math.round(volumes[i]) || 0,
              close: close,
              open: open,
              high: high,
              low: low,
              vwap: vwap
            });
          }
        }
        
        // Sort by date descending (most recent first)
        volumeHistory.sort((a, b) => new Date(b.date) - new Date(a.date));
      }
      
      return {
        symbol: symbol.toUpperCase(),
        currentPrice: meta.regularMarketPrice || meta.previousClose,
        previousClose: meta.previousClose,
        open: meta.regularMarketOpen || meta.previousClose,
        high: meta.regularMarketDayHigh,
        low: meta.regularMarketDayLow,
        volume: meta.regularMarketVolume,
        marketCap: meta.marketCap,
        changePercent: meta.regularMarketPrice && meta.previousClose 
          ? ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose) * 100 
          : 0,
        change: meta.regularMarketPrice && meta.previousClose
          ? meta.regularMarketPrice - meta.previousClose
          : 0,
        // Get recent price history
        recentPrices: quotes?.close?.slice(-5) || [],
        // Get volume history (last 5 days)
        volumeHistory: volumeHistory,
        timestamp: new Date().toISOString()
      };
    }
    
    return null;
  } catch (error) {
    console.warn(`Failed to fetch Yahoo Finance data for ${symbol}:`, error.message);
    return null;
  }
}

/**
 * Batch fetch stock data for multiple symbols with concurrency control
 * @param {string[]} symbols - Array of stock symbols
 * @param {number} concurrency - Number of concurrent requests (default: 5)
 * @returns {Promise<Object>} Map of symbol to price data
 */
export async function batchFetchYahooFinanceData(symbols, concurrency = 5) {
  if (!symbols || symbols.length === 0) {
    return {};
  }
  
  // Remove duplicates and normalize symbols
  const uniqueSymbols = [...new Set(symbols.map(s => s.toUpperCase().trim()))].filter(Boolean);
  
  if (uniqueSymbols.length === 0) {
    return {};
  }
  
  const priceDataMap = {};
  
  // Process in batches to avoid overwhelming the API
  for (let i = 0; i < uniqueSymbols.length; i += concurrency) {
    const batch = uniqueSymbols.slice(i, i + concurrency);
    const batchPromises = batch.map(async (symbol) => {
      const data = await fetchYahooFinanceData(symbol);
      return { symbol, data };
    });
    
    const batchResults = await Promise.allSettled(batchPromises);
    
    batchResults.forEach((result) => {
      if (result.status === 'fulfilled') {
        const { symbol, data } = result.value;
        if (data) {
          priceDataMap[symbol] = data;
        }
      } else {
        console.warn(`Failed to fetch data for symbol in batch:`, result.reason);
      }
    });
    
    // Small delay between batches to be respectful to the API
    if (i + concurrency < uniqueSymbols.length) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }
  
  return priceDataMap;
}

