"""HTTP client for communicating with the HiveCompute coordinator."""

from __future__ import annotations

import httpx
import structlog

from hive_compute.models import ComputeJob

logger = structlog.get_logger()


class CoordinatorClient:
    """Pull-based client for the HiveCompute coordinator API."""

    def __init__(self, base_url: str, worker_token: str, worker_id: str):
        self.base_url = base_url.rstrip("/")
        self.worker_id = worker_id
        self.headers = {
            "Authorization": f"Bearer {worker_token}",
            "X-Worker-ID": worker_id,
        }
        self.client = httpx.Client(base_url=self.base_url, headers=self.headers, timeout=30)

    def pull_job(self, job_types: list[str]) -> ComputeJob | None:
        """Poll for the next available job or shard. Returns None if no work."""
        try:
            resp = self.client.get(
                "/api/v1/workers/poll",
                params={"types": ",".join(job_types)},
            )
            if resp.status_code == 204:
                return None
            resp.raise_for_status()
            data = resp.json()
            return ComputeJob(
                id=data["job_id"],
                job_type=data["job_type"],
                input_url=data["audio_url"],
                input_data=data.get("input_config", {}),
                timeout_seconds=data.get("timeout_seconds", 3600),
                shard_id=data.get("shard_id"),
                start_seconds=data.get("start_seconds"),
                end_seconds=data.get("end_seconds"),
            )
        except httpx.HTTPStatusError as e:
            logger.warning("Failed to pull job", status=e.response.status_code)
            return None
        except Exception as e:
            logger.warning("Error pulling job", error=str(e))
            return None

    def heartbeat(self, job_id: str, shard_id: str | None = None) -> bool:
        """Send heartbeat for a claimed job or shard."""
        try:
            params = {"shard_id": shard_id} if shard_id else {}
            resp = self.client.post(f"/api/v1/jobs/{job_id}/heartbeat", params=params)
            return resp.status_code == 200
        except Exception:
            return False

    def push_result(self, job_id: str, result: dict, shard_id: str | None = None) -> bool:
        """Push completed result back to coordinator."""
        try:
            params = {"shard_id": shard_id} if shard_id else {}
            resp = self.client.post(f"/api/v1/jobs/{job_id}/result", json=result, params=params)
            resp.raise_for_status()
            logger.info("Result pushed", job_id=job_id, shard_id=shard_id)
            return True
        except Exception as e:
            logger.error("Failed to push result", job_id=job_id, error=str(e))
            return False

    def report_failure(self, job_id: str, error: str, shard_id: str | None = None) -> bool:
        """Report job or shard failure."""
        try:
            params = {"shard_id": shard_id} if shard_id else {}
            resp = self.client.post(f"/api/v1/jobs/{job_id}/fail", json={"error": error}, params=params)
            return resp.status_code == 200
        except Exception:
            return False

    def release_job(self, job_id: str, shard_id: str | None = None, reason: str = "worker_release") -> bool:
        """Release a claimed job or shard that was prefetched but not processed."""
        try:
            params = {"reason": reason}
            if shard_id:
                params["shard_id"] = shard_id
            resp = self.client.post(f"/api/v1/jobs/{job_id}/release", params=params)
            return resp.status_code == 200
        except Exception:
            return False

    def update_worker(self, info: dict) -> dict | None:
        """Update worker info on daemon startup (uses worker token auth)."""
        try:
            resp = self.client.put("/api/v1/workers/me", json=info)
            resp.raise_for_status()
            return resp.json()
        except Exception as e:
            logger.warning("Failed to update worker info", error=str(e))
            return None

    def fetch_pending_payout(self) -> float | None:
        """Return this worker's currently held payout balance in USD, or None on failure."""
        try:
            resp = self.client.get("/api/v1/workers/me/payouts")
            resp.raise_for_status()
            data = resp.json()
            return float(data.get("pending_usd", 0))
        except Exception:
            return None

    def report_benchmark(self, report: dict) -> bool:
        """Upload local benchmark results to the coordinator."""
        try:
            resp = self.client.post("/api/v1/workers/me/benchmarks", json=report)
            resp.raise_for_status()
            return True
        except Exception as exc:
            logger.warning("Failed to report benchmark", error=str(exc))
            return False


def build_coordinator_client(config: dict) -> CoordinatorClient:
    """Build an authenticated coordinator client from worker config."""
    from hive_compute.worker.keychain import resolve_worker_token as load_credential

    return CoordinatorClient(
        config["coordinator_url"],
        load_credential(config),
        config["worker_id"],
    )
