"""zg_storage.node.zgs_kv module."""

from __future__ import annotations

from typing import Optional, Union

from ..rpc import RpcClient
from ..types import KeyValue, Value


class ZgsKvClient:
    """Client for KV node RPC endpoints.

    Purpose:
        Query KV values and metadata over `kv_*` RPC calls.
    Notes:
        Low-level client; higher-level helpers live in `zg_storage.kv`."""

    def __init__(self, url: str, timeout: float = 30.0) -> None:
        self._rpc = RpcClient(url, timeout=timeout)

    def get_value(
        self,
        stream_id: str,
        key: str,
        start_index: int,
        length: int,
        version: Optional[int] = None,
    ) -> Value:
        """Get a value by key with optional paging and version."""
        params = [stream_id, key, start_index, length]
        if version is not None:
            params.append(version)
        result = self._rpc.call("kv_getValue", params)
        return Value.model_validate(result)

    def get_next(
        self,
        stream_id: str,
        key: str,
        start_index: int,
        length: int,
        inclusive: bool,
        version: Optional[int] = None,
    ) -> Optional[KeyValue]:
        """Get the next key-value pair after the given key."""
        params = [stream_id, key, start_index, length, inclusive]
        if version is not None:
            params.append(version)
        result = self._rpc.call("kv_getNext", params)
        if result is None:
            return None
        return KeyValue.model_validate(result)

    def get_prev(
        self,
        stream_id: str,
        key: str,
        start_index: int,
        length: int,
        inclusive: bool,
        version: Optional[int] = None,
    ) -> Optional[KeyValue]:
        """Get the previous key-value pair before the given key."""
        params = [stream_id, key, start_index, length, inclusive]
        if version is not None:
            params.append(version)
        result = self._rpc.call("kv_getPrev", params)
        if result is None:
            return None
        return KeyValue.model_validate(result)

    def get_first(
        self,
        stream_id: str,
        start_index: int,
        length: int,
        version: Optional[int] = None,
    ) -> Optional[KeyValue]:
        """Get the first key-value pair in a stream."""
        params = [stream_id, start_index, length]
        if version is not None:
            params.append(version)
        result = self._rpc.call("kv_getFirst", params)
        if result is None:
            return None
        return KeyValue.model_validate(result)

    def get_last(
        self,
        stream_id: str,
        start_index: int,
        length: int,
        version: Optional[int] = None,
    ) -> Optional[KeyValue]:
        """Get the last key-value pair in a stream."""
        params = [stream_id, start_index, length]
        if version is not None:
            params.append(version)
        result = self._rpc.call("kv_getLast", params)
        if result is None:
            return None
        return KeyValue.model_validate(result)

    def get_transaction_result(self, tx_seq: int) -> str:
        return self._rpc.call("kv_getTransactionResult", [tx_seq])

    def get_holding_stream_ids(self) -> list[str]:
        return self._rpc.call("kv_getHoldingStreamIds")

    def has_write_permission(
        self,
        account: str,
        stream_id: str,
        key: str,
        version: Optional[int] = None,
    ) -> bool:
        """Check write permission for a key."""
        params = [account, stream_id, key]
        if version is not None:
            params.append(version)
        return self._rpc.call("kv_hasWritePermission", params)

    def is_admin(self, account: str, stream_id: str, version: Optional[int] = None) -> bool:
        """Check whether the account is an admin of the stream."""
        params = [account, stream_id]
        if version is not None:
            params.append(version)
        return self._rpc.call("kv_isAdmin", params)

    def is_special_key(self, stream_id: str, key: str, version: Optional[int] = None) -> bool:
        """Check whether the key is marked as special."""
        params = [stream_id, key]
        if version is not None:
            params.append(version)
        return self._rpc.call("kv_isSpecialKey", params)

    def is_writer_of_key(
        self,
        account: str,
        stream_id: str,
        key: str,
        version: Optional[int] = None,
    ) -> bool:
        """Check whether the account is a writer for the key."""
        params = [account, stream_id, key]
        if version is not None:
            params.append(version)
        return self._rpc.call("kv_isWriterOfKey", params)

    def is_writer_of_stream(
        self,
        account: str,
        stream_id: str,
        version: Optional[int] = None,
    ) -> bool:
        """Check whether the account is a writer for the stream."""
        params = [account, stream_id]
        if version is not None:
            params.append(version)
        return self._rpc.call("kv_isWriterOfStream", params)
