# coding: utf-8

"""
Trading API

API for automated trading and exchange interface. This API is used to trade on the exchange and manage bots, API keys, orders, and more.

The version of the OpenAPI document: 1.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""  # noqa: E501


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

from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional, Union
from typing_extensions import Annotated
from crypticorn.trade.client.models.api_error_identifier import ApiErrorIdentifier
from crypticorn.trade.client.models.exchange import Exchange
from crypticorn.trade.client.models.margin_mode import MarginMode
from crypticorn.trade.client.models.market_type import MarketType
from crypticorn.trade.client.models.order_status import OrderStatus
from crypticorn.trade.client.models.trading_action_type import TradingActionType
from typing import Optional, Set
from typing_extensions import Self


class Order(BaseModel):
    """
    Response model for orders. All optional as the model is built step by step.
    """  # noqa: E501

    id: Optional[StrictStr] = Field(
        default=None, description="Unique identifier for the resource"
    )
    created_at: Optional[StrictInt] = Field(
        default=None, description="Timestamp of creation"
    )
    updated_at: Optional[StrictInt] = Field(
        default=None, description="Timestamp of last update"
    )
    trading_action_id: Optional[StrictStr] = None
    execution_id: Optional[StrictStr] = None
    exchange_order_id: Optional[StrictStr] = None
    position_id: Optional[StrictStr] = None
    api_key_id: Optional[StrictStr] = None
    user_id: Optional[StrictStr] = None
    bot_id: Optional[StrictStr] = None
    client_order_id: Optional[StrictStr] = None
    exchange: Optional[Exchange] = None
    symbol: Optional[StrictStr] = None
    common_symbol: Optional[StrictStr] = None
    price: Optional[Union[StrictFloat, StrictInt]] = None
    action_type: Optional[TradingActionType] = None
    market_type: Optional[MarketType] = None
    margin_mode: Optional[MarginMode] = None
    status_code: Optional[ApiErrorIdentifier] = None
    status: Optional[OrderStatus] = None
    filled_perc: Optional[
        Union[
            Annotated[float, Field(le=1.0, strict=True, ge=0.0)],
            Annotated[int, Field(le=1, strict=True, ge=0)],
        ]
    ] = Field(default=0, description="Percentage of the order filled")
    filled_qty: Optional[
        Union[
            Annotated[float, Field(strict=True, ge=0.0)],
            Annotated[int, Field(strict=True, ge=0)],
        ]
    ] = Field(
        default=0,
        description="Quantity filled. Needed for pnl calculation. In the symbol's base currency.",
    )
    fee: Optional[Union[StrictFloat, StrictInt]] = Field(
        default=0, description="Fees for the order"
    )
    leverage: Optional[Union[StrictFloat, StrictInt]] = None
    order_details: Optional[Any] = Field(
        default=None, description="Exchange specific details of the order"
    )
    pnl: Optional[Union[StrictFloat, StrictInt]] = Field(
        default=0, description="Profit and loss for the order"
    )
    order_time: Optional[StrictInt] = None
    __properties: ClassVar[List[str]] = [
        "id",
        "created_at",
        "updated_at",
        "trading_action_id",
        "execution_id",
        "exchange_order_id",
        "position_id",
        "api_key_id",
        "user_id",
        "bot_id",
        "client_order_id",
        "exchange",
        "symbol",
        "common_symbol",
        "price",
        "action_type",
        "market_type",
        "margin_mode",
        "status_code",
        "status",
        "filled_perc",
        "filled_qty",
        "fee",
        "leverage",
        "order_details",
        "pnl",
        "order_time",
    ]

    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 Order 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.
        """
        excluded_fields: Set[str] = set([])

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return _dict

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

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

        _obj = cls.model_validate(
            {
                "id": obj.get("id"),
                "created_at": obj.get("created_at"),
                "updated_at": obj.get("updated_at"),
                "trading_action_id": obj.get("trading_action_id"),
                "execution_id": obj.get("execution_id"),
                "exchange_order_id": obj.get("exchange_order_id"),
                "position_id": obj.get("position_id"),
                "api_key_id": obj.get("api_key_id"),
                "user_id": obj.get("user_id"),
                "bot_id": obj.get("bot_id"),
                "client_order_id": obj.get("client_order_id"),
                "exchange": obj.get("exchange"),
                "symbol": obj.get("symbol"),
                "common_symbol": obj.get("common_symbol"),
                "price": obj.get("price"),
                "action_type": obj.get("action_type"),
                "market_type": obj.get("market_type"),
                "margin_mode": obj.get("margin_mode"),
                "status_code": obj.get("status_code"),
                "status": obj.get("status"),
                "filled_perc": (
                    obj.get("filled_perc") if obj.get("filled_perc") is not None else 0
                ),
                "filled_qty": (
                    obj.get("filled_qty") if obj.get("filled_qty") is not None else 0
                ),
                "fee": obj.get("fee") if obj.get("fee") is not None else 0,
                "leverage": obj.get("leverage"),
                "order_details": (
                    AnyOf.from_dict(obj["order_details"])
                    if obj.get("order_details") is not None
                    else None
                ),
                "pnl": obj.get("pnl") if obj.get("pnl") is not None else 0,
                "order_time": obj.get("order_time"),
            }
        )
        return _obj
