# 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: 2.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, StrictInt, StrictStr, field_validator
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from crypticorn.trade.client.models.tpsl_create import TPSLCreate
from crypticorn.trade.client.models.trading_action_type import TradingActionType
from typing import Set
from typing_extensions import Self


class FuturesTradingActionCreate(BaseModel):
    """
    Model for sending futures trading actions to the API
    """  # noqa: E501

    leverage: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(
        default=1, description="Leverage to use for futures trades. Default is 1."
    )
    margin_mode: Optional[StrictStr] = Field(
        default="isolated",
        description="Margin mode for futures trades. Default is isolated.",
    )
    execution_id: Optional[StrictStr] = None
    open_order_execution_id: Optional[StrictStr] = None
    action_type: TradingActionType = Field(description="The type of action.")
    market_type: Optional[StrictStr] = Field(
        default="futures",
        description="The type of market the action is for. Must be set to futures.",
    )
    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)"
    )
    limit_price: Optional[StrictStr] = None
    allocation: StrictStr = Field(
        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[TPSLCreate]] = None
    stop_loss: Optional[List[TPSLCreate]] = None
    expiry_timestamp: Optional[StrictInt] = None
    __properties: ClassVar[List[str]] = [
        "leverage",
        "margin_mode",
        "execution_id",
        "open_order_execution_id",
        "action_type",
        "market_type",
        "strategy_id",
        "symbol",
        "limit_price",
        "allocation",
        "take_profit",
        "stop_loss",
        "expiry_timestamp",
    ]

    @field_validator("margin_mode")
    def margin_mode_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(["isolated", "cross"]):
            raise ValueError("must be one of enum values ('isolated', 'cross')")
        return value

    @field_validator("market_type")
    def market_type_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(["spot", "futures"]):
            raise ValueError("must be one of enum values ('spot', 'futures')")
        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 FuturesTradingActionCreate 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 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

        return _dict

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

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

        _obj = cls.model_validate(
            {
                "leverage": obj.get("leverage")
                if obj.get("leverage") is not None
                else 1,
                "margin_mode": obj.get("margin_mode")
                if obj.get("margin_mode") is not None
                else "isolated",
                "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")
                if obj.get("market_type") is not None
                else "futures",
                "strategy_id": obj.get("strategy_id"),
                "symbol": obj.get("symbol"),
                "limit_price": obj.get("limit_price"),
                "allocation": obj.get("allocation"),
                "take_profit": [
                    TPSLCreate.from_dict(_item) for _item in obj["take_profit"]
                ]
                if obj.get("take_profit") is not None
                else None,
                "stop_loss": [TPSLCreate.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"),
            }
        )
        return _obj
