"""Mock yfinance OHLCV data for eval runs -- no network calls."""

from __future__ import annotations

import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone

# Symbols we provide mock OHLCV for
MOCK_OHLCV_SYMBOLS = {"AAPL", "TSLA", "GOOG", "MSFT", "NVDA", "SPY", "VIX"}

# Realistic last prices for synthesis
MOCK_LAST_CLOSE = {
    "AAPL": 187.50,
    "TSLA": 248.00,
    "GOOG": 142.00,
    "MSFT": 415.00,
    "NVDA": 875.00,
    "SPY": 545.00,
    "VIX": 16.50,
}


def _make_mock_ohlcv_df(symbol: str, num_days: int = 252) -> pd.DataFrame:
    """Build a DataFrame with Open, High, Low, Close, Volume for indicator computation."""
    base = MOCK_LAST_CLOSE.get(symbol, 100.0)
    today_utc = pd.Timestamp(datetime.now(timezone.utc).date())
    dates = pd.date_range(end=today_utc, periods=num_days, freq="B")
    if dates[-1] < today_utc:
        dates = dates.append(pd.DatetimeIndex([today_utc]))
    actual_len = len(dates)
    np.random.seed(hash(symbol) % 2**32)
    returns = np.random.randn(actual_len) * 0.01
    close = base * np.exp(np.cumsum(returns))
    close = np.maximum(close, base * 0.5)
    # Pin last close to canonical price so ground-truth checks are stable
    close[-1] = base
    open_ = np.roll(close, 1)
    open_[0] = close[0] * 0.99
    high = np.maximum(open_, close) * (1 + np.abs(np.random.randn(actual_len)) * 0.005)
    low = np.minimum(open_, close) * (1 - np.abs(np.random.randn(actual_len)) * 0.005)
    volume = (np.random.rand(actual_len) * 1e7 + 5e6).astype(int)
    df = pd.DataFrame(
        {
            "Open": open_,
            "High": high,
            "Low": low,
            "Close": close,
            "Volume": volume,
        },
        index=dates,
    )
    df.index.name = "Date"
    return df


def mock_fetch_with_retry(
    symbols: list[str], period: str, interval: str, max_retries: int = 3
) -> dict[str, pd.DataFrame]:
    """Returns mock DataFrames for the given symbols."""
    result: dict[str, pd.DataFrame] = {}
    num_days = 252
    if period in ("1d", "5d"):
        num_days = 5
    elif "d" in period:
        try:
            num_days = min(252, int(period.replace("d", "")))
        except ValueError:
            num_days = 60
    for symbol in symbols:
        sym_upper = (symbol or "").strip().upper()
        if sym_upper in MOCK_OHLCV_SYMBOLS or not sym_upper:
            result[symbol] = _make_mock_ohlcv_df(sym_upper or "AAPL", num_days=num_days)
        else:
            result[symbol] = _make_mock_ohlcv_df("AAPL", num_days=num_days)
    return result
