# coding: utf-8

"""
Waybiller External API - with fixes

The **Waybiller External API** is a feature that allows companies to access **Waybiller** data as JSON objects and create **Waybiller** instances out of their own data.  To make integration easier for the companies, the external API provides mapping support - it is possible to create company-specific mappings for object identifiers (such as destination and origin).  These mappings will be used for representing companies data from external API, and for converting the values during the creation of **Waybiller** instances (such as transport orders and waybills).  Most of the API responses contain mapped values, which may be null if the company doesn't have a mapping for this object.  Unique **Waybiller** identifiers and values can be accessed via the `raw_data` key.  The API is HTTPS and JSON based.  ### Pagination  By default, list endpoint responses are presented in pages of 30 items.  It is possible to control the page size using the `limit` parameter: `/external-api/<some-list-endpoint>/?limit=<number>`, where `<number>` is an integer between 1 and 1000.

The version of the OpenAPI document: v1
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 datetime import date
from typing import Any, ClassVar, Dict, List, Optional, Set, Union

from pydantic import (
    BaseModel,
    ConfigDict,
    Field,
    StrictBool,
    StrictFloat,
    StrictInt,
    StrictStr,
    field_validator,
)
from typing_extensions import Annotated, Self

from pywaybiller.openapi_client.models.external_api_order_origin import (
    ExternalAPIOrderOrigin,
)
from pywaybiller.openapi_client.models.external_api_order_origins_assortments import (
    ExternalAPIOrderOriginsAssortments,
)
from pywaybiller.openapi_client.models.external_api_order_raw_data import (
    ExternalAPIOrderRawData,
)
from pywaybiller.openapi_client.models.external_api_order_transport_companies import (
    ExternalAPIOrderTransportCompanies,
)
from pywaybiller.openapi_client.models.external_api_order_vehicles import (
    ExternalAPIOrderVehicles,
)
from pywaybiller.openapi_client.models.order_status_enum import OrderStatusEnum


class ExternalAPIOrderRetrieve(BaseModel):
    """
    ExternalAPIOrderRetrieve
    """  # noqa: E501

    number: Annotated[str, Field(strict=True, max_length=16)] = Field(
        description="Unique order reference number"
    )
    status: OrderStatusEnum = Field(description="Current status of the order")
    order_id: Optional[Annotated[str, Field(strict=True, max_length=1024)]] = Field(
        description="Unique identifier for this order in your system"
    )
    period: List[date] = Field(description="Date range when the order is active")
    owner_raw_id: Annotated[str, Field(strict=True, max_length=10)] = Field(
        description="Unique identifier of the company that owns this order"
    )
    owner_company_name: Annotated[str, Field(strict=True, max_length=64)] = Field(
        description="Name of the company that owns this order"
    )
    client_id: Optional[Annotated[str, Field(strict=True, max_length=1024)]] = Field(
        description="Unique identifier for the client company of this order in your system"
    )
    destination_id: Optional[Annotated[str, Field(strict=True, max_length=1024)]] = (
        Field(
            description="Unique identifier for the destination of this order in your system"
        )
    )
    destination_name: Optional[Annotated[str, Field(strict=True, max_length=64)]] = (
        Field(description="Name of the destination")
    )
    destination_address: Optional[
        Annotated[str, Field(strict=True, max_length=255)]
    ] = Field(description="Physical address of the delivery destination")
    destination_latitude: Optional[Union[StrictFloat, StrictInt]] = Field(
        description="Geographic latitude coordinate of the destination (decimal degrees)"
    )
    destination_longitude: Optional[Union[StrictFloat, StrictInt]] = Field(
        description="Geographic longitude coordinate of the destination (decimal degrees)"
    )
    origins: List[ExternalAPIOrderOrigin] = Field(
        description="List of origins associated with this order"
    )
    total_allowed_amount: Optional[Annotated[str, Field(strict=True)]] = Field(
        description="Maximum total quantity allowed for this order"
    )
    rows: List[ExternalAPIOrderOriginsAssortments] = Field(
        description="Assortments associated with the origins of this order"
    )
    transportation_companies: List[ExternalAPIOrderTransportCompanies] = Field(
        description="List of companies authorized to transport assortments for this order"
    )
    cancel_transport_orders_on_allowed_amount_exceeding: StrictBool = Field(
        description="Cancel transport orders and do not allow to create new transport orders if the order amount has been exceeded."
    )
    client_can_edit_transportation_values: StrictBool = Field(
        description="Boolean flag indicating whether the client has permission to modify transportation details"
    )
    vehicles: List[ExternalAPIOrderVehicles] = Field(
        description="Specific vehicles approved for transporting materials in this order"
    )
    extra_information: StrictStr = Field(
        description="Additional notes, special instructions, or requirements for this order"
    )
    user_id: StrictInt = Field(
        description="Identifier of the user who created this order"
    )
    raw_data: ExternalAPIOrderRawData = Field(
        description="The IDs of the Waybiller internal objects"
    )
    __properties: ClassVar[List[str]] = [
        "number",
        "status",
        "order_id",
        "period",
        "owner_raw_id",
        "owner_company_name",
        "client_id",
        "destination_id",
        "destination_name",
        "destination_address",
        "destination_latitude",
        "destination_longitude",
        "origins",
        "total_allowed_amount",
        "rows",
        "transportation_companies",
        "cancel_transport_orders_on_allowed_amount_exceeding",
        "client_can_edit_transportation_values",
        "vehicles",
        "extra_information",
        "user_id",
        "raw_data",
    ]

    @field_validator("total_allowed_amount")
    def total_allowed_amount_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if value is None:
            return value

        if not re.match(r"^-?\d{0,7}(?:\.\d{0,3})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,7}(?:\.\d{0,3})?$/"
            )
        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 ExternalAPIOrderRetrieve 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.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        """
        excluded_fields: Set[str] = set(
            [
                "number",
                "status",
                "order_id",
                "period",
                "owner_raw_id",
                "owner_company_name",
                "client_id",
                "destination_id",
                "destination_name",
                "destination_address",
                "destination_latitude",
                "destination_longitude",
                "origins",
                "total_allowed_amount",
                "rows",
                "transportation_companies",
                "cancel_transport_orders_on_allowed_amount_exceeding",
                "client_can_edit_transportation_values",
                "vehicles",
                "extra_information",
                "user_id",
                "raw_data",
            ]
        )

        _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 item in origins (list)
        _items = []
        if self.origins:
            for _item_origins in self.origins:
                if _item_origins:
                    _items.append(_item_origins.to_dict())
            _dict["origins"] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in rows (list)
        _items = []
        if self.rows:
            for _item_rows in self.rows:
                if _item_rows:
                    _items.append(_item_rows.to_dict())
            _dict["rows"] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in transportation_companies (list)
        _items = []
        if self.transportation_companies:
            for _item_transportation_companies in self.transportation_companies:
                if _item_transportation_companies:
                    _items.append(_item_transportation_companies.to_dict())
            _dict["transportation_companies"] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in vehicles (list)
        _items = []
        if self.vehicles:
            for _item_vehicles in self.vehicles:
                if _item_vehicles:
                    _items.append(_item_vehicles.to_dict())
            _dict["vehicles"] = _items
        # override the default output from pydantic by calling `to_dict()` of raw_data
        if self.raw_data:
            _dict["raw_data"] = self.raw_data.to_dict()
        # set to None if order_id (nullable) is None
        # and model_fields_set contains the field
        if self.order_id is None and "order_id" in self.model_fields_set:
            _dict["order_id"] = None

        # set to None if client_id (nullable) is None
        # and model_fields_set contains the field
        if self.client_id is None and "client_id" in self.model_fields_set:
            _dict["client_id"] = None

        # set to None if destination_id (nullable) is None
        # and model_fields_set contains the field
        if self.destination_id is None and "destination_id" in self.model_fields_set:
            _dict["destination_id"] = None

        # set to None if destination_name (nullable) is None
        # and model_fields_set contains the field
        if (
            self.destination_name is None
            and "destination_name" in self.model_fields_set
        ):
            _dict["destination_name"] = None

        # set to None if destination_address (nullable) is None
        # and model_fields_set contains the field
        if (
            self.destination_address is None
            and "destination_address" in self.model_fields_set
        ):
            _dict["destination_address"] = None

        # set to None if destination_latitude (nullable) is None
        # and model_fields_set contains the field
        if (
            self.destination_latitude is None
            and "destination_latitude" in self.model_fields_set
        ):
            _dict["destination_latitude"] = None

        # set to None if destination_longitude (nullable) is None
        # and model_fields_set contains the field
        if (
            self.destination_longitude is None
            and "destination_longitude" in self.model_fields_set
        ):
            _dict["destination_longitude"] = None

        # set to None if total_allowed_amount (nullable) is None
        # and model_fields_set contains the field
        if (
            self.total_allowed_amount is None
            and "total_allowed_amount" in self.model_fields_set
        ):
            _dict["total_allowed_amount"] = None

        return _dict

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

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

        _obj = cls.model_validate(
            {
                "number": obj.get("number"),
                "status": obj.get("status"),
                "order_id": obj.get("order_id"),
                "period": obj.get("period"),
                "owner_raw_id": obj.get("owner_raw_id"),
                "owner_company_name": obj.get("owner_company_name"),
                "client_id": obj.get("client_id"),
                "destination_id": obj.get("destination_id"),
                "destination_name": obj.get("destination_name"),
                "destination_address": obj.get("destination_address"),
                "destination_latitude": obj.get("destination_latitude"),
                "destination_longitude": obj.get("destination_longitude"),
                "origins": [
                    ExternalAPIOrderOrigin.from_dict(_item) for _item in obj["origins"]
                ]
                if obj.get("origins") is not None
                else None,
                "total_allowed_amount": obj.get("total_allowed_amount"),
                "rows": [
                    ExternalAPIOrderOriginsAssortments.from_dict(_item)
                    for _item in obj["rows"]
                ]
                if obj.get("rows") is not None
                else None,
                "transportation_companies": [
                    ExternalAPIOrderTransportCompanies.from_dict(_item)
                    for _item in obj["transportation_companies"]
                ]
                if obj.get("transportation_companies") is not None
                else None,
                "cancel_transport_orders_on_allowed_amount_exceeding": obj.get(
                    "cancel_transport_orders_on_allowed_amount_exceeding"
                ),
                "client_can_edit_transportation_values": obj.get(
                    "client_can_edit_transportation_values"
                ),
                "vehicles": [
                    ExternalAPIOrderVehicles.from_dict(_item)
                    for _item in obj["vehicles"]
                ]
                if obj.get("vehicles") is not None
                else None,
                "extra_information": obj.get("extra_information"),
                "user_id": obj.get("user_id"),
                "raw_data": ExternalAPIOrderRawData.from_dict(obj["raw_data"])
                if obj.get("raw_data") is not None
                else None,
            }
        )
        return _obj
