"""Yahoo Finance market data provider (unofficial API).

FREE - No API key required!
Uses yahooquery library which scrapes Yahoo Finance.
Great for development and testing.

Note: This is an unofficial API and may break without notice.
For production, consider Alpha Vantage or other official providers.
"""

from __future__ import annotations

from collections.abc import Sequence
from datetime import UTC, datetime
from decimal import Decimal

try:
    from yahooquery import Ticker

    HAS_YAHOOQUERY = True
except ImportError:  # pragma: no cover
    HAS_YAHOOQUERY = False
    Ticker = None

from ...models import Candle, Quote
from .base import MarketDataProvider


def _require_yahooquery() -> None:
    """Raise ImportError if yahooquery is not installed."""
    if not HAS_YAHOOQUERY:
        raise ImportError(
            "Yahoo Finance support requires the 'yahooquery' package. "
            "Install with: pip install fin-infra[yahoo] or pip install fin-infra[markets]"
        )


class YahooFinanceMarketData(MarketDataProvider):
    """Yahoo Finance provider (zero config, no API key needed).

    Features:
    - FREE - No API key required
    - Real-time quotes (15-min delay)
    - Historical OHLCV data
    - No rate limits (but be respectful)

    Limitations:
    - Unofficial API (may break)
    - No symbol search
    - Less reliable than official APIs

    Best for:
    - Development and testing
    - MVPs with no budget
    - Fallback when other providers are rate-limited
    """

    def __init__(self) -> None:
        """Initialize Yahoo Finance provider (no configuration needed)."""
        _require_yahooquery()

    def quote(self, symbol: str) -> Quote:
        """Get real-time quote for a symbol.

        Args:
            symbol: Stock ticker symbol (e.g., "AAPL", "MSFT")

        Returns:
            Quote with price and timestamp

        Raises:
            ValueError: Invalid symbol or no data
            Exception: Network or API errors
        """
        tk = Ticker(symbol, asynchronous=False)
        quotes = tk.quotes

        if isinstance(quotes, dict) and "error" in quotes:
            raise ValueError(f"Yahoo Finance error: {quotes['error']}")

        data = quotes.get(symbol)
        if not data:
            raise ValueError(f"No data returned for symbol: {symbol}")

        # Yahoo returns regularMarketPrice for current price
        price_raw = data.get("regularMarketPrice") or data.get("price")
        if price_raw is None:
            raise ValueError(f"No price data for symbol: {symbol}")

        price = Decimal(str(price_raw))

        # Get timestamp (use regularMarketTime or current time)
        ts_raw = data.get("regularMarketTime")
        if ts_raw:
            # Convert Unix timestamp to datetime
            as_of = datetime.fromtimestamp(ts_raw, tz=UTC)
        else:
            as_of = datetime.now(UTC)

        return Quote(
            symbol=symbol.upper(),
            price=price,
            as_of=as_of,
            currency=data.get("currency", "USD"),
        )

    def history(
        self, symbol: str, *, period: str = "1mo", interval: str = "1d"
    ) -> Sequence[Candle]:
        """Get historical OHLCV data.

        Args:
            symbol: Stock ticker symbol
            period: Time period ("1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max")
            interval: Data interval ("1m", "2m", "5m", "15m", "30m", "60m", "90m", "1h", "1d", "5d", "1wk", "1mo", "3mo")

        Returns:
            List of Candle objects (newest first)

        Raises:
            ValueError: Invalid symbol or period
            Exception: Network or API errors

        Note:
            Intraday data (1m, 5m, etc.) limited to last 7 days.
        """
        tk = Ticker(symbol, asynchronous=False)
        df = tk.history(period=period, interval=interval)

        if df is None or df.empty:
            return []

        # Reset index to access date column
        df = df.reset_index()

        candles: list[Candle] = []
        for _, row in df.iterrows():
            try:
                # Get timestamp
                date_val = row.get("date") or row.get("Date") or row.get("index")
                if date_val is None:
                    continue

                # Convert to datetime if needed
                if not isinstance(date_val, datetime):
                    # Try parsing as string
                    dt = datetime.fromisoformat(str(date_val))
                else:
                    dt = date_val

                # Ensure timezone aware
                if dt.tzinfo is None:
                    dt = dt.replace(tzinfo=UTC)

                ts_ms = int(dt.timestamp() * 1000)

                candles.append(
                    Candle(
                        ts=ts_ms,
                        open=Decimal(str(row.get("open", 0))),
                        high=Decimal(str(row.get("high", 0))),
                        low=Decimal(str(row.get("low", 0))),
                        close=Decimal(str(row.get("close", 0))),
                        volume=Decimal(str(row.get("volume", 0))),
                    )
                )
            except (ValueError, KeyError, TypeError):
                continue  # Skip malformed rows

        # Reverse to get newest first (Yahoo returns oldest first)
        return list(reversed(candles))
