# This file was auto-generated by Fern from our API Definition.

import typing
from ..core.client_wrapper import SyncClientWrapper
from ..types.named_quantity import NamedQuantity
from ..types.parameter_bound import ParameterBound
from ..types.named_quantity_list import NamedQuantityList
from ..core.request_options import RequestOptions
from ..types.optimizer_result import OptimizerResult
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..errors.unprocessable_entity_error import UnprocessableEntityError
from ..types.http_validation_error import HttpValidationError
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class DigitalTwinClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def optimize(
        self,
        *,
        parameters: typing.Sequence[NamedQuantity],
        parameter_bounds: typing.Sequence[ParameterBound],
        constants: typing.Sequence[NamedQuantity],
        inputs: typing.Sequence[NamedQuantityList],
        targets: typing.Sequence[NamedQuantityList],
        tolerance: typing.Optional[float] = OMIT,
        max_time: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> OptimizerResult:
        """
        Fits a digital twin model to input data using numerical optimization.

            Accepts parameter guesses, bounds, inputs, targets, and constants — all with units —
            and returns the optimized parameters that minimize the model's error using a selected cost function.

            Args:
                OptimizerBody: The input data and optimization parameters.
            Returns:
                OptimizerResult: The result of the optimization.

        Parameters
        ----------
        parameters : typing.Sequence[NamedQuantity]

        parameter_bounds : typing.Sequence[ParameterBound]

        constants : typing.Sequence[NamedQuantity]

        inputs : typing.Sequence[NamedQuantityList]

        targets : typing.Sequence[NamedQuantityList]

        tolerance : typing.Optional[float]

        max_time : typing.Optional[int]

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        OptimizerResult
            Successful Response

        Examples
        --------
        from axiomatic import (
            Axiomatic,
            NamedQuantity,
            NamedQuantityList,
            ParameterBound,
            Quantity,
            QuantityList,
        )

        client = Axiomatic(
            api_key="YOUR_API_KEY",
        )
        client.digital_twin.optimize(
            parameters=[
                NamedQuantity(
                    name="name",
                    value=Quantity(
                        magnitude=1.1,
                        unit="unit",
                    ),
                )
            ],
            parameter_bounds=[
                ParameterBound(
                    name="name",
                    lower=Quantity(
                        magnitude=1.1,
                        unit="unit",
                    ),
                    upper=Quantity(
                        magnitude=1.1,
                        unit="unit",
                    ),
                )
            ],
            constants=[
                NamedQuantity(
                    name="name",
                    value=Quantity(
                        magnitude=1.1,
                        unit="unit",
                    ),
                )
            ],
            inputs=[
                NamedQuantityList(
                    name="name",
                    value=QuantityList(
                        unit="unit",
                        magnitude=[1.1],
                    ),
                )
            ],
            targets=[
                NamedQuantityList(
                    name="name",
                    value=QuantityList(
                        unit="unit",
                        magnitude=[1.1],
                    ),
                )
            ],
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            "digital-twin/optimize",
            method="POST",
            json={
                "parameters": convert_and_respect_annotation_metadata(
                    object_=parameters, annotation=typing.Sequence[NamedQuantity], direction="write"
                ),
                "parameter_bounds": convert_and_respect_annotation_metadata(
                    object_=parameter_bounds, annotation=typing.Sequence[ParameterBound], direction="write"
                ),
                "constants": convert_and_respect_annotation_metadata(
                    object_=constants, annotation=typing.Sequence[NamedQuantity], direction="write"
                ),
                "inputs": convert_and_respect_annotation_metadata(
                    object_=inputs, annotation=typing.Sequence[NamedQuantityList], direction="write"
                ),
                "targets": convert_and_respect_annotation_metadata(
                    object_=targets, annotation=typing.Sequence[NamedQuantityList], direction="write"
                ),
                "tolerance": tolerance,
                "max_time": max_time,
                "model_name": "EOResponseModel",
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    OptimizerResult,
                    parse_obj_as(
                        type_=OptimizerResult,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


class AsyncDigitalTwinClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def optimize(
        self,
        *,
        parameters: typing.Sequence[NamedQuantity],
        parameter_bounds: typing.Sequence[ParameterBound],
        constants: typing.Sequence[NamedQuantity],
        inputs: typing.Sequence[NamedQuantityList],
        targets: typing.Sequence[NamedQuantityList],
        tolerance: typing.Optional[float] = OMIT,
        max_time: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> OptimizerResult:
        """
        Fits a digital twin model to input data using numerical optimization.

            Accepts parameter guesses, bounds, inputs, targets, and constants — all with units —
            and returns the optimized parameters that minimize the model's error using a selected cost function.

            Args:
                OptimizerBody: The input data and optimization parameters.
            Returns:
                OptimizerResult: The result of the optimization.

        Parameters
        ----------
        parameters : typing.Sequence[NamedQuantity]

        parameter_bounds : typing.Sequence[ParameterBound]

        constants : typing.Sequence[NamedQuantity]

        inputs : typing.Sequence[NamedQuantityList]

        targets : typing.Sequence[NamedQuantityList]

        tolerance : typing.Optional[float]

        max_time : typing.Optional[int]

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        OptimizerResult
            Successful Response

        Examples
        --------
        import asyncio

        from axiomatic import (
            AsyncAxiomatic,
            NamedQuantity,
            NamedQuantityList,
            ParameterBound,
            Quantity,
            QuantityList,
        )

        client = AsyncAxiomatic(
            api_key="YOUR_API_KEY",
        )


        async def main() -> None:
            await client.digital_twin.optimize(
                parameters=[
                    NamedQuantity(
                        name="name",
                        value=Quantity(
                            magnitude=1.1,
                            unit="unit",
                        ),
                    )
                ],
                parameter_bounds=[
                    ParameterBound(
                        name="name",
                        lower=Quantity(
                            magnitude=1.1,
                            unit="unit",
                        ),
                        upper=Quantity(
                            magnitude=1.1,
                            unit="unit",
                        ),
                    )
                ],
                constants=[
                    NamedQuantity(
                        name="name",
                        value=Quantity(
                            magnitude=1.1,
                            unit="unit",
                        ),
                    )
                ],
                inputs=[
                    NamedQuantityList(
                        name="name",
                        value=QuantityList(
                            unit="unit",
                            magnitude=[1.1],
                        ),
                    )
                ],
                targets=[
                    NamedQuantityList(
                        name="name",
                        value=QuantityList(
                            unit="unit",
                            magnitude=[1.1],
                        ),
                    )
                ],
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            "digital-twin/optimize",
            method="POST",
            json={
                "parameters": convert_and_respect_annotation_metadata(
                    object_=parameters, annotation=typing.Sequence[NamedQuantity], direction="write"
                ),
                "parameter_bounds": convert_and_respect_annotation_metadata(
                    object_=parameter_bounds, annotation=typing.Sequence[ParameterBound], direction="write"
                ),
                "constants": convert_and_respect_annotation_metadata(
                    object_=constants, annotation=typing.Sequence[NamedQuantity], direction="write"
                ),
                "inputs": convert_and_respect_annotation_metadata(
                    object_=inputs, annotation=typing.Sequence[NamedQuantityList], direction="write"
                ),
                "targets": convert_and_respect_annotation_metadata(
                    object_=targets, annotation=typing.Sequence[NamedQuantityList], direction="write"
                ),
                "tolerance": tolerance,
                "max_time": max_time,
                "model_name": "EOResponseModel",
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    OptimizerResult,
                    parse_obj_as(
                        type_=OptimizerResult,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
