# 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_transport_companies import (
    ExternalAPIOrderTransportCompanies,
)
from pywaybiller.openapi_client.models.external_api_order_vehicles import (
    ExternalAPIOrderVehicles,
)


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

    period: Optional[Annotated[List[date], Field(min_length=2, max_length=2)]] = Field(
        default=None, description="Date range when the order is active"
    )
    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"
    )
    client_company_reg_code: Optional[
        Annotated[str, Field(strict=True, max_length=16)]
    ] = Field(
        default=None,
        description="The company reg code for whom the order is created for. Used as raw id to match the company, if it exists. Required if the `client_id` is not provided",
    )
    client_company_name: Optional[Annotated[str, Field(strict=True, max_length=64)]] = (
        Field(
            default=None,
            description="Name of the company for whom the order is created for. Only used if a company with the given `client_company_reg_code` does not exist",
        )
    )
    destination_raw_id: Optional[StrictInt] = Field(
        default=None, description="Unique identifier of the destination"
    )
    destination_id: Optional[StrictStr] = Field(
        description="Unique identifier of the destination in your system"
    )
    destination_name: Optional[StrictStr] = Field(
        default=None,
        description="Name of the destination. Ignored if existing `destination_id` or `destination_raw_id` is provided",
    )
    destination_address: Optional[
        Annotated[str, Field(strict=True, max_length=255)]
    ] = Field(
        default=None,
        description="Address of the destination. Ignored if existing `destination_id` or `destination_raw_id` is provided",
    )
    destination_latitude: Optional[Union[StrictFloat, StrictInt]] = Field(
        default=None,
        description="Geographic latitude coordinate of the destination (decimal degrees). Ignored if existing `destination_id` or `destination_raw_id` is provided",
    )
    destination_longitude: Optional[Union[StrictFloat, StrictInt]] = Field(
        default=None,
        description="Geographic longitude coordinate of the destination (decimal degrees). Ignored if existing `destination_id` or `destination_raw_id` is provided",
    )
    origins: Optional[List[ExternalAPIOrderOrigin]] = Field(
        default=None, description="The origins for which the order is created"
    )
    rows: Optional[List[ExternalAPIOrderOriginsAssortments]] = Field(
        default=None,
        description="Assortments associated with the origins of this order",
    )
    total_allowed_amount: Optional[Annotated[str, Field(strict=True)]] = Field(
        default=None, description="Maximum total quantity allowed for this order"
    )
    transportation_companies: Optional[List[ExternalAPIOrderTransportCompanies]] = (
        Field(
            default=None,
            description="The transportation companies the client is using for transporting assortments from origins to destination",
        )
    )
    vehicles: Optional[List[ExternalAPIOrderVehicles]] = Field(
        default=None,
        description="The vehicles that the transportation companies are allowed to use for this order",
    )
    client_can_edit_transportation_values: Optional[StrictBool] = Field(
        default=None,
        description="Boolean flag indicating whether the client has permission to modify transportation details",
    )
    cancel_transport_orders_on_allowed_amount_exceeding: Optional[StrictBool] = Field(
        default=None,
        description="Cancel transport orders and do not allow to create new transport orders if the order amount has been exceeded.",
    )
    extra_information: Optional[StrictStr] = Field(
        default=None,
        description="Additional notes, special instructions, or requirements for this order",
    )
    __properties: ClassVar[List[str]] = [
        "period",
        "client_id",
        "client_company_reg_code",
        "client_company_name",
        "destination_raw_id",
        "destination_id",
        "destination_name",
        "destination_address",
        "destination_latitude",
        "destination_longitude",
        "origins",
        "rows",
        "total_allowed_amount",
        "transportation_companies",
        "vehicles",
        "client_can_edit_transportation_values",
        "cancel_transport_orders_on_allowed_amount_exceeding",
        "extra_information",
    ]

    @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 ExternalAPIOrderUpdate 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.
        """
        excluded_fields: Set[str] = set(
            [
                "client_id",
                "destination_id",
            ]
        )

        _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
        # 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 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 ExternalAPIOrderUpdate from a dict"""
        if obj is None:
            return None

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

        _obj = cls.model_validate(
            {
                "period": obj.get("period"),
                "client_id": obj.get("client_id"),
                "client_company_reg_code": obj.get("client_company_reg_code"),
                "client_company_name": obj.get("client_company_name"),
                "destination_raw_id": obj.get("destination_raw_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,
                "rows": [
                    ExternalAPIOrderOriginsAssortments.from_dict(_item)
                    for _item in obj["rows"]
                ]
                if obj.get("rows") is not None
                else None,
                "total_allowed_amount": obj.get("total_allowed_amount"),
                "transportation_companies": [
                    ExternalAPIOrderTransportCompanies.from_dict(_item)
                    for _item in obj["transportation_companies"]
                ]
                if obj.get("transportation_companies") is not None
                else None,
                "vehicles": [
                    ExternalAPIOrderVehicles.from_dict(_item)
                    for _item in obj["vehicles"]
                ]
                if obj.get("vehicles") is not None
                else None,
                "client_can_edit_transportation_values": obj.get(
                    "client_can_edit_transportation_values"
                ),
                "cancel_transport_orders_on_allowed_amount_exceeding": obj.get(
                    "cancel_transport_orders_on_allowed_amount_exceeding"
                ),
                "extra_information": obj.get("extra_information"),
            }
        )
        return _obj
