from __future__ import annotations

import json
from pathlib import Path
from typing import Any

import httpx


class SpecLoadError(RuntimeError):
    pass


def load_spec_with_cache(openapi_url: str, cache_path: Path, timeout_seconds: float) -> tuple[dict[str, Any], str]:
    cache_path.parent.mkdir(parents=True, exist_ok=True)

    try:
        with httpx.Client(timeout=timeout_seconds) as client:
            response = client.get(openapi_url)
            response.raise_for_status()
            spec = response.json()
        cache_path.write_text(json.dumps(spec, indent=2), encoding="utf-8")
        return spec, "remote"
    except Exception as remote_error:
        if cache_path.exists():
            try:
                cached = json.loads(cache_path.read_text(encoding="utf-8"))
                return cached, "cache"
            except Exception as cache_error:
                raise SpecLoadError(
                    f"Failed to load remote spec ({remote_error}) and failed to parse cached spec ({cache_error})."
                ) from cache_error
        raise SpecLoadError(f"Failed to load remote spec and cache does not exist: {remote_error}") from remote_error
