# 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_transport_costs_pricing_system import (
    ExternalAPIWaybillTransportCostsPricingSystem,
)
from pywaybiller.openapi_client.models.external_api_waybill_transport_costs_weights_to_use import (
    ExternalAPIWaybillTransportCostsWeightsToUse,
)
from pywaybiller.openapi_client.models.incoterm_enum import IncotermEnum


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

    incoterm: IncotermEnum = Field(
        description="The incoterm for which the transport cost is calculated.  * `EXW` - EXW (Ex Works) * `DAP` - DAP (Delivered At Place)"
    )
    pricing_system: ExternalAPIWaybillTransportCostsPricingSystem
    load_price: Annotated[str, Field(strict=True)] = Field(
        description="The price used to calculate the transport cost for load pricing system."
    )
    transport_coefficient: Annotated[str, Field(strict=True)] = Field(
        description="The transport coefficient used to calculate the transport cost."
    )
    minimum_unit_price: Annotated[str, Field(strict=True)] = Field(
        description="The minimum unit price used to calculate the transport cost."
    )
    weights_to_use: ExternalAPIWaybillTransportCostsWeightsToUse
    tonnes: Annotated[str, Field(strict=True)] = Field(
        description="Amount in tonnes to be used to calculate the transport cost."
    )
    ton_price: Annotated[str, Field(strict=True)] = Field(
        description="The price used to calculate the transport cost for ton pricing system."
    )
    mileage_price: Annotated[str, Field(strict=True)] = Field(
        description="The price used to calculate the transport cost for mileage pricing system."
    )
    mileage: Annotated[int, Field(le=32767, strict=True, ge=0)] = Field(
        description="The distance in kilometers used to calculate the transport cost."
    )
    waiting_hours: Annotated[str, Field(strict=True)] = Field(
        description="The number of hours the driver waited."
    )
    waiting_hours_price: Annotated[str, Field(strict=True)] = Field(
        description="The cost of waiting for one hour."
    )
    extra_costs: Annotated[str, Field(strict=True)] = Field(
        description="Extra costs for the transport."
    )
    transport_cost_value: Annotated[str, Field(strict=True)] = Field(
        description="The calculated transport cost value."
    )
    transport_cost_calculation: Annotated[str, Field(strict=True, max_length=100)] = (
        Field(description="The calculation of the transport cost.")
    )
    last_saved_by_email: Optional[StrictStr] = Field(
        description="The e-mail address of the user that last saved the transport costs. If confirmation time is set, then this user confirmed the costs"
    )
    last_saved_by_name: Optional[StrictStr] = Field(
        description="The name of the user that last saved the transport costs"
    )
    last_saved_by_company_name: Optional[StrictStr] = Field(
        description="The company name of the user that last saved the transport costs"
    )
    confirmed_at: Optional[datetime] = Field(
        description="The time when the transport cost was confirmed."
    )
    __properties: ClassVar[List[str]] = [
        "incoterm",
        "pricing_system",
        "load_price",
        "transport_coefficient",
        "minimum_unit_price",
        "weights_to_use",
        "tonnes",
        "ton_price",
        "mileage_price",
        "mileage",
        "waiting_hours",
        "waiting_hours_price",
        "extra_costs",
        "transport_cost_value",
        "transport_cost_calculation",
        "last_saved_by_email",
        "last_saved_by_name",
        "last_saved_by_company_name",
        "confirmed_at",
    ]

    @field_validator("load_price")
    def load_price_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,4}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,4}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("transport_coefficient")
    def transport_coefficient_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,1}(?:\.\d{0,7})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,1}(?:\.\d{0,7})?$/"
            )
        return value

    @field_validator("minimum_unit_price")
    def minimum_unit_price_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,4}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,4}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("tonnes")
    def tonnes_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

    @field_validator("ton_price")
    def ton_price_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,4}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,4}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("mileage_price")
    def mileage_price_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,4}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,4}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("waiting_hours")
    def waiting_hours_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,3}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,3}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("waiting_hours_price")
    def waiting_hours_price_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,4}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,4}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("extra_costs")
    def extra_costs_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,4}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,4}(?:\.\d{0,2})?$/"
            )
        return value

    @field_validator("transport_cost_value")
    def transport_cost_value_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^-?\d{0,11}(?:\.\d{0,2})?$", value):
            raise ValueError(
                r"must validate the regular expression /^-?\d{0,11}(?:\.\d{0,2})?$/"
            )
        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 ExternalAPIWaybillTransportCosts 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.
        """
        excluded_fields: Set[str] = set(
            [
                "incoterm",
                "load_price",
                "transport_coefficient",
                "minimum_unit_price",
                "tonnes",
                "ton_price",
                "mileage_price",
                "mileage",
                "waiting_hours",
                "waiting_hours_price",
                "extra_costs",
                "transport_cost_value",
                "transport_cost_calculation",
                "last_saved_by_email",
                "last_saved_by_name",
                "last_saved_by_company_name",
                "confirmed_at",
            ]
        )

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of pricing_system
        if self.pricing_system:
            _dict["pricing_system"] = self.pricing_system.to_dict()
        # override the default output from pydantic by calling `to_dict()` of weights_to_use
        if self.weights_to_use:
            _dict["weights_to_use"] = self.weights_to_use.to_dict()
        # set to None if last_saved_by_email (nullable) is None
        # and model_fields_set contains the field
        if (
            self.last_saved_by_email is None
            and "last_saved_by_email" in self.model_fields_set
        ):
            _dict["last_saved_by_email"] = None

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

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

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

        return _dict

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

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

        _obj = cls.model_validate(
            {
                "incoterm": obj.get("incoterm"),
                "pricing_system": ExternalAPIWaybillTransportCostsPricingSystem.from_dict(
                    obj["pricing_system"]
                )
                if obj.get("pricing_system") is not None
                else None,
                "load_price": obj.get("load_price"),
                "transport_coefficient": obj.get("transport_coefficient"),
                "minimum_unit_price": obj.get("minimum_unit_price"),
                "weights_to_use": ExternalAPIWaybillTransportCostsWeightsToUse.from_dict(
                    obj["weights_to_use"]
                )
                if obj.get("weights_to_use") is not None
                else None,
                "tonnes": obj.get("tonnes"),
                "ton_price": obj.get("ton_price"),
                "mileage_price": obj.get("mileage_price"),
                "mileage": obj.get("mileage"),
                "waiting_hours": obj.get("waiting_hours"),
                "waiting_hours_price": obj.get("waiting_hours_price"),
                "extra_costs": obj.get("extra_costs"),
                "transport_cost_value": obj.get("transport_cost_value"),
                "transport_cost_calculation": obj.get("transport_cost_calculation"),
                "last_saved_by_email": obj.get("last_saved_by_email"),
                "last_saved_by_name": obj.get("last_saved_by_name"),
                "last_saved_by_company_name": obj.get("last_saved_by_company_name"),
                "confirmed_at": obj.get("confirmed_at"),
            }
        )
        return _obj
