"""Continuous front-month-input futures fetch for the trend hedge sleeve — Databento GLBX ohlcv-1d, parent
symbology, written as <data_dir>/<ROOT>.dbn (LocalDbnLoader builds the continuous series from these).

Ported from foxhunt scripts/surfer/fetch_daily.py. Preserves the hard-won cost discipline: estimate
get_cost (free, no download) and refuse any root over the per-root cap or any fetch that would breach the
cumulative cap BEFORE downloading. The Databento client is injected so tests exercise the gates with no
network and no spend. A runaway download once cost $3.5k — the gate is non-negotiable."""
from __future__ import annotations

import logging
import os
import time
from typing import Any

_log = logging.getLogger(__name__)

DATASET = "GLBX.MDP3"
SCHEMA = "ohlcv-1d"
STYPE = "parent"
DEFAULT_ROOTS = ["ES", "NQ", "YM", "RTY", "ZN", "ZB", "ZF", "ZT", "6E", "6J", "6B", "6A",
                 "6C", "GC", "SI", "HG", "CL", "NG", "RB", "ZC", "ZS", "ZW"]


def _default_client() -> Any:
    import databento as db
    key = os.environ.get("DATABENTO_API_KEY")
    if not key:
        raise RuntimeError("DATABENTO_API_KEY not set (required for --futures)")
    return db.Historical(key)


def fetch_futures(data_dir: str, *, roots: list[str] | None = None, start: str = "2010-06-06",
                  end: str = "", max_cost_usd: float = 40.0, per_root_cap_usd: float = 10.0,
                  client: Any | None = None) -> tuple[int, int, float]:
    """Fetch per-root ohlcv-1d DBN into <data_dir>/<ROOT>.dbn under cost caps. Returns (records, roots_ok,
    spent_usd). `end` defaults to today clamped to the dataset's available range."""
    import datetime as dt

    roots = roots or DEFAULT_ROOTS
    client = client or _default_client()
    end = end or dt.date.today().isoformat()
    try:                                                   # clamp END to dataset range (GLBX lags 1-3d)
        avail = (client.metadata.get_dataset_range(dataset=DATASET).get("end") or "")[:10]
        if avail:
            end = min(end, avail)
    except Exception as e:                                 # noqa: BLE001 — clamp is best-effort
        _log.warning("dataset range clamp failed: %s", e)
    os.makedirs(data_dir, exist_ok=True)

    total_recs, spent, ok = 0, 0.0, 0
    for r in roots:
        sym = f"{r}.FUT"
        try:
            c_r = client.metadata.get_cost(dataset=DATASET, symbols=[sym], schema=SCHEMA,
                                           start=start, end=end, stype_in=STYPE)
        except Exception as e:                             # noqa: BLE001
            _log.warning("%s: get_cost failed (%s); skip", r, e)
            continue
        if c_r > per_root_cap_usd or spent + c_r > max_cost_usd:
            _log.warning("%s: cost $%.4f would breach cap (spent $%.2f); skip", r, c_r, spent)
            continue
        for attempt in range(1, 4):
            try:
                data = client.timeseries.get_range(dataset=DATASET, symbols=[sym], schema=SCHEMA,
                                                   start=start, end=end, stype_in=STYPE)
                data.to_file(os.path.join(data_dir, f"{r}.dbn"))
                total_recs += sum(1 for _ in data)
                spent += c_r
                ok += 1
                break
            except Exception as e:                         # noqa: BLE001
                _log.warning("%s: attempt %d failed (%s)", r, attempt, e)
                time.sleep(3)
    _log.info("futures fetch: %d/%d roots, %d records, $%.2f", ok, len(roots), total_recs, spent)
    return total_recs, ok, spent
