# GENERATED BY Accumulate gen-sdk. DO NOT EDIT.

"""JSON-RPC 2.0 client implementation"""

import json
import random
from typing import Any, Dict, List, Optional

import requests


class JsonRpcException(Exception):
    """JSON-RPC error exception"""

    def __init__(self, message: str, code: Optional[int] = None, data: Any = None):
        super().__init__(message)
        self.code = code
        self.data = data

    def __str__(self) -> str:
        if self.code is not None:
            return f"JsonRpcException({self.code}): {super().__str__()}"
        return f"JsonRpcException: {super().__str__()}"


class JsonRpcClient:
    """JSON-RPC 2.0 client"""

    def __init__(self, server_url: str, *, timeout: Optional[float] = None):
        """Initialize the client

        Args:
            server_url: The JSON-RPC endpoint URL
            timeout: Request timeout in seconds (default: 30)
        """
        self._server_url = server_url
        self.host = server_url  # Public attribute for compatibility
        self._timeout = timeout or 30.0
        self._session = requests.Session()

    def call(self, method: str, params: Any = None) -> Any:
        """Make a JSON-RPC call

        Args:
            method: The RPC method name
            params: The method parameters

        Returns:
            The result from the RPC call

        Raises:
            JsonRpcException: If the RPC call fails
        """
        request_id = random.randint(1, 1000000)
        request_data = {
            "jsonrpc": "2.0",
            "method": method,
            "id": request_id,
        }
        if params is not None:
            request_data["params"] = params

        try:
            response = self._session.post(
                self._server_url,
                json=request_data,
                headers={"Content-Type": "application/json"},
                timeout=self._timeout,
            )
            if response.status_code != 200:
                raise JsonRpcException(
                    f"HTTP {response.status_code}: {response.reason}",
                    code=response.status_code,
                )

            response_data = response.json()
        except requests.exceptions.RequestException as e:
            raise JsonRpcException(f"HTTP request failed: {e}")
        except json.JSONDecodeError as e:
            raise JsonRpcException(f"Invalid JSON response: {e}")

        if "error" in response_data:
            error = response_data["error"]
            raise JsonRpcException(
                error.get("message", "Unknown error"),
                code=error.get("code"),
                data=error.get("data"),
            )

        return response_data.get("result")

    def batch(self, requests_list: List[Dict[str, Any]]) -> List[Any]:
        """Make a batch JSON-RPC call

        Args:
            requests_list: List of request dictionaries with 'method' and optional 'params'

        Returns:
            List of results from the RPC calls

        Raises:
            JsonRpcException: If any RPC call fails
        """
        batch_request = []
        for i, req in enumerate(requests_list):
            request_data = {
                "jsonrpc": "2.0",
                "method": req["method"],
                "id": i,
            }
            if "params" in req:
                request_data["params"] = req["params"]
            batch_request.append(request_data)

        try:
            response = self._session.post(
                self._server_url,
                json=batch_request,
                headers={"Content-Type": "application/json"},
                timeout=self._timeout,
            )
            if response.status_code != 200:
                raise JsonRpcException(
                    f"HTTP {response.status_code}: {response.reason}",
                    code=response.status_code,
                )

            response_data = response.json()
        except requests.exceptions.RequestException as e:
            raise JsonRpcException(f"HTTP request failed: {e}")
        except json.JSONDecodeError as e:
            raise JsonRpcException(f"Invalid JSON response: {e}")

        results = []
        for item in response_data:
            if "error" in item:
                error = item["error"]
                raise JsonRpcException(
                    error.get("message", "Unknown error"),
                    code=error.get("code"),
                    data=error.get("data"),
                )
            results.append(item.get("result"))

        return results

    def close(self) -> None:
        """Close the HTTP session"""
        self._session.close()

    # Core API methods for compatibility with test expectations
    def status(self) -> Dict[str, Any]:
        """Get network status"""
        return self.call("status")

    def version(self) -> Dict[str, Any]:
        """Get node version"""
        return self.call("version")

    def describe(self) -> Dict[str, Any]:
        """Get network description"""
        return self.call("describe")

    def metrics(self) -> Dict[str, Any]:
        """Get network metrics"""
        return self.call("metrics")

    def query(self, scope: str, query: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """Execute a query"""
        params = {"scope": scope}
        if query:
            params.update(query)
        return self.call("query", params)

    def submit(self, envelope: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Submit a transaction"""
        result = self.call("submit", {"envelope": envelope})
        return [result] if not isinstance(result, list) else result

    def faucet(self, account: str) -> Dict[str, Any]:
        """Request tokens from faucet"""
        return self.call("faucet", {"account": account})

    def query_tx(self, txid: str) -> Dict[str, Any]:
        """Query transaction by ID"""
        return self.call("query-tx", {"txid": txid})

    def query_directory(self, url: str) -> Dict[str, Any]:
        """Query directory"""
        return self.call("query-directory", {"url": url})

    def query_data(self, url: str) -> Dict[str, Any]:
        """Query data"""
        return self.call("query-data", {"url": url})

    def execute(self, envelope: Dict[str, Any]) -> Dict[str, Any]:
        """Execute a transaction"""
        return self.call("execute", {"envelope": envelope})

    def node_info(self) -> Dict[str, Any]:
        """Get node information"""
        return self.call("node-info")

    def network_status(self) -> Dict[str, Any]:
        """Get network status"""
        return self.call("network-status")

    def find_service(self) -> Dict[str, Any]:
        """Find service"""
        return self.call("find-service")

    def consensus_status(self) -> Dict[str, Any]:
        """Get consensus status"""
        return self.call("consensus-status")

    def list_snapshots(self) -> List[Dict[str, Any]]:
        """List snapshots"""
        return self.call("list-snapshots")

    def query_tx_local(self, txid: str) -> Dict[str, Any]:
        """Query transaction locally"""
        return self.call("query-tx-local", {"txid": txid})

    def query_tx_history(self, url: str) -> Dict[str, Any]:
        """Query transaction history"""
        return self.call("query-tx-history", {"url": url})

    def query_data_set(self, url: str) -> Dict[str, Any]:
        """Query data set"""
        return self.call("query-data-set", {"url": url})

    def query_key_page_index(self, url: str, key: str) -> Dict[str, Any]:
        """Query key page index"""
        return self.call("query-key-page-index", {"url": url, "key": key})

    def query_minor_blocks(self, url: str) -> Dict[str, Any]:
        """Query minor blocks"""
        return self.call("query-minor-blocks", {"url": url})

    def query_major_blocks(self, url: str) -> Dict[str, Any]:
        """Query major blocks"""
        return self.call("query-major-blocks", {"url": url})

    def query_synth(self, source: str, destination: str) -> Dict[str, Any]:
        """Query synthetic transactions"""
        return self.call("query-synth", {"source": source, "destination": destination})

    def validate(self, envelope: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Validate a transaction"""
        result = self.call("validate", {"envelope": envelope})
        return [result] if not isinstance(result, list) else result

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
