"""
Background tasks for the invest app.
"""
import logging
from decimal import Decimal

logger = logging.getLogger(__name__)


def snapshot_all_portfolios():
    """
    Capture a PortfolioSnapshot for every portfolio.
    Scheduled every Saturday at 08:00. Also callable manually for backfill.
    """
    from django.utils import timezone

    from .models import Portfolio, PortfolioSnapshot
    from .services import get_portfolio_value, refresh_benchmark_prices

    now = timezone.now()
    today = now.date()
    logger.info("invest: starting portfolio snapshot at %s", now)

    count = 0
    for portfolio in Portfolio.objects.prefetch_related('stocks').all():
        try:
            data = get_portfolio_value(portfolio)
            total_value = Decimal(str(data['total_value']))

            # One snapshot per portfolio per day — overwrite if run twice.
            PortfolioSnapshot.objects.filter(
                portfolio=portfolio,
                captured_at__date=today,
            ).delete()

            PortfolioSnapshot.objects.create(
                portfolio=portfolio,
                captured_at=now,
                total_value=total_value,
            )
            count += 1
            logger.info("invest: snapshot %s = $%.2f", portfolio.name, total_value)
        except Exception as exc:
            logger.error("invest: snapshot failed for %s: %s", portfolio.name, exc, exc_info=True)

    refresh_benchmark_prices()
    logger.info("invest: snapshot complete — %d portfolios", count)
    # Also refresh benchmark prices so the chart has up-to-date SPY/QQQ data
    refresh_benchmark_prices()


def refresh_benchmark_prices(tickers=None):
    """
    Fetch and cache daily closing prices for benchmark tickers (SPY, QQQ).
    Skips the fetch if data is already fresh (latest date within last 7 days).
    Called weekly alongside snapshot_all_portfolios.
    """
    import datetime as dt
    import yfinance as yf
    from .models import BenchmarkPrice

    if tickers is None:
        tickers = ['SPY', 'QQQ']

    today = dt.date.today()
    start = (today - dt.timedelta(days=365 * 2)).isoformat()  # 2 years of history
    end = (today + dt.timedelta(days=1)).isoformat()

    for ticker in tickers:
        latest = (
            BenchmarkPrice.objects.filter(ticker=ticker)
            .order_by('-date')
            .values_list('date', flat=True)
            .first()
        )
        if latest and (today - latest).days <= 7:
            logger.info("invest: benchmark %s is fresh (latest=%s), skipping", ticker, latest)
            continue

        try:
            hist = yf.Ticker(ticker).history(start=start, end=end)
            if hist.empty:
                logger.warning("invest: no data for benchmark %s", ticker)
                continue
            rows = []
            for d, v in hist['Close'].items():
                date_val = d.date() if hasattr(d, 'date') else d
                rows.append(BenchmarkPrice(ticker=ticker, date=date_val, close=round(float(v), 4)))
            BenchmarkPrice.objects.bulk_create(
                rows,
                update_conflicts=True,
                unique_fields=['ticker', 'date'],
                update_fields=['close'],
            )
            logger.info("invest: refreshed %d prices for %s (latest=%s)", len(rows), ticker, today)
        except Exception as exc:
            logger.error("invest: benchmark refresh failed for %s: %s", ticker, exc, exc_info=True)
