# coding: utf-8

"""
    Zuora API Reference

    REST API reference for the Zuora Billing, Payments, and Central Platform! Check out the [REST API Overview](https://www.zuora.com/developer/api-references/api/overview/).

    The version of the OpenAPI document: 2024-05-20
    Contact: docs@zuora.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

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


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from typing import Optional, Set
from typing_extensions import Self

class SubmitDataLabelingJobRequest(BaseModel):
    """
    SubmitDataLabelingJobRequest
    """ # noqa: E501
    # avoid validation
    def __init__(self, **kwargs):
        # Directly assign values without validation using `construct()`
        model = self.construct(**kwargs)
        self.__dict__.update(model.__dict__)

        _dict_all = convert_snake_dict_to_camel(kwargs, self.model_fields, self.__properties)

        _dict = self.to_alias_dict(_dict_all)
        for field_name, field_info in self.model_fields.items():
            alias = field_info.alias or field_name
            if alias in _dict:
                self.__dict__[field_name] = _dict.get(alias)
        self.update_additional_properties(self, _dict_all)
        pass

    def __setattr__(self, name, value):
        # Override setattr to bypass validation when setting attributes
        object.__setattr__(self, name, value)

    ids: Optional[List[StrictStr]] = Field(default=None, description="The IDs of the objects to be labeled, only required if the `queryType` is `ById`.  There is a 4MB limit of the JSON payload, so in case of a large number of IDs, please make sure the payload is less than 4MB. ")
    object_type: StrictStr = Field(description="The object type of the data labeling job.  Currently, the following objects are supported:   * `User`   * `Account`       All the associated transaction objects of the account being labeled will automatically inherit the org label of the account.   * `Product`      You have to label the Account object first, make sure all accounts have been labeled, then you can proceed with the Product object.       You can get all the unlabeled accounts by running a Data Source export job, with the following query:     ``` sql     SELECT Id, Name FROM Account WHERE Organization.Id IS NULL     ```                        All the ProductRatePlanS of the product will be automatically labeled with the same `orgs`.          When labeling products, you can omit the `orgs` parameter, i.e, leave it empty, the system will find all the subscriptions that include the product and get the org list of those subscriptions, then label the product with those `orgs`, aka, the `derived orgs`.          You can also explicitly specify the orgs parameter, in that case, you will need to provide a super set of the `derived orgs`.     * `BillRun`      You don't need to specify the `orgs` parameter, we will label the `BillRun` with all the orgs because existing runs could pick up all accounts. You can definitely create new bill run with certain `orgs` to operate separately by `orgs`.   * `PaymentRun`      Same as BillRun.   * `ForecastRun` ", alias="objectType")
    org_ids: Optional[List[Annotated[str, Field(min_length=36, strict=True, max_length=36)]]] = Field(default=None, description="The IDs of the organizations that the data labeling job will associate with the data to be labeled. Either the `orgIds` or `orgs` field is required.  For `Account` object, one and only one org Id is required.  For configuration objects, `null` and `[]` are treated differently, use `null` to unlabel the object, `[]` to label it with all orgs. ", alias="orgIds")
    orgs: Optional[List[StrictStr]] = Field(default=None, description="The names of the organizations that the data labeling job will associate with the data to be labeled. Either the `orgIds` or `orgs` field is required.  For `Account` object, one and only one org name is required.  For configuration objects, `null` and `[]` are treated differently, use `null` to unlabel the object, `[]` to label it with all orgs. ")
    query: Optional[StrictStr] = Field(default=None, description="The query that the data labeling job will run to fetch the data to be labeled, only required if the `queryType` is `ByZoql`. ")
    query_type: StrictStr = Field(description="Specifies the type of query that the data labeling job will run to fetch the data to be labeled.  * `ByZoql` - The data labeling job will run a ZOQL query which is specified in the `query` field to fetch the data to be labeled. * `ById` - The data labeling job will fetch the data to be labeled by the IDs specified in the `ids` field. ", alias="queryType")
    additional_properties: Dict[str, Any] = {}
    __properties: ClassVar[List[str]] = ["ids", "objectType", "orgIds", "orgs", "query", "queryType"]

    @field_validator('query_type')
    def query_type_validate_enum(cls, value):
        """Validates the enum"""
        if value not in set(['ByZoql', 'ById']):
            raise ValueError("must be one of enum values ('ByZoql', 'ById')")
        return value

    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) -> Optional[Self]:
        """Create an instance of SubmitDataLabelingJobRequest 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.
        * Fields in `self.additional_properties` are added to the output dict.
        """
        excluded_fields: Set[str] = set([
            "additional_properties",
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # puts key-value pairs in additional_properties in the top level
        if self.additional_properties is not None:
            for _key, _value in self.additional_properties.items():
                _dict[_key] = _value

        return _dict

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

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

        obj = convert_snake_dict_to_camel(obj, cls.model_fields, cls.__properties)

        _obj = cls.model_validate(cls.to_alias_dict(obj))
        return cls.update_additional_properties(_obj, obj)

    @classmethod
    def update_additional_properties(cls, obj, _dict: Optional[Dict[str, Any]]):
        # store additional fields in additional_properties

        # store additional fields in additional_properties
        for _key in _dict.keys():
            if _key not in cls.__properties:
                obj.additional_properties[_key] = _dict.get(_key)


        return obj
        pass

    @classmethod
    def to_alias_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:

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

        return {
            "ids": obj.get("ids"),
            "objectType": obj.get("objectType"),
            "orgIds": obj.get("orgIds"),
            "orgs": obj.get("orgs"),
            "query": obj.get("query"),
            "queryType": obj.get("queryType")
        }
        return _obj


def convert_snake_dict_to_camel(_dict: dict, model_fields, properties):
    if not isinstance(_dict, dict):
        return _dict
    new_dict = {}
    for k, v in _dict.items():
        if k in model_fields:
            # model_fields: key is attribute name like bill_to_contact,
            alias = model_fields.get(k).alias or k
            new_dict[alias] = v
            pass
        else:
            new_key = snake_to_camel(k)
            if properties is not None and isinstance(properties, list) and new_key in properties:
                new_dict[new_key] = v
            else:
                new_dict[k] = v
    return new_dict
    pass


def snake_to_camel(name):
    if name is None or '_' not in name:
        return name
    components = name.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])
