from typing import Any, Dict, List, Self, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..constants.trading import (
    ConditionalCloseOrderType,
    OrderType,
    SelfTradePreventionStrategy,
    TimeInForce,
    Trigger,
    TypeOrder,
)
from ..security import get_nonce
from ..types import UNSET, Unset


@_attrs_define
class AddStandardOrderRequestBody:
    """
    Attributes:
        nonce (int): Nonce used in construction of `API-Sign` header. Default `../security.get_nonce`
        ordertype (Ordertype): Order type
        type (TypeOrder): Order direction (buy/sell)
        volume (str): Order quantity in terms of the base asset
            > Note: Volume can be specified as `0` for closing margin orders to automatically fill the requisite quantity.
        pair (str): Asset pair `id` or `altname`
        userref (Union[Unset, int]): User reference id

            `userref` is an optional user-specified integer id that can be associated with any number of orders. Many
            clients choose a `userref` corresponding to a unique integer id generated by their systems (e.g. a timestamp).
            However, because we don't enforce uniqueness on our side, it can also be used to easily group orders by pair,
            side, strategy, etc. This allows clients to more readily cancel or query information about orders in a
            particular group, with fewer API calls by using `userref` instead of our `txid`, where supported.
        displayvol (Union[Unset, str]): Used to create an iceberg order, this is the visible order quantity in terms of
            the base asset. The rest of the order will be hidden, although the full `volume` can be filled at any time by
            any order of that size or larger that matches in the order book. `displayvol` can only be used with the `limit`
            order type, must be greater than `0`, and less than `volume`.
        price (Union[Unset, str]): Price:

            * Limit price for `limit` orders
            * Trigger price for `stop-loss`, `stop-loss-limit`, `take-profit` and `take-profit-limit` orders
        price2 (Union[Unset, str]): Secondary Price:

            * Limit price for `stop-loss-limit` and `take-profit-limit` orders

            >  Note: Either `price` or `price2` can be preceded by `+`, `-`, or `#` to specify the order price as an offset
            relative to the last traded price. `+` adds the amount to, and `-` subtracts the amount from the last traded
            price. `#` will either add or subtract the amount to the last traded price, depending on the direction and order
            type used. Relative prices can be suffixed with a `%` to signify the relative amount as a percentage.
        trigger (Union[Unset, Trigger]): Price signal used to trigger `stop-loss`, `stop-
            loss-limit`, `take-profit` and `take-profit-limit` orders
            >  Note: This `trigger` type will as well be used for associated conditional close orders.
             Default: Trigger.LAST.
        leverage (Union[Unset, str]): Amount of leverage desired (default: none)
        reduce_only (Union[Unset, bool]): If `true`, order will only reduce a currently open position, not increase it
            or open a new position.
        stptype (Union[Unset, SelfTradePreventionStrategy]): Self trade prevention behavior definition:
            * cancel-newest - if self trade is triggered, arriving order will be canceled
            * cancel-oldest - if self trade is triggered, resting order will be canceled
            * cancel-both - if self trade is triggered, both arriving and resting orders will be canceled
             Default: SelfTradePreventionStrategy.CANCEL_NEWEST.
        oflags (Union[Unset, str]): Comma delimited list of order flags

              * `post` post-only order (available when ordertype = limit)
              * `fcib` prefer fee in base currency (default if selling)
              * `fciq` prefer fee in quote currency (default if buying, mutually exclusive with `fcib`)
              * `nompp` disable [market price protection](https://support.kraken.com/hc/en-us/articles/201648183-Market-
            Price-Protection) for market orders
              * `viqc`  order volume expressed in quote currency. This is supported only for market orders.
        timeinforce (Union[Unset, TimeInForce]): Time-in-force of the order to specify how
            long it should remain in the order book before being cancelled. GTC (Good-'til-cancelled) is default if the
            parameter is omitted. IOC (immediate-or-cancel) will immediately execute the amount possible and cancel any
            remaining balance rather than resting in the book. GTD (good-'til-date), if specified, must coincide with a
            desired `expiretm`.
             Default: TimeInForce.GTC.
        starttm (Union[Unset, str]): Scheduled start time, can be specified as an absolute timestamp or as a number of
            seconds in the future:
              * `0` now (default)
              * `<n>` = unix timestamp of start time
              * `+<n>` = schedule start time `<n>` seconds from now
                * Note that URL encoding of the `+` character changes it to a space, so please use `%2b` followed by the
            number of seconds instead of `+`
        expiretm (Union[Unset, str]): Expiration time, also can be specified as an absolute timestamp or as a number of
            seconds in the future:
              * `0` no expiration (default)
              * `<n>` = unix timestamp of expiration time
              * `+<n>` = expire `<n>` seconds from now, minimum 5 seconds
                * Note that URL encoding of the `+` character changes it to a space, so please use `%2b` followed by the
            number of seconds instead of `+`
        closeordertype (Union[Unset, ConditionalCloseOrderType]): Conditional close order type
            > Note: [Conditional close orders](https://support.kraken.com/hc/en-us/articles/360038640052-Conditional-Close)
            are triggered by execution of the primary order in the same quantity and opposite direction, but once triggered
            are __independent orders__ that may reduce or increase net position
        closeprice (Union[Unset, str]): Conditional close order `price`
        closeprice2 (Union[Unset, str]): Conditional close order `price2`
        deadline (Union[Unset, str]): RFC3339 timestamp (e.g. 2021-04-01T00:18:45Z) after which the matching engine
            should reject the new order request, in presence of latency or order queueing: min now() + 2 seconds, max now()
            + 60 seconds.
        validate (Union[Unset, bool]): Validate inputs only. Do not submit order.
    """

    ordertype: OrderType
    type: TypeOrder
    volume: str
    pair: str
    nonce: int = get_nonce()
    userref: Union[Unset, int] = UNSET
    displayvol: Union[Unset, str] = UNSET
    price: Union[Unset, str] = UNSET
    price2: Union[Unset, str] = UNSET
    trigger: Union[Unset, Trigger] = Trigger.LAST
    leverage: Union[Unset, str] = UNSET
    reduce_only: Union[Unset, bool] = False
    stptype: Union[
        Unset, SelfTradePreventionStrategy
    ] = SelfTradePreventionStrategy.CANCEL_NEWEST
    oflags: Union[Unset, str] = UNSET
    timeinforce: Union[Unset, TimeInForce] = TimeInForce.GTC
    starttm: Union[Unset, str] = UNSET
    expiretm: Union[Unset, str] = UNSET
    closeordertype: Union[Unset, ConditionalCloseOrderType] = UNSET
    closeprice: Union[Unset, str] = UNSET
    closeprice2: Union[Unset, str] = UNSET
    deadline: Union[Unset, str] = UNSET
    validate: Union[Unset, bool] = False
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        nonce = self.nonce
        ordertype = self.ordertype.value

        type = self.type.value

        volume = self.volume
        pair = self.pair
        userref = self.userref
        displayvol = self.displayvol
        price = self.price
        price2 = self.price2
        trigger: Union[Unset, str] = UNSET
        if not isinstance(self.trigger, Unset):
            trigger = self.trigger.value

        leverage = self.leverage
        reduce_only = self.reduce_only
        stptype: Union[Unset, str] = UNSET
        if not isinstance(self.stptype, Unset):
            stptype = self.stptype.value

        oflags = self.oflags
        timeinforce: Union[Unset, str] = UNSET
        if not isinstance(self.timeinforce, Unset):
            timeinforce = self.timeinforce.value

        starttm = self.starttm
        expiretm = self.expiretm
        closeordertype: Union[Unset, str] = UNSET
        if not isinstance(self.closeordertype, Unset):
            closeordertype = self.closeordertype.value

        closeprice = self.closeprice
        closeprice2 = self.closeprice2
        deadline = self.deadline
        validate = self.validate

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "nonce": nonce,
                "ordertype": ordertype,
                "type": type,
                "volume": volume,
                "pair": pair,
            }
        )
        if userref is not UNSET:
            field_dict["userref"] = userref
        if displayvol is not UNSET:
            field_dict["displayvol"] = displayvol
        if price is not UNSET:
            field_dict["price"] = price
        if price2 is not UNSET:
            field_dict["price2"] = price2
        if trigger is not UNSET:
            field_dict["trigger"] = trigger
        if leverage is not UNSET:
            field_dict["leverage"] = leverage
        if reduce_only is not UNSET:
            field_dict["reduce_only"] = reduce_only
        if stptype is not UNSET:
            field_dict["stptype"] = stptype
        if oflags is not UNSET:
            field_dict["oflags"] = oflags
        if timeinforce is not UNSET:
            field_dict["timeinforce"] = timeinforce
        if starttm is not UNSET:
            field_dict["starttm"] = starttm
        if expiretm is not UNSET:
            field_dict["expiretm"] = expiretm
        if closeordertype is not UNSET:
            field_dict["close[ordertype]"] = closeordertype
        if closeprice is not UNSET:
            field_dict["close[price]"] = closeprice
        if closeprice2 is not UNSET:
            field_dict["close[price2]"] = closeprice2
        if deadline is not UNSET:
            field_dict["deadline"] = deadline
        if validate is not UNSET:
            field_dict["validate"] = validate

        return field_dict

    @classmethod
    def from_dict(cls: Self, src_dict: Dict[str, Any]) -> Self:
        d = src_dict.copy()
        nonce = d.pop("nonce", get_nonce())

        ordertype = OrderType(d.pop("ordertype"))

        type = TypeOrder(d.pop("type"))

        volume = d.pop("volume")

        pair = d.pop("pair")

        userref = d.pop("userref", UNSET)

        displayvol = d.pop("displayvol", UNSET)

        price = d.pop("price", UNSET)

        price2 = d.pop("price2", UNSET)

        _trigger = d.pop("trigger", UNSET)
        trigger: Union[Unset, Trigger]
        trigger = UNSET if isinstance(_trigger, Unset) else Trigger(_trigger)

        leverage = d.pop("leverage", UNSET)

        reduce_only = d.pop("reduce_only", UNSET)

        _stptype = d.pop("stptype", UNSET)
        stptype: Union[Unset, SelfTradePreventionStrategy]
        if isinstance(_stptype, Unset):
            stptype = UNSET
        else:
            stptype = SelfTradePreventionStrategy(_stptype)

        oflags = d.pop("oflags", UNSET)

        _timeinforce = d.pop("timeinforce", UNSET)
        timeinforce: Union[Unset, TimeInForce]
        if isinstance(_timeinforce, Unset):
            timeinforce = UNSET
        else:
            timeinforce = TimeInForce(_timeinforce)

        starttm = d.pop("starttm", UNSET)

        expiretm = d.pop("expiretm", UNSET)

        _closeordertype = d.pop("close[ordertype]", UNSET)
        closeordertype: Union[Unset, ConditionalCloseOrderType]
        if isinstance(_closeordertype, Unset):
            closeordertype = UNSET
        else:
            closeordertype = ConditionalCloseOrderType(_closeordertype)

        closeprice = d.pop("close[price]", UNSET)

        closeprice2 = d.pop("close[price2]", UNSET)

        deadline = d.pop("deadline", UNSET)

        validate = d.pop("validate", UNSET)

        add_standard_order_request_body = cls(
            nonce=nonce,
            ordertype=ordertype,
            type=type,
            volume=volume,
            pair=pair,
            userref=userref,
            displayvol=displayvol,
            price=price,
            price2=price2,
            trigger=trigger,
            leverage=leverage,
            reduce_only=reduce_only,
            stptype=stptype,
            oflags=oflags,
            timeinforce=timeinforce,
            starttm=starttm,
            expiretm=expiretm,
            closeordertype=closeordertype,
            closeprice=closeprice,
            closeprice2=closeprice2,
            deadline=deadline,
            validate=validate,
        )

        add_standard_order_request_body.additional_properties = d
        return add_standard_order_request_body

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties
