"""
Yahoo Finance Direct API Client
Bypasses yfinance library and calls Yahoo Finance v8 API directly
This fixes the broken yfinance 0.1.87 on Python 3.6

Author: Claude Code
Date: 2026-03-15
"""

import requests
import time
import threading
from datetime import datetime
from typing import Dict, Any, Optional, List
from collections import deque

from error_logger import log_scraper_error, log_warning

# Yahoo Finance v8 API endpoints
YAHOO_CHART_API = "https://query1.finance.yahoo.com/v8/finance/chart"
YAHOO_QUOTE_API = "https://query1.finance.yahoo.com/v7/finance/quote"

HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept': 'application/json',
    'Accept-Language': 'en-US,en;q=0.9',
}

# ============================================================================
# Rate Limiter
# ============================================================================

class RateLimiter:
    """
    Thread-safe rate limiter: max N requests per M seconds
    Prevents 429 Too Many Requests errors
    """

    def __init__(self, max_requests: int = 5, time_window: float = 1.0):
        """
        Args:
            max_requests: Maximum requests allowed in time window
            time_window: Time window in seconds
        """
        self.max_requests = max_requests
        self.time_window = time_window
        self.requests = deque()
        self.lock = threading.Lock()

    def acquire(self):
        """Wait if necessary, then allow request"""
        with self.lock:
            now = time.time()

            # Remove old requests outside window
            while self.requests and self.requests[0] < now - self.time_window:
                self.requests.popleft()

            # If at limit, wait
            if len(self.requests) >= self.max_requests:
                sleep_time = self.requests[0] + self.time_window - now
                if sleep_time > 0:
                    time.sleep(sleep_time)
                # Re-check after sleep
                now = time.time()
                while self.requests and self.requests[0] < now - self.time_window:
                    self.requests.popleft()

            self.requests.append(time.time())


# Global rate limiter: 5 requests per second
_rate_limiter = RateLimiter(max_requests=5, time_window=1.0)

# ============================================================================
# Helper Functions
# ============================================================================

def _safe_float(value) -> Optional[float]:
    """Safely convert value to float, handling NaN/Inf"""
    if value is None:
        return None
    try:
        f = float(value)
        # NaN check without numpy
        if f != f:
            return None
        # Inf check
        if f == float('inf') or f == float('-inf'):
            return None
        return round(f, 4)
    except (ValueError, TypeError):
        return None


# Symbol mapping for restructured/renamed stocks
# NSE Symbol -> Yahoo Symbol (without .NS suffix)
# Updated March 2026: Tata Motors restructured into TMCV (commercial) and TMPV (passenger)
YAHOO_SYMBOL_MAP = {
    'TATAMOTORS': 'TMCV',      # Tata Motors -> Tata Motors Commercial Vehicles
    'TATAMTRDVR': 'TMPV',      # DVR shares -> Passenger Vehicles
    # Add more mappings as corporate restructurings occur
}


def _format_symbol(symbol: str, add_ns_suffix: bool = True) -> str:
    """Format symbol for Yahoo Finance API"""
    symbol = symbol.strip().upper()

    # Don't add suffix to indices or forex
    if symbol.startswith('^') or '=' in symbol or '-' in symbol:
        return symbol

    # Check for symbol mapping (restructured stocks)
    base_symbol = symbol.replace('.NS', '').replace('.BO', '')
    if base_symbol in YAHOO_SYMBOL_MAP:
        symbol = YAHOO_SYMBOL_MAP[base_symbol]

    # Add .NS suffix for NSE stocks if needed
    if add_ns_suffix and '.NS' not in symbol and '.BO' not in symbol:
        return '{}.NS'.format(symbol)

    return symbol


# ============================================================================
# Core API Functions
# ============================================================================

def get_chart_data(symbol: str, period: str = '5d', interval: str = '1d',
                   use_rate_limit: bool = True) -> Dict[str, Any]:
    """
    Fetch chart data directly from Yahoo Finance v8 API

    Args:
        symbol: Stock symbol (e.g., 'RELIANCE.NS', '^INDIAVIX', 'CL=F')
        period: '1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', 'max'
        interval: '1m', '5m', '15m', '30m', '1h', '1d', '1wk', '1mo'
        use_rate_limit: Whether to apply rate limiting

    Returns:
        Dictionary with chart data and metadata
    """
    result = {
        'source': 'yahoo_direct',
        'symbol': symbol,
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat()
    }

    try:
        # Apply rate limiting
        if use_rate_limit:
            _rate_limiter.acquire()

        url = "{}/{}".format(YAHOO_CHART_API, symbol)
        params = {
            'interval': interval,
            'range': period,
            'includePrePost': 'false',
            'events': 'div,splits'
        }

        response = requests.get(url, headers=HEADERS, params=params, timeout=15)

        if response.status_code == 429:
            result['error'] = 'Rate limited - too many requests'
            return result

        if response.status_code != 200:
            result['error'] = 'HTTP {}'.format(response.status_code)
            return result

        data = response.json()
        chart = data.get('chart', {})

        # Check for API error
        if chart.get('error'):
            error_desc = chart['error'].get('description', 'Unknown error')
            result['error'] = error_desc
            return result

        results = chart.get('result', [])
        if not results:
            result['error'] = 'No data returned'
            return result

        r = results[0]
        meta = r.get('meta', {})
        timestamps = r.get('timestamp', [])
        indicators = r.get('indicators', {})
        quote = indicators.get('quote', [{}])[0]

        # Success
        result['status'] = 'ok'
        result['data_points'] = len(timestamps) if timestamps else 0
        result['currency'] = meta.get('currency')
        result['exchange'] = meta.get('exchangeName')
        result['instrument_type'] = meta.get('instrumentType')
        result['timezone'] = meta.get('exchangeTimezoneName')

        # Current price from meta (most reliable)
        result['ltp'] = _safe_float(meta.get('regularMarketPrice'))
        result['prev_close'] = _safe_float(meta.get('chartPreviousClose') or meta.get('previousClose'))
        result['day_high'] = _safe_float(meta.get('regularMarketDayHigh'))
        result['day_low'] = _safe_float(meta.get('regularMarketDayLow'))
        result['open'] = _safe_float(meta.get('regularMarketOpen'))
        result['volume'] = _safe_float(meta.get('regularMarketVolume'))
        result['week_52_high'] = _safe_float(meta.get('fiftyTwoWeekHigh'))
        result['week_52_low'] = _safe_float(meta.get('fiftyTwoWeekLow'))

        # Historical OHLCV data
        if timestamps:
            result['timestamps'] = timestamps
            result['dates'] = [datetime.fromtimestamp(ts).isoformat() for ts in timestamps]

        result['closes'] = [_safe_float(v) for v in quote.get('close', [])]
        result['highs'] = [_safe_float(v) for v in quote.get('high', [])]
        result['lows'] = [_safe_float(v) for v in quote.get('low', [])]
        result['opens'] = [_safe_float(v) for v in quote.get('open', [])]
        result['volumes'] = [_safe_float(v) for v in quote.get('volume', [])]

        # Calculate change if we have prices
        if result['ltp'] and result['prev_close']:
            change = result['ltp'] - result['prev_close']
            result['change'] = _safe_float(change)
            result['change_pct'] = _safe_float((change / result['prev_close']) * 100)

        return result

    except requests.exceptions.Timeout:
        log_scraper_error('yahoo_direct', 'get_chart_data', symbol, Exception('Request timeout'))
        result['error'] = 'Request timeout'
        return result
    except requests.exceptions.ConnectionError:
        log_scraper_error('yahoo_direct', 'get_chart_data', symbol, Exception('Connection error'))
        result['error'] = 'Connection error'
        return result
    except Exception as e:
        log_scraper_error('yahoo_direct', 'get_chart_data', symbol, e)
        result['error'] = str(e)
        return result


def get_multi_quotes(symbols: List[str], use_rate_limit: bool = True) -> Dict[str, Any]:
    """
    Fetch quotes for multiple symbols in a single API call

    Args:
        symbols: List of symbols
        use_rate_limit: Whether to apply rate limiting

    Returns:
        Dictionary with quotes for each symbol
    """
    result = {
        'source': 'yahoo_multi_quote',
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat(),
        'quotes': {}
    }

    if not symbols:
        result['status'] = 'ok'
        return result

    try:
        if use_rate_limit:
            _rate_limiter.acquire()

        # Join symbols for batch request
        symbols_str = ','.join(symbols)
        url = YAHOO_QUOTE_API
        params = {
            'symbols': symbols_str,
            'fields': 'regularMarketPrice,regularMarketChange,regularMarketChangePercent,regularMarketVolume,regularMarketOpen,regularMarketDayHigh,regularMarketDayLow,regularMarketPreviousClose'
        }

        response = requests.get(url, headers=HEADERS, params=params, timeout=15)

        if response.status_code != 200:
            result['error'] = 'HTTP {}'.format(response.status_code)
            return result

        data = response.json()
        quote_response = data.get('quoteResponse', {})
        quotes = quote_response.get('result', [])

        for q in quotes:
            sym = q.get('symbol', '')
            result['quotes'][sym] = {
                'ltp': _safe_float(q.get('regularMarketPrice')),
                'change': _safe_float(q.get('regularMarketChange')),
                'change_pct': _safe_float(q.get('regularMarketChangePercent')),
                'volume': _safe_float(q.get('regularMarketVolume')),
                'open': _safe_float(q.get('regularMarketOpen')),
                'high': _safe_float(q.get('regularMarketDayHigh')),
                'low': _safe_float(q.get('regularMarketDayLow')),
                'prev_close': _safe_float(q.get('regularMarketPreviousClose'))
            }

        result['status'] = 'ok'
        return result

    except Exception as e:
        log_scraper_error('yahoo_direct', 'get_multi_quotes', None, e)
        result['error'] = str(e)
        return result


# ============================================================================
# Stock-Specific Functions (replacements for scraper_yahoo.py)
# ============================================================================

def get_quick_quote(symbol: str) -> Dict[str, Any]:
    """
    Get quick quote for an NSE stock

    Args:
        symbol: Stock symbol (e.g., 'RELIANCE')

    Returns:
        Dictionary with current price data
    """
    ticker = _format_symbol(symbol)
    data = get_chart_data(ticker, period='2d', interval='1d')

    if data.get('status') == 'ok':
        data['source'] = 'quick_quote'
        data['symbol'] = symbol

    return data


def get_historical_data(symbol: str, period: str = '1y') -> Dict[str, Any]:
    """
    Get historical OHLCV data for technical analysis

    Args:
        symbol: Stock symbol
        period: '1mo', '3mo', '6mo', '1y', '2y'

    Returns:
        Dictionary with historical data arrays
    """
    ticker = _format_symbol(symbol)
    data = get_chart_data(ticker, period=period, interval='1d')

    if data.get('status') == 'ok':
        data['source'] = 'historical'
        data['symbol'] = symbol
        data['period'] = period

        # Add summary stats
        closes = [c for c in data.get('closes', []) if c is not None]
        if closes:
            data['summary'] = {
                'latest_close': closes[-1] if closes else None,
                'period_high': max(closes),
                'period_low': min(closes),
                'period_return': _safe_float(((closes[-1] / closes[0]) - 1) * 100) if len(closes) > 1 else None,
                'data_points': len(closes)
            }

    return data


def get_bulk_quotes(symbols: List[str]) -> Dict[str, Any]:
    """
    Get quotes for multiple stocks

    Args:
        symbols: List of stock symbols

    Returns:
        Dictionary with quotes for all symbols
    """
    result = {
        'source': 'bulk_quotes',
        'status': 'ok',
        'timestamp': datetime.now().isoformat(),
        'quotes': {}
    }

    # Format symbols
    tickers = [_format_symbol(s) for s in symbols]

    # Fetch in batches of 10 to avoid URL length issues
    batch_size = 10
    for i in range(0, len(tickers), batch_size):
        batch = tickers[i:i + batch_size]
        batch_result = get_multi_quotes(batch)

        if batch_result.get('status') == 'ok':
            # Map back to original symbols
            for j, ticker in enumerate(batch):
                orig_symbol = symbols[i + j]
                if ticker in batch_result.get('quotes', {}):
                    result['quotes'][orig_symbol] = batch_result['quotes'][ticker]
                else:
                    result['quotes'][orig_symbol] = {'error': 'No data'}

    return result


def get_earnings(symbol: str) -> Dict[str, Any]:
    """
    Get earnings/financial data for a stock
    Note: Limited data available from chart API, but includes key metrics

    Args:
        symbol: Stock symbol

    Returns:
        Dictionary with available financial metrics
    """
    ticker = _format_symbol(symbol)
    data = get_chart_data(ticker, period='1y', interval='1d')

    result = {
        'source': 'yahoo_earnings',
        'symbol': symbol,
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat()
    }

    if data.get('status') != 'ok':
        result['error'] = data.get('error', 'Failed to fetch data')
        return result

    result['status'] = 'ok'
    result['week_52_high'] = data.get('week_52_high')
    result['week_52_low'] = data.get('week_52_low')
    result['currency'] = data.get('currency')
    result['exchange'] = data.get('exchange')

    # Calculate 52-week position
    ltp = data.get('ltp')
    high = data.get('week_52_high')
    low = data.get('week_52_low')

    if ltp and high and low and (high - low) > 0:
        position = ((ltp - low) / (high - low)) * 100
        result['week_52_position'] = _safe_float(position)

    # Note: Full earnings data requires Yahoo v10/v11 API which has different auth
    # For now, fundamentals come from Screener.in

    return result


def get_corporate_actions(symbol: str) -> Dict[str, Any]:
    """
    Get corporate actions (dividends, splits) from chart events

    Args:
        symbol: Stock symbol

    Returns:
        Dictionary with corporate action data
    """
    ticker = _format_symbol(symbol)

    result = {
        'source': 'corporate_actions',
        'symbol': symbol,
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat()
    }

    try:
        _rate_limiter.acquire()

        url = "{}/{}".format(YAHOO_CHART_API, ticker)
        params = {
            'interval': '1d',
            'range': '2y',
            'events': 'div,splits'
        }

        response = requests.get(url, headers=HEADERS, params=params, timeout=15)

        if response.status_code != 200:
            result['error'] = 'HTTP {}'.format(response.status_code)
            return result

        data = response.json()
        chart = data.get('chart', {})
        results = chart.get('result', [])

        if not results:
            result['status'] = 'limited'
            result['message'] = 'No corporate action data available'
            return result

        r = results[0]
        events = r.get('events', {})

        # Dividends
        dividends = events.get('dividends', {})
        if dividends:
            result['dividends'] = []
            for ts, div_data in sorted(dividends.items(), reverse=True)[:5]:
                result['dividends'].append({
                    'date': datetime.fromtimestamp(int(ts)).isoformat(),
                    'amount': _safe_float(div_data.get('amount'))
                })

            # Latest dividend
            if result['dividends']:
                result['last_dividend_date'] = result['dividends'][0]['date']
                result['last_dividend_amount'] = result['dividends'][0]['amount']

        # Splits
        splits = events.get('splits', {})
        if splits:
            result['splits'] = []
            for ts, split_data in sorted(splits.items(), reverse=True)[:5]:
                num = split_data.get('numerator', 1)
                den = split_data.get('denominator', 1)
                result['splits'].append({
                    'date': datetime.fromtimestamp(int(ts)).isoformat(),
                    'ratio': '{}:{}'.format(int(num), int(den))
                })

            if result['splits']:
                result['last_split_date'] = result['splits'][0]['date']
                result['last_split_ratio'] = result['splits'][0]['ratio']

        result['status'] = 'ok' if (dividends or splits) else 'limited'
        if result['status'] == 'limited':
            result['message'] = 'Limited corporate action data available'

        return result

    except Exception as e:
        log_scraper_error('yahoo_direct', 'get_corporate_actions', symbol, e)
        result['error'] = str(e)
        return result


# ============================================================================
# Global Market Functions (replacements for scraper_global.py)
# ============================================================================

def get_india_vix() -> Dict[str, Any]:
    """
    Fetch India VIX

    Returns:
        Dictionary with VIX value and interpretation
    """
    data = get_chart_data('^INDIAVIX', period='5d', interval='1d')

    result = {
        'source': 'india_vix',
        'status': data.get('status', 'unavailable'),
        'timestamp': datetime.now().isoformat()
    }

    if data.get('status') != 'ok':
        result['error'] = data.get('error', 'Failed to fetch India VIX')
        return result

    vix_value = data.get('ltp')
    prev_value = data.get('prev_close')

    result['value'] = vix_value
    result['previous'] = prev_value
    result['change'] = data.get('change')
    result['change_pct'] = data.get('change_pct')

    # Fear level interpretation
    if vix_value:
        if vix_value > 25:
            result['fear_level'] = 'EXTREME'
            result['interpretation'] = 'Extreme fear in market - high volatility expected'
        elif vix_value > 20:
            result['fear_level'] = 'HIGH'
            result['interpretation'] = 'High fear - caution advised'
        elif vix_value > 15:
            result['fear_level'] = 'ELEVATED'
            result['interpretation'] = 'Elevated volatility - moderate caution'
        elif vix_value > 12:
            result['fear_level'] = 'NORMAL'
            result['interpretation'] = 'Normal market conditions'
        else:
            result['fear_level'] = 'LOW'
            result['interpretation'] = 'Low volatility - complacency risk'

    return result


def get_us_market_data() -> Dict[str, Any]:
    """
    Fetch US market data (S&P500, NASDAQ, VIX, DXY, USD/INR, 10Y)

    Returns:
        Dictionary with US market indicators
    """
    tickers = {
        'sp500': '^GSPC',
        'nasdaq': '^IXIC',
        'us_vix': '^VIX',
        'dxy': 'DX-Y.NYB',
        'usdinr': 'USDINR=X',
        'us_10y': '^TNX'
    }

    result = {
        'source': 'us_markets',
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat(),
        'data': {}
    }

    success_count = 0

    for name, ticker in tickers.items():
        data = get_chart_data(ticker, period='2d', interval='1d')

        if data.get('status') == 'ok':
            result['data'][name] = {
                'value': data.get('ltp'),
                'previous': data.get('prev_close'),
                'change': data.get('change'),
                'change_pct': data.get('change_pct')
            }
            success_count += 1
        else:
            result['data'][name] = {'status': 'error', 'error': data.get('error')}

    if success_count > 0:
        result['status'] = 'ok'

        # Generate interpretations
        interpretations = []

        sp500 = result['data'].get('sp500', {})
        if sp500.get('change_pct'):
            pct = sp500['change_pct']
            if pct > 1:
                interpretations.append('S&P500 strongly positive - bullish global sentiment')
            elif pct < -1:
                interpretations.append('S&P500 strongly negative - bearish global sentiment')

        us_vix = result['data'].get('us_vix', {})
        if us_vix.get('value') and us_vix['value'] > 25:
            interpretations.append('US VIX elevated - global risk-off mode')

        dxy = result['data'].get('dxy', {})
        if dxy.get('change_pct'):
            dxy_chg = dxy['change_pct']
            if dxy_chg > 0.5:
                interpretations.append('Dollar strengthening - may pressure EM markets')
            elif dxy_chg < -0.5:
                interpretations.append('Dollar weakening - positive for EM flows')

        usdinr = result['data'].get('usdinr', {})
        if usdinr.get('change_pct'):
            inr_chg = usdinr['change_pct']
            if inr_chg > 0.3:
                interpretations.append('INR weakening - positive for IT exporters')
            elif inr_chg < -0.3:
                interpretations.append('INR strengthening - may impact export earnings')

        result['interpretations'] = interpretations

    return result


def get_commodity_prices(commodities: List[str]) -> Dict[str, Any]:
    """
    Fetch commodity prices for correlation analysis

    Args:
        commodities: List of commodity tickers (e.g., ['CL=F', 'GC=F'])

    Returns:
        Dictionary with commodity prices and trends
    """
    # Commodity ticker descriptions
    COMMODITY_NAMES = {
        'CL=F': 'Crude Oil',
        'NG=F': 'Natural Gas',
        'GC=F': 'Gold',
        'SI=F': 'Silver',
        'HG=F': 'Copper',
        'ALI=F': 'Aluminum',
        'ZNC=F': 'Zinc',
        'BTU': 'Coal (Peabody)',
        'SLX': 'Steel ETF',
        'VALE': 'Iron Ore (Vale)',
        'CT=F': 'Cotton',
        'ZS=F': 'Soybean',
        'SB=F': 'Sugar',
        'USDINR=X': 'USD/INR',
        '^TNX': 'US 10Y Yield',
    }

    result = {
        'source': 'commodities',
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat()
    }

    if not commodities:
        result['status'] = 'ok'
        result['data'] = {}
        result['message'] = 'No commodities mapped for this stock'
        return result

    data = {}
    success_count = 0

    for ticker in commodities:
        chart_data = get_chart_data(ticker, period='5d', interval='1d')

        if chart_data.get('status') == 'ok':
            entry = {
                'name': COMMODITY_NAMES.get(ticker, ticker),
                'ticker': ticker,
                'value': chart_data.get('ltp'),
                'previous': chart_data.get('prev_close'),
                'change': chart_data.get('change'),
                'change_pct': chart_data.get('change_pct')
            }

            # Determine trend
            change_pct = chart_data.get('change_pct')
            if change_pct is not None:
                if change_pct > 2:
                    entry['trend'] = 'STRONG_UP'
                elif change_pct > 0.5:
                    entry['trend'] = 'UP'
                elif change_pct < -2:
                    entry['trend'] = 'STRONG_DOWN'
                elif change_pct < -0.5:
                    entry['trend'] = 'DOWN'
                else:
                    entry['trend'] = 'FLAT'

            data[ticker] = entry
            success_count += 1
        else:
            data[ticker] = {
                'name': COMMODITY_NAMES.get(ticker, ticker),
                'status': 'error',
                'error': chart_data.get('error')
            }

    result['data'] = data
    if success_count > 0:
        result['status'] = 'ok'

    return result


def get_sector_index(sector_symbol: str) -> Dict[str, Any]:
    """
    Fetch sector index performance

    Args:
        sector_symbol: Sector index symbol (e.g., '^CNXIT', '^NSEBANK')

    Returns:
        Dictionary with sector index data
    """
    result = {
        'source': 'sector_index',
        'status': 'unavailable',
        'timestamp': datetime.now().isoformat(),
        'sector_symbol': sector_symbol
    }

    if not sector_symbol:
        result['message'] = 'No sector index mapped for this stock'
        return result

    data = get_chart_data(sector_symbol, period='5d', interval='1d')

    if data.get('status') != 'ok':
        result['error'] = data.get('error', 'Failed to fetch sector index')
        return result

    result['status'] = 'ok'
    result['value'] = data.get('ltp')
    result['previous'] = data.get('prev_close')
    result['change'] = data.get('change')
    result['change_pct'] = data.get('change_pct')

    # Performance interpretation
    change_pct = data.get('change_pct')
    if change_pct is not None:
        if change_pct > 2:
            result['performance'] = 'STRONG_OUTPERFORM'
        elif change_pct > 0.5:
            result['performance'] = 'OUTPERFORM'
        elif change_pct < -2:
            result['performance'] = 'STRONG_UNDERPERFORM'
        elif change_pct < -0.5:
            result['performance'] = 'UNDERPERFORM'
        else:
            result['performance'] = 'INLINE'

    return result


# ============================================================================
# Testing
# ============================================================================

if __name__ == '__main__':
    import json

    print("Testing Yahoo Direct API...")
    print("=" * 50)

    # Test 1: Quick Quote
    print("\n1. Quick Quote (RELIANCE):")
    quote = get_quick_quote('RELIANCE')
    print("Status:", quote.get('status'))
    print("LTP:", quote.get('ltp'))
    print("Change:", quote.get('change_pct'), "%")

    # Test 2: India VIX
    print("\n2. India VIX:")
    vix = get_india_vix()
    print("Status:", vix.get('status'))
    print("Value:", vix.get('value'))
    print("Fear Level:", vix.get('fear_level'))

    # Test 3: US Markets
    print("\n3. US Markets:")
    us = get_us_market_data()
    print("Status:", us.get('status'))
    for key, val in us.get('data', {}).items():
        if val.get('value'):
            print("  {}: {} ({:+.2f}%)".format(key, val['value'], val.get('change_pct', 0)))

    # Test 4: Historical Data
    print("\n4. Historical Data (TCS, 1Y):")
    hist = get_historical_data('TCS', '1y')
    print("Status:", hist.get('status'))
    print("Data points:", hist.get('data_points'))
    if hist.get('summary'):
        print("Period return:", hist['summary'].get('period_return'), "%")

    # Test 5: Commodities
    print("\n5. Commodities (Crude, Gold):")
    comm = get_commodity_prices(['CL=F', 'GC=F'])
    print("Status:", comm.get('status'))
    for ticker, data in comm.get('data', {}).items():
        if data.get('value'):
            print("  {}: {} ({})".format(data.get('name'), data['value'], data.get('trend')))

    print("\n" + "=" * 50)
    print("All tests completed!")
