from __future__ import annotations

import json
import os
import time
from pathlib import Path

import pytest

from historical_replay import fetch_hyperliquid_candles


class FakeResponse:
    def __init__(self, payload=None, status_error: Exception | None = None):
        self.payload = payload or []
        self.status_error = status_error

    def raise_for_status(self):
        if self.status_error:
            raise self.status_error

    def json(self):
        return self.payload


def _row(ts: int, close: float = 100.0):
    return {"t": ts * 1000, "o": str(close), "h": str(close), "l": str(close), "c": str(close), "v": "1"}


def test_fetch_hyperliquid_candles_retries_429_then_succeeds(tmp_path: Path):
    calls = []

    def request_post(*args, **kwargs):
        calls.append((args, kwargs))
        if len(calls) < 3:
            return FakeResponse(status_error=RuntimeError("429 Too Many Requests"))
        return FakeResponse(payload=[_row(1, 101)])

    sleeps = []
    rows = fetch_hyperliquid_candles(
        "BTC",
        interval="15m",
        hours_back=24,
        cache_dir=tmp_path,
        request_post=request_post,
        sleep_fn=sleeps.append,
        max_attempts=3,
    )

    assert len(calls) == 3
    assert sleeps == [1.0, 2.0]
    assert rows[0].close == 101.0


def test_fetch_hyperliquid_candles_uses_stale_cache_when_network_fails(tmp_path: Path):
    cache_file = tmp_path / "ETH_15m_24h.json"
    cache_file.write_text(json.dumps([_row(1, 99)]), encoding="utf-8")
    old = time.time() - 7200
    os.utime(cache_file, (old, old))

    def request_post(*args, **kwargs):
        raise RuntimeError("network down")

    rows = fetch_hyperliquid_candles(
        "ETH",
        interval="15m",
        hours_back=24,
        cache_dir=tmp_path,
        request_post=request_post,
        sleep_fn=lambda _: None,
        max_attempts=2,
        allow_stale_cache=True,
    )

    assert rows[0].close == 99.0


def test_fetch_hyperliquid_candles_raises_without_stale_cache(tmp_path: Path):
    def request_post(*args, **kwargs):
        raise RuntimeError("network down")

    with pytest.raises(RuntimeError):
        fetch_hyperliquid_candles(
            "SOL",
            interval="15m",
            hours_back=24,
            cache_dir=tmp_path,
            request_post=request_post,
            sleep_fn=lambda _: None,
            max_attempts=1,
            allow_stale_cache=False,
        )
