# 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 datetime
from typing import Any, ClassVar, Dict, List, Optional, Set

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

from pywaybiller.openapi_client.models.external_api_waybill_raw_data_list import (
    ExternalAPIWaybillRawDataList,
)
from pywaybiller.openapi_client.models.external_api_waybill_row_list import (
    ExternalAPIWaybillRowList,
)
from pywaybiller.openapi_client.models.waybill_status_enum import WaybillStatusEnum


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

    waybill_id: Optional[StrictStr] = Field(
        description="The external ID of the waybill. Usually `null` if waybill was created in Waybiller UI and not over Waybiller External API."
    )
    destination_id: Optional[StrictStr] = Field(
        description="The external ID of the destination. Usually `null` if waybill was created in Waybiller UI and not over Waybiller External API."
    )
    dispatcher_timestamp: datetime = Field(description="Waybill creation timestamp")
    driver_timestamp: Optional[datetime] = Field(
        description="Timestamp when driver started driving"
    )
    destination_timestamp: Optional[datetime]
    confirmed_timestamp: Optional[datetime] = Field(
        description="Time of confirmation in the destination"
    )
    cancelled_timestamp: Optional[datetime] = Field(
        description="Time of waybill cancelling"
    )
    status: WaybillStatusEnum
    number: StrictStr
    navision_bin_code: Optional[StrictStr] = Field(description="Bin code.")
    project: Optional[StrictStr] = Field(description="Project code in your system.")
    raw_data: ExternalAPIWaybillRawDataList = Field(
        description="The IDs of the Waybiller internal objects"
    )
    shipper_company_name: StrictStr = Field(
        description="The name of the shipper company."
    )
    origin_id: Optional[StrictStr] = Field(
        description="The external ID of the origin. Usually `null` if waybill was created in Waybiller UI and not over Waybiller External API."
    )
    origin_name: StrictStr
    origin_address: StrictStr
    transportation_company_name: StrictStr = Field(
        description="The name of the transportation company."
    )
    driver_name: Annotated[str, Field(strict=True, max_length=255)] = Field(
        description="The name of the driver."
    )
    truck_reg_number: StrictStr = Field(
        description="The registration number of the vehicle."
    )
    trailer_reg_number: StrictStr = Field(
        description="The registration number of the trailer."
    )
    receiver_company_name: StrictStr = Field(
        description="The name of the receiving company."
    )
    receiver_company_reg_code: StrictStr = Field(
        description="The registry code of the receiving company."
    )
    last_vehicle_location: Optional[Dict[str, Any]]
    destination_name: StrictStr = Field(description="The name of the destination.")
    destination_address: StrictStr = Field(
        description="The address of the destination."
    )
    dispatched_amount: Annotated[str, Field(strict=True)] = Field(
        description="The total dispatched amount."
    )
    rows: List[ExternalAPIWaybillRowList] = Field(description="Waybill rows.")
    __properties: ClassVar[List[str]] = [
        "waybill_id",
        "destination_id",
        "dispatcher_timestamp",
        "driver_timestamp",
        "destination_timestamp",
        "confirmed_timestamp",
        "cancelled_timestamp",
        "status",
        "number",
        "navision_bin_code",
        "project",
        "raw_data",
        "shipper_company_name",
        "origin_id",
        "origin_name",
        "origin_address",
        "transportation_company_name",
        "driver_name",
        "truck_reg_number",
        "trailer_reg_number",
        "receiver_company_name",
        "receiver_company_reg_code",
        "last_vehicle_location",
        "destination_name",
        "destination_address",
        "dispatched_amount",
        "rows",
    ]

    @field_validator("dispatched_amount")
    def dispatched_amount_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,5}(?:\.\d{0,3})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,5}(?:\.\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 ExternalAPIWaybillList 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.
        * 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(
            [
                "waybill_id",
                "destination_id",
                "dispatcher_timestamp",
                "driver_timestamp",
                "destination_timestamp",
                "confirmed_timestamp",
                "cancelled_timestamp",
                "status",
                "number",
                "navision_bin_code",
                "project",
                "raw_data",
                "shipper_company_name",
                "origin_id",
                "origin_name",
                "origin_address",
                "transportation_company_name",
                "driver_name",
                "truck_reg_number",
                "trailer_reg_number",
                "receiver_company_name",
                "receiver_company_reg_code",
                "last_vehicle_location",
                "destination_name",
                "destination_address",
                "dispatched_amount",
                "rows",
            ]
        )

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # 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()
        # 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
        # set to None if waybill_id (nullable) is None
        # and model_fields_set contains the field
        if self.waybill_id is None and "waybill_id" in self.model_fields_set:
            _dict["waybill_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 driver_timestamp (nullable) is None
        # and model_fields_set contains the field
        if (
            self.driver_timestamp is None
            and "driver_timestamp" in self.model_fields_set
        ):
            _dict["driver_timestamp"] = None

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

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

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

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

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

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

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

        return _dict

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

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

        _obj = cls.model_validate(
            {
                "waybill_id": obj.get("waybill_id"),
                "destination_id": obj.get("destination_id"),
                "dispatcher_timestamp": obj.get("dispatcher_timestamp"),
                "driver_timestamp": obj.get("driver_timestamp"),
                "destination_timestamp": obj.get("destination_timestamp"),
                "confirmed_timestamp": obj.get("confirmed_timestamp"),
                "cancelled_timestamp": obj.get("cancelled_timestamp"),
                "status": obj.get("status"),
                "number": obj.get("number"),
                "navision_bin_code": obj.get("navision_bin_code"),
                "project": obj.get("project"),
                "raw_data": ExternalAPIWaybillRawDataList.from_dict(obj["raw_data"])
                if obj.get("raw_data") is not None
                else None,
                "shipper_company_name": obj.get("shipper_company_name"),
                "origin_id": obj.get("origin_id"),
                "origin_name": obj.get("origin_name"),
                "origin_address": obj.get("origin_address"),
                "transportation_company_name": obj.get("transportation_company_name"),
                "driver_name": obj.get("driver_name"),
                "truck_reg_number": obj.get("truck_reg_number"),
                "trailer_reg_number": obj.get("trailer_reg_number"),
                "receiver_company_name": obj.get("receiver_company_name"),
                "receiver_company_reg_code": obj.get("receiver_company_reg_code"),
                "last_vehicle_location": obj.get("last_vehicle_location"),
                "destination_name": obj.get("destination_name"),
                "destination_address": obj.get("destination_address"),
                "dispatched_amount": obj.get("dispatched_amount"),
                "rows": [
                    ExternalAPIWaybillRowList.from_dict(_item) for _item in obj["rows"]
                ]
                if obj.get("rows") is not None
                else None,
            }
        )
        return _obj
