# coding: utf-8

"""
    LUSID API

    FINBOURNE Technology  # noqa: E501

    Contact: info@finbourne.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""


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


from typing import Any, Dict, List, Optional, Union
from pydantic.v1 import BaseModel, Field, StrictFloat, StrictInt, StrictStr, conlist, constr, validator
from lusid.models.currency_and_amount import CurrencyAndAmount
from lusid.models.lusid_instrument import LusidInstrument
from lusid.models.model_property import ModelProperty
from lusid.models.resource_id import ResourceId

class LusidTradeTicket(BaseModel):
    """
    A LUSID Trade Ticket comprising an instrument, a transaction, and a counterparty.  # noqa: E501
    """
    transaction_id: constr(strict=True, max_length=256, min_length=0) = Field(..., alias="transactionId", description="Transaction ID. Must be unique.")
    transaction_type: constr(strict=True, max_length=256, min_length=0) = Field(..., alias="transactionType", description="Type of transaction for processing. Referenced by Transaction Configuration.")
    source: Optional[constr(strict=True, max_length=256, min_length=0)] = Field(None, description="Transaction Source. Referenced by Transaction Configuration.")
    transaction_date: constr(strict=True, min_length=1) = Field(..., alias="transactionDate", description="Transaction Date. Date at which transaction is known.")
    settlement_date: constr(strict=True, min_length=1) = Field(..., alias="settlementDate", description="Transaction settlement. Date at which transaction is finalised and realised into the system.")
    total_consideration: CurrencyAndAmount = Field(..., alias="totalConsideration")
    units: Union[StrictFloat, StrictInt] = Field(..., description="Number of units in the transaction. For an OTC this is somewhat interchangeable with the quantity booked in the  instrument. As M x N or N x M are equivalent it is advised a client chooses one approach and sticks to it.  Arguably either the unit or holding is best unitised.")
    instrument_identifiers: Dict[str, StrictStr] = Field(..., alias="instrumentIdentifiers", description="Identifiers for the instrument.")
    instrument_scope: Optional[constr(strict=True, max_length=64, min_length=1)] = Field(None, alias="instrumentScope", description="Scope of instrument")
    instrument_name: Optional[constr(strict=True, max_length=256, min_length=0)] = Field(None, alias="instrumentName", description="Name of instrument")
    instrument_definition: Optional[LusidInstrument] = Field(None, alias="instrumentDefinition")
    counterparty_agreement_id: Optional[ResourceId] = Field(None, alias="counterpartyAgreementId")
    counterparty: Optional[constr(strict=True, max_length=256, min_length=0)] = Field(None, description="Counterparty")
    instrument_properties: Optional[conlist(ModelProperty)] = Field(None, alias="instrumentProperties", description="Set of instrument properties (as defined by client/user).")
    transaction_properties: Optional[conlist(ModelProperty)] = Field(None, alias="transactionProperties", description="Set of transaction properties (as defined by client/user).")
    trade_ticket_type: StrictStr = Field(..., alias="tradeTicketType", description="The available values are: LusidTradeTicket, ExternalTradeTicket")
    __properties = ["transactionId", "transactionType", "source", "transactionDate", "settlementDate", "totalConsideration", "units", "instrumentIdentifiers", "instrumentScope", "instrumentName", "instrumentDefinition", "counterpartyAgreementId", "counterparty", "instrumentProperties", "transactionProperties", "tradeTicketType"]

    @validator('instrument_scope')
    def instrument_scope_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if value is None:
            return value

        if not re.match(r"^[a-zA-Z0-9\-_]+$", value):
            raise ValueError(r"must validate the regular expression /^[a-zA-Z0-9\-_]+$/")
        return value

    @validator('trade_ticket_type')
    def trade_ticket_type_validate_enum(cls, value):
        """Validates the enum"""
        if value not in ('LusidTradeTicket', 'ExternalTradeTicket'):
            raise ValueError("must be one of enum values ('LusidTradeTicket', 'ExternalTradeTicket')")
        return value

    class Config:
        """Pydantic configuration"""
        allow_population_by_field_name = True
        validate_assignment = True

    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.dict(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> LusidTradeTicket:
        """Create an instance of LusidTradeTicket from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self):
        """Returns the dictionary representation of the model using alias"""
        _dict = self.dict(by_alias=True,
                          exclude={
                          },
                          exclude_none=True)
        # override the default output from pydantic by calling `to_dict()` of total_consideration
        if self.total_consideration:
            _dict['totalConsideration'] = self.total_consideration.to_dict()
        # override the default output from pydantic by calling `to_dict()` of instrument_definition
        if self.instrument_definition:
            _dict['instrumentDefinition'] = self.instrument_definition.to_dict()
        # override the default output from pydantic by calling `to_dict()` of counterparty_agreement_id
        if self.counterparty_agreement_id:
            _dict['counterpartyAgreementId'] = self.counterparty_agreement_id.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in instrument_properties (list)
        _items = []
        if self.instrument_properties:
            for _item in self.instrument_properties:
                if _item:
                    _items.append(_item.to_dict())
            _dict['instrumentProperties'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in transaction_properties (list)
        _items = []
        if self.transaction_properties:
            for _item in self.transaction_properties:
                if _item:
                    _items.append(_item.to_dict())
            _dict['transactionProperties'] = _items
        # set to None if source (nullable) is None
        # and __fields_set__ contains the field
        if self.source is None and "source" in self.__fields_set__:
            _dict['source'] = None

        # set to None if instrument_scope (nullable) is None
        # and __fields_set__ contains the field
        if self.instrument_scope is None and "instrument_scope" in self.__fields_set__:
            _dict['instrumentScope'] = None

        # set to None if instrument_name (nullable) is None
        # and __fields_set__ contains the field
        if self.instrument_name is None and "instrument_name" in self.__fields_set__:
            _dict['instrumentName'] = None

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

        # set to None if instrument_properties (nullable) is None
        # and __fields_set__ contains the field
        if self.instrument_properties is None and "instrument_properties" in self.__fields_set__:
            _dict['instrumentProperties'] = None

        # set to None if transaction_properties (nullable) is None
        # and __fields_set__ contains the field
        if self.transaction_properties is None and "transaction_properties" in self.__fields_set__:
            _dict['transactionProperties'] = None

        return _dict

    @classmethod
    def from_dict(cls, obj: dict) -> LusidTradeTicket:
        """Create an instance of LusidTradeTicket from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return LusidTradeTicket.parse_obj(obj)

        _obj = LusidTradeTicket.parse_obj({
            "transaction_id": obj.get("transactionId"),
            "transaction_type": obj.get("transactionType"),
            "source": obj.get("source"),
            "transaction_date": obj.get("transactionDate"),
            "settlement_date": obj.get("settlementDate"),
            "total_consideration": CurrencyAndAmount.from_dict(obj.get("totalConsideration")) if obj.get("totalConsideration") is not None else None,
            "units": obj.get("units"),
            "instrument_identifiers": obj.get("instrumentIdentifiers"),
            "instrument_scope": obj.get("instrumentScope"),
            "instrument_name": obj.get("instrumentName"),
            "instrument_definition": LusidInstrument.from_dict(obj.get("instrumentDefinition")) if obj.get("instrumentDefinition") is not None else None,
            "counterparty_agreement_id": ResourceId.from_dict(obj.get("counterpartyAgreementId")) if obj.get("counterpartyAgreementId") is not None else None,
            "counterparty": obj.get("counterparty"),
            "instrument_properties": [ModelProperty.from_dict(_item) for _item in obj.get("instrumentProperties")] if obj.get("instrumentProperties") is not None else None,
            "transaction_properties": [ModelProperty.from_dict(_item) for _item in obj.get("transactionProperties")] if obj.get("transactionProperties") is not None else None,
            "trade_ticket_type": obj.get("tradeTicketType")
        })
        return _obj
