"""Model Registry REST API.

REST API for Model Registry to create and manage ML model metadata

The version of the OpenAPI document: v1alpha3
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""  # noqa: E501

from __future__ import annotations

import json
import pprint
import re  # noqa: F401
from typing import Any, ClassVar

from pydantic import BaseModel, ConfigDict, Field, StrictStr
from typing_extensions import Self

from mr_openapi.models.artifact_state import ArtifactState
from mr_openapi.models.metadata_value import MetadataValue


class ModelArtifactUpdate(BaseModel):
    """An ML model artifact to be updated."""  # noqa: E501

    custom_properties: dict[str, MetadataValue] | None = Field(
        default=None,
        description="User provided custom properties which are not defined by its type.",
        alias="customProperties",
    )
    description: StrictStr | None = Field(default=None, description="An optional description about the resource.")
    external_id: StrictStr | None = Field(
        default=None,
        description="The external id that come from the clients’ system. This field is optional. If set, it must be unique among all resources within a database instance.",
        alias="externalId",
    )
    artifact_type: StrictStr | None = Field(default="model-artifact", alias="artifactType")
    model_format_name: StrictStr | None = Field(
        default=None, description="Name of the model format.", alias="modelFormatName"
    )
    storage_key: StrictStr | None = Field(default=None, description="Storage secret name.", alias="storageKey")
    storage_path: StrictStr | None = Field(
        default=None, description="Path for model in storage provided by `storageKey`.", alias="storagePath"
    )
    model_format_version: StrictStr | None = Field(
        default=None, description="Version of the model format.", alias="modelFormatVersion"
    )
    service_account_name: StrictStr | None = Field(
        default=None, description="Name of the service account with storage secret.", alias="serviceAccountName"
    )
    model_source_kind: StrictStr | None = Field(
        default=None,
        description="A string identifier describing the source kind. It differentiates various sources of model artifacts. This identifier should be agreed upon by producers and consumers of source model metadata. It is not an enumeration to keep the source of model metadata open ended.  E.g. Kubeflow pipelines could use `pipelines` to identify models it produces.",
        alias="modelSourceKind",
    )
    model_source_class: StrictStr | None = Field(
        default=None,
        description="A subgroup within the source kind. It is a specific sub-component or instance within the source kind. E.g. `pipelinerun` for a Kubeflow pipeline run.",
        alias="modelSourceClass",
    )
    model_source_group: StrictStr | None = Field(
        default=None,
        description="Unique identifier for a source group for models from source class.  It maps to a physical group of source models.  E.g. a Kubernetes namespace where the pipeline run was executed.",
        alias="modelSourceGroup",
    )
    model_source_id: StrictStr | None = Field(
        default=None,
        description="A unique identifier for a source model within kind, class, and group. It should be a url friendly string if source supports using URLs to locate source models. E.g. a pipeline run ID.",
        alias="modelSourceId",
    )
    model_source_name: StrictStr | None = Field(
        default=None,
        description="A human-readable name for the source model.  E.g. `my-project/1`, `ibm-granite/granite-3.1-8b-base:2.1.2`.",
        alias="modelSourceName",
    )
    uri: StrictStr | None = Field(
        default=None,
        description="The uniform resource identifier of the physical artifact. May be empty if there is no physical artifact.",
    )
    state: ArtifactState | None = ArtifactState.UNKNOWN
    __properties: ClassVar[list[str]] = [
        "customProperties",
        "description",
        "externalId",
        "artifactType",
        "modelFormatName",
        "storageKey",
        "storagePath",
        "modelFormatVersion",
        "serviceAccountName",
        "modelSourceKind",
        "modelSourceClass",
        "modelSourceGroup",
        "modelSourceId",
        "modelSourceName",
        "uri",
        "state",
    ]

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )

    def to_str(self) -> str:
        """Returns the string representation of the model using alias."""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias."""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Self | None:
        """Create an instance of ModelArtifactUpdate from a JSON string."""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: set[str] = set()

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of each value in custom_properties (dict)
        _field_dict = {}
        if self.custom_properties:
            for _key_custom_properties in self.custom_properties:
                if self.custom_properties[_key_custom_properties]:
                    _field_dict[_key_custom_properties] = self.custom_properties[_key_custom_properties].to_dict()
            _dict["customProperties"] = _field_dict
        return _dict

    @classmethod
    def from_dict(cls, obj: dict[str, Any] | None) -> Self | None:
        """Create an instance of ModelArtifactUpdate from a dict."""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        return cls.model_validate(
            {
                "customProperties": {_k: MetadataValue.from_dict(_v) for _k, _v in obj["customProperties"].items()}
                if obj.get("customProperties") is not None
                else None,
                "description": obj.get("description"),
                "externalId": obj.get("externalId"),
                "artifactType": obj.get("artifactType") if obj.get("artifactType") is not None else "model-artifact",
                "modelFormatName": obj.get("modelFormatName"),
                "storageKey": obj.get("storageKey"),
                "storagePath": obj.get("storagePath"),
                "modelFormatVersion": obj.get("modelFormatVersion"),
                "serviceAccountName": obj.get("serviceAccountName"),
                "modelSourceKind": obj.get("modelSourceKind"),
                "modelSourceClass": obj.get("modelSourceClass"),
                "modelSourceGroup": obj.get("modelSourceGroup"),
                "modelSourceId": obj.get("modelSourceId"),
                "modelSourceName": obj.get("modelSourceName"),
                "uri": obj.get("uri"),
                "state": obj.get("state") if obj.get("state") is not None else ArtifactState.UNKNOWN,
            }
        )
