from __future__ import annotations

from dataclasses import asdict
import json
import time
from pathlib import Path
from typing import Any

from src.ctb_copy.models import VaultSnapshot
from src.hyperliquid.market_data import HyperliquidMarketData, ReadOnlyTransport


class HyperliquidVaultCollector:
    """Read-only vault snapshot collector.

    Uses the Hyperliquid Info endpoint transport only. It stores discovery-time
    snapshots so future scoring is based on observed-forward performance rather
    than today's survivor leaderboard.
    """

    def __init__(self, env: str | None = None, transport: ReadOnlyTransport | None = None) -> None:
        self.market = HyperliquidMarketData(env=env, transport=transport)

    def collect_vault_summaries(self, observed_at_ms: int | None = None) -> list[VaultSnapshot]:
        observed = observed_at_ms or int(time.time() * 1000)
        payload = self.market._post({"type": "vaultSummaries"})
        if not isinstance(payload, list):
            raise ValueError("vaultSummaries response must be a list")
        snapshots: list[VaultSnapshot] = []
        for idx, row in enumerate(payload):
            if row is None:
                continue
            vault_id = str(row.get("vaultAddress") or row.get("address") or row.get("name") or f"vault_{idx}")
            snapshots.append(VaultSnapshot(vault_id=vault_id, observed_at_ms=observed, source="hyperliquid_info:vaultSummaries", raw=dict(row)))
        return snapshots

    def collect_vault_detail(self, vault_address: str, observed_at_ms: int | None = None) -> VaultSnapshot:
        observed = observed_at_ms or int(time.time() * 1000)
        payload = self.market._post({"type": "vaultDetails", "vaultAddress": vault_address})
        if not isinstance(payload, dict):
            raise ValueError("vaultDetails response must be an object")
        return VaultSnapshot(vault_id=vault_address, observed_at_ms=observed, source="hyperliquid_info:vaultDetails", raw=dict(payload))

    def write_jsonl(self, snapshots: list[VaultSnapshot], path: str | Path) -> Path:
        target = Path(path)
        target.parent.mkdir(parents=True, exist_ok=True)
        with target.open("a", encoding="utf-8") as f:
            for snapshot in snapshots:
                f.write(json.dumps(asdict(snapshot), sort_keys=True) + "\n")
        return target
