import json
from warnings import warn
from dynamix_sdk import config
from dynamix_sdk.exceptions import IncompatibleAPIError
from dynamix_sdk.utils import F_DECORATOR
from .api import API


class Dynamix:
    _config: config.ConfigWithAuth
    _COMPATIBLE_DX_BUILD = 1145
    _dx_build: int

    def __init__(
        self,
        *,
        url: str,
        auth: str | config.AuthenticatorProtocol,
        verify_ssl: bool = True,
        http503_attempts: int = 10,
        http503_attempts_interval: int = 5,
        result_extra_allow: bool = False,
        ignore_api_compatibility: bool = False,
        wrap_request_exceptions: bool = False,
        f_decorators: list[F_DECORATOR] | None = None,
    ):
        self._config = config.ConfigWithAuth(
            base_api_path='/restmachine',
            url=url,
            auth=auth,
            verify_ssl=verify_ssl,
            http503_attempts=http503_attempts,
            http503_attempts_interval=http503_attempts_interval,
            result_extra_allow=result_extra_allow,
            wrap_request_exceptions=wrap_request_exceptions,
            f_decorators=f_decorators,
        )
        self._dx_build = self._get_dx_build()
        self._check_dx_compatibility(ignore_api_compatibility)

    @property
    def api(self):
        return API(config=self._config)

    @property
    def compatible_dx_build(self) -> int:
        return self._COMPATIBLE_DX_BUILD

    @property
    def dx_build(self) -> int:
        return self._dx_build

    def _get_dx_build(self) -> int:
        result = self.api.system.info.version()
        dx_build = json.loads(result.replace("'", '"'))['build']
        if not isinstance(dx_build, int):
            raise TypeError(f'DX build must be an int, got {type(dx_build)}')
        return dx_build

    def _check_dx_compatibility(self, ignore_api_compatibility: bool):
        if self.dx_build != self.compatible_dx_build:
            message = (
                f'Incompatible Dynamix build. '
                f'Dynamix build: {self.dx_build}. '
                f'Compatible build: {self.compatible_dx_build}'
            )
            if ignore_api_compatibility:
                warn(message=message)
            else:
                raise IncompatibleAPIError(message=message)
