# 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,
    StrictBool,
    StrictFloat,
    StrictInt,
    StrictStr,
)
from typing import Any, ClassVar, Dict, List, Optional, Union
from typing_extensions import Annotated
from crypticorn.trade.client.models.margin_mode import MarginMode
from crypticorn.trade.client.models.market_type import MarketType
from crypticorn.trade.client.models.tpsl import TPSL
from crypticorn.trade.client.models.trading_action_type import TradingActionType
from typing import Optional, Set
from typing_extensions import Self


class FuturesTradingAction(BaseModel):
    """
    Model for futures trading actions
    """  # 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"
    )
    execution_id: Optional[StrictStr] = None
    open_order_execution_id: Optional[StrictStr] = None
    action_type: TradingActionType = Field(description="The type of action.")
    market_type: MarketType = Field(description="The type of market the action is for.")
    strategy_id: StrictStr = Field(description="UID for the strategy.")
    symbol: StrictStr = Field(
        description="Trading symbol or asset pair in format: 'symbol/quote_currency' (see market service for valid symbols)"
    )
    is_limit: Optional[StrictBool] = None
    limit_price: Optional[Union[StrictFloat, StrictInt]] = None
    allocation: Optional[
        Union[
            Annotated[float, Field(le=1.0, strict=True)],
            Annotated[int, Field(le=1, strict=True)],
        ]
    ] = Field(
        default=None,
        description="How much of bot's balance to use for the order (for open actions). How much of the reference open order (open_order_execution_id) to close (for close actions). 0=0%, 1=100%.",
    )
    take_profit: Optional[List[TPSL]] = None
    stop_loss: Optional[List[TPSL]] = None
    expiry_timestamp: Optional[StrictInt] = None
    client_order_id: Optional[StrictStr] = None
    position_id: Optional[StrictStr] = None
    leverage: Optional[Annotated[int, Field(strict=True, ge=1)]]
    margin_mode: Optional[MarginMode] = None
    __properties: ClassVar[List[str]] = [
        "id",
        "created_at",
        "updated_at",
        "execution_id",
        "open_order_execution_id",
        "action_type",
        "market_type",
        "strategy_id",
        "symbol",
        "is_limit",
        "limit_price",
        "allocation",
        "take_profit",
        "stop_loss",
        "expiry_timestamp",
        "client_order_id",
        "position_id",
        "leverage",
        "margin_mode",
    ]

    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 FuturesTradingAction 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 each item in take_profit (list)
        _items = []
        if self.take_profit:
            for _item_take_profit in self.take_profit:
                if _item_take_profit:
                    _items.append(_item_take_profit.to_dict())
            _dict["take_profit"] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in stop_loss (list)
        _items = []
        if self.stop_loss:
            for _item_stop_loss in self.stop_loss:
                if _item_stop_loss:
                    _items.append(_item_stop_loss.to_dict())
            _dict["stop_loss"] = _items
        # 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 open_order_execution_id (nullable) is None
        # and model_fields_set contains the field
        if (
            self.open_order_execution_id is None
            and "open_order_execution_id" in self.model_fields_set
        ):
            _dict["open_order_execution_id"] = None

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

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

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

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

        # set to None if expiry_timestamp (nullable) is None
        # and model_fields_set contains the field
        if (
            self.expiry_timestamp is None
            and "expiry_timestamp" in self.model_fields_set
        ):
            _dict["expiry_timestamp"] = 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 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 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 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

        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of FuturesTradingAction 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"),
                "execution_id": obj.get("execution_id"),
                "open_order_execution_id": obj.get("open_order_execution_id"),
                "action_type": obj.get("action_type"),
                "market_type": obj.get("market_type"),
                "strategy_id": obj.get("strategy_id"),
                "symbol": obj.get("symbol"),
                "is_limit": obj.get("is_limit"),
                "limit_price": obj.get("limit_price"),
                "allocation": obj.get("allocation"),
                "take_profit": (
                    [TPSL.from_dict(_item) for _item in obj["take_profit"]]
                    if obj.get("take_profit") is not None
                    else None
                ),
                "stop_loss": (
                    [TPSL.from_dict(_item) for _item in obj["stop_loss"]]
                    if obj.get("stop_loss") is not None
                    else None
                ),
                "expiry_timestamp": obj.get("expiry_timestamp"),
                "client_order_id": obj.get("client_order_id"),
                "position_id": obj.get("position_id"),
                "leverage": (
                    obj.get("leverage") if obj.get("leverage") is not None else 1
                ),
                "margin_mode": obj.get("margin_mode"),
            }
        )
        return _obj
