# This file was generated by ModelOS
import json
import os
import typing
from pathlib import Path
from typing import Type
from urllib import request

import modelos.object.kind
from lib_programname import get_path_executed_script
from modelos import Client
from modelos.object.encoding import deep_isinstance, json_is_type_match
from modelos.object.opts import Opts, OptsBuilder

if get_path_executed_script() == Path(os.path.dirname(__file__)).joinpath(
    Path("store.py")
):
    import __main__ as store  # type: ignore # noqa


class KVStoreClient(Client):
    """A resource client for KVStore"""

    uri: str = "aunum/mdl-test:kvstore-e17cfed-38b3e99"

    def __init__(self, data_uri: str, **kwargs) -> None:
        """Create a KV store

        Args:
            data_uri (str): URI of immutable data to fetch
        """
        ClientOpts = OptsBuilder[Opts].build(self.__class__)
        opts = ClientOpts(data_uri=data_uri)
        super().__init__(opts=opts, **kwargs)

    def get(self, uid: str) -> str:
        """Get a key

        Args:
            uid (str): UID to get

        Returns:
            str: Value
        """

        _params = json.dumps({"uid": uid}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/get",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: str
        _ret = _jdict

        return _ret

    def health(self) -> typing.Dict[str, str]:
        """Health of the resource

        Returns:
            Dict[str, Any]: Resource health
        """

        _params = json.dumps({}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/health",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: typing.Dict[str, str]
        # code for arg: typing.Dict[str, str]
        if not json_is_type_match(typing.Dict[str, str], _jdict):
            raise ValueError("JSON returned does not match type: typing.Dict[str, str]")
        _ret = _jdict
        # end dict: typing.Dict[str, str]

        return _ret

    def info(self) -> modelos.object.kind.ObjectInfo:
        """Info about the resource

        Returns:
            Dict[str, Any]: Resource info
        """

        _params = json.dumps({}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/info",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: modelos.object.kind.ObjectInfo
        # code for object: <class 'modelos.object.kind.ObjectInfo'>
        if not json_is_type_match(modelos.object.kind.ObjectInfo, _jdict):
            raise ValueError(
                "JSON returned does not match type: modelos.object.kind.ObjectInfo"
            )
        _ret_obj = object.__new__(modelos.object.kind.ObjectInfo)  # type: ignore
        _name = _jdict["name"]
        setattr(_ret_obj, "name", _name)

        _version = _jdict["version"]
        setattr(_ret_obj, "version", _version)

        _env_sha = _jdict["env_sha"]
        setattr(_ret_obj, "env_sha", _env_sha)

        _uri = _jdict["uri"]
        setattr(_ret_obj, "uri", _uri)

        _server_entrypoint = _jdict["server_entrypoint"]
        setattr(_ret_obj, "server_entrypoint", _server_entrypoint)

        _locked = _jdict["locked"]
        setattr(_ret_obj, "locked", _locked)

        _ext = _jdict["ext"]
        # code for union: typing.Optional[typing.Dict[str, str]]
        if json_is_type_match(typing.Dict[str, str], _ext):
            # code for arg: typing.Dict[str, str]
            _ret = _ext
            # end dict: typing.Dict[str, str]

        elif json_is_type_match(None, _ext):
            _ret = _ext
        else:
            raise ValueError(f"Unable to deserialize return value: {type(_ext)}")
        # end union: typing.Optional[typing.Dict[str, str]]

        setattr(_ret_obj, "ext", _ext)

        _ret = _ret_obj
        # end object: <class 'modelos.object.kind.ObjectInfo'>

        return _ret

    def lock(
        self, key: typing.Optional[str] = None, timeout: typing.Optional[int] = None
    ) -> None:
        """Lock the process to only operate with the caller

        Args:
            key (Optional[str], optional): An optional key to secure the lock
            timeout (Optional[int], optional): Whether to unlock after a set amount of time. Defaults to None.
        """
        # code for union: typing.Optional[str]
        if deep_isinstance(key, None):
            pass
        elif deep_isinstance(key, str):
            pass
        else:
            raise ValueError(
                "Do not know how to serialize "
                + "parameter 'key' "
                + f"of type '{type(key)}'"
            )
        # end union: typing.Optional[str]

        # code for union: typing.Optional[int]
        if deep_isinstance(timeout, None):
            pass
        elif deep_isinstance(timeout, int):
            pass
        else:
            raise ValueError(
                "Do not know how to serialize "
                + "parameter 'timeout' "
                + f"of type '{type(timeout)}'"
            )
        # end union: typing.Optional[int]

        _params = json.dumps({"key": key, "timeout": timeout}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/lock",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: None
        _ret = _jdict

        return _ret

    def save(self, out_dir: str = "./artifacts") -> None:
        """Save the object

        Args:
            out_dir (str, optional): Directory to output the artiacts. Defaults to "./artifacts".
        """

        _params = json.dumps({"out_dir": out_dir}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/save",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: None
        _ret = _jdict

        return _ret

    def unlock(self, key: typing.Optional[str] = None, force: bool = False) -> None:
        """Unlock the kind

        Args:
            key (Optional[str], optional): Key to unlock, if needed. Defaults to None.
            force (bool, optional): Force unlock without a key. Defaults to False.
        """
        # code for union: typing.Optional[str]
        if deep_isinstance(key, None):
            pass
        elif deep_isinstance(key, str):
            pass
        else:
            raise ValueError(
                "Do not know how to serialize "
                + "parameter 'key' "
                + f"of type '{type(key)}'"
            )
        # end union: typing.Optional[str]

        _params = json.dumps({"key": key, "force": force}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/unlock",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: None
        _ret = _jdict

        return _ret

    def labels(self) -> typing.Dict[str, str]:  # type: ignore
        """Labels for the resource

        Args:
            scm (Optional[SCM], optional): SCM to use. Defaults to None.

        Returns:
            Dict[str, Any]: Labels for the server
        """

        _params = json.dumps({}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/labels",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: typing.Dict[str, str]
        # code for arg: typing.Dict[str, str]
        if not json_is_type_match(typing.Dict[str, str], _jdict):
            raise ValueError("JSON returned does not match type: typing.Dict[str, str]")
        _ret = _jdict
        # end dict: typing.Dict[str, str]

        return _ret

    def name(self) -> str:  # type: ignore
        """Name of the resource

        Returns:
            str: Name of the server
        """

        _params = json.dumps({}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/name",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: str
        _ret = _jdict

        return _ret

    def short_name(self) -> str:  # type: ignore
        """Short name for the resource

        Returns:
            str: A short name
        """

        _params = json.dumps({}).encode("utf8")
        _headers = {"content-type": "application/json", "client-uuid": str(self.uid)}
        _req = request.Request(
            f"{self.server_addr}/short_name",
            data=_params,
            headers=_headers,
        )
        _resp = request.urlopen(_req)
        _data = _resp.read().decode("utf-8")
        _jdict = json.loads(_data)

        if _jdict is None:
            raise ValueError("recieved invalid response from server, check server logs")

        if "value" in _jdict:
            _jdict = _jdict["value"]

        _ret: str
        _ret = _jdict

        return _ret

    def _super_init(self, uri: str) -> None:
        super().__init__(uri)

    @classmethod
    def from_uri(cls: Type["KVStoreClient"], uri: str) -> "KVStoreClient":
        c = cls.__new__(cls)
        c._super_init(uri)
        return c
