# generated by datamodel-codegen:
#   filename:  Oms/PlaceOrderRequest.json

from __future__ import annotations
from architect_py.grpc.models.Oms.Order import Order
from architect_py.common_types import OrderDir, TimeInForce

from decimal import Decimal
from typing import Annotated, Optional

from msgspec import Meta, Struct

from .. import definitions


class PlaceOrderRequest(Struct, omit_defaults=True):
    d: Annotated[OrderDir, Meta(title="dir")]
    q: Annotated[Decimal, Meta(title="quantity")]
    s: Annotated[str, Meta(title="symbol")]
    tif: Annotated[TimeInForce, Meta(title="time_in_force")]
    k: Annotated[definitions.OrderType, Meta(title="order_type")]
    a: Optional[
        Annotated[Optional[definitions.AccountIdOrName], Meta(title="account")]
    ] = None
    id: Optional[
        Annotated[
            Optional[definitions.OrderId],
            Meta(
                description="If not specified, one will be generated for you; note, in that case, you won't know for sure if the specific request went through."
            ),
        ]
    ] = None
    """
    If not specified, one will be generated for you; note, in that case, you won't know for sure if the specific request went through.
    """
    pid: Optional[Annotated[Optional[definitions.OrderId], Meta(title="parent_id")]] = (
        None
    )
    src: Optional[
        Annotated[Optional[definitions.OrderSource], Meta(title="source")]
    ] = None
    u: Optional[
        Annotated[Optional[definitions.TraderIdOrEmail], Meta(title="trader")]
    ] = None
    x: Optional[Annotated[Optional[str], Meta(title="execution_venue")]] = None
    p: Optional[Annotated[Decimal, Meta(title="limit_price")]] = None
    po: Optional[Annotated[bool, Meta(title="post_only")]] = None
    tp: Optional[Annotated[Decimal, Meta(title="trigger_price")]] = None
    sl: Optional[
        Annotated[Optional[definitions.TriggerLimitOrderType], Meta(title="stop_loss")]
    ] = None
    tpp: Optional[Annotated[Optional[Decimal], Meta(title="take_profit_price")]] = None

    # Constructor that takes all field titles as arguments for convenience
    @classmethod
    def new(
        cls,
        dir: OrderDir,
        quantity: Decimal,
        symbol: str,
        time_in_force: TimeInForce,
        order_type: definitions.OrderType,
        account: Optional[definitions.AccountIdOrName] = None,
        id: Optional[definitions.OrderId] = None,
        parent_id: Optional[definitions.OrderId] = None,
        source: Optional[definitions.OrderSource] = None,
        trader: Optional[definitions.TraderIdOrEmail] = None,
        execution_venue: Optional[str] = None,
        limit_price: Optional[Decimal] = None,
        post_only: Optional[bool] = None,
        trigger_price: Optional[Decimal] = None,
        stop_loss: Optional[definitions.TriggerLimitOrderType] = None,
        take_profit_price: Optional[Decimal] = None,
    ):
        return cls(
            dir,
            quantity,
            symbol,
            time_in_force,
            order_type,
            account,
            id,
            parent_id,
            source,
            trader,
            execution_venue,
            limit_price,
            post_only,
            trigger_price,
            stop_loss,
            take_profit_price,
        )

    def __str__(self) -> str:
        return f"PlaceOrderRequest(dir={self.d},quantity={self.q},symbol={self.s},time_in_force={self.tif},order_type={self.k},account={self.a},id={self.id},parent_id={self.pid},source={self.src},trader={self.u},execution_venue={self.x},limit_price={self.p},post_only={self.po},trigger_price={self.tp},stop_loss={self.sl},take_profit_price={self.tpp})"

    @property
    def dir(self) -> OrderDir:
        return self.d

    @dir.setter
    def dir(self, value: OrderDir) -> None:
        self.d = value

    @property
    def quantity(self) -> Decimal:
        return self.q

    @quantity.setter
    def quantity(self, value: Decimal) -> None:
        self.q = value

    @property
    def symbol(self) -> str:
        return self.s

    @symbol.setter
    def symbol(self, value: str) -> None:
        self.s = value

    @property
    def time_in_force(self) -> TimeInForce:
        return self.tif

    @time_in_force.setter
    def time_in_force(self, value: TimeInForce) -> None:
        self.tif = value

    @property
    def order_type(self) -> definitions.OrderType:
        return self.k

    @order_type.setter
    def order_type(self, value: definitions.OrderType) -> None:
        self.k = value

    @property
    def account(self) -> Optional[definitions.AccountIdOrName]:
        return self.a

    @account.setter
    def account(self, value: Optional[definitions.AccountIdOrName]) -> None:
        self.a = value

    @property
    def parent_id(self) -> Optional[definitions.OrderId]:
        return self.pid

    @parent_id.setter
    def parent_id(self, value: Optional[definitions.OrderId]) -> None:
        self.pid = value

    @property
    def source(self) -> Optional[definitions.OrderSource]:
        return self.src

    @source.setter
    def source(self, value: Optional[definitions.OrderSource]) -> None:
        self.src = value

    @property
    def trader(self) -> Optional[definitions.TraderIdOrEmail]:
        return self.u

    @trader.setter
    def trader(self, value: Optional[definitions.TraderIdOrEmail]) -> None:
        self.u = value

    @property
    def execution_venue(self) -> Optional[str]:
        return self.x

    @execution_venue.setter
    def execution_venue(self, value: Optional[str]) -> None:
        self.x = value

    @property
    def limit_price(self) -> Optional[Decimal]:
        return self.p

    @limit_price.setter
    def limit_price(self, value: Optional[Decimal]) -> None:
        self.p = value

    @property
    def post_only(self) -> Optional[bool]:
        return self.po

    @post_only.setter
    def post_only(self, value: Optional[bool]) -> None:
        self.po = value

    @property
    def trigger_price(self) -> Optional[Decimal]:
        return self.tp

    @trigger_price.setter
    def trigger_price(self, value: Optional[Decimal]) -> None:
        self.tp = value

    @property
    def stop_loss(self) -> Optional[definitions.TriggerLimitOrderType]:
        return self.sl

    @stop_loss.setter
    def stop_loss(self, value: Optional[definitions.TriggerLimitOrderType]) -> None:
        self.sl = value

    @property
    def take_profit_price(self) -> Optional[Decimal]:
        return self.tpp

    @take_profit_price.setter
    def take_profit_price(self, value: Optional[Decimal]) -> None:
        self.tpp = value

    @staticmethod
    def get_response_type():
        return Order

    @staticmethod
    def get_unannotated_response_type():
        return Order

    @staticmethod
    def get_route() -> str:
        return "/json.architect.Oms/PlaceOrder"

    @staticmethod
    def get_rpc_method():
        return "unary"

    def __post_init__(self):
        if self.k == "LIMIT":
            if not all(getattr(self, key) is not None for key in ["p", "po"]):
                raise ValueError(
                    f"When field k (order_type) is of value LIMIT, class PlaceOrderRequest requires fields ['limit_price (p)', 'post_only (po)']"
                )
            elif any(getattr(self, key) is not None for key in ["tp"]):
                raise ValueError(
                    f"When field k (order_type) is of value LIMIT, class PlaceOrderRequest should not have fields ['tp']"
                )
        elif self.k == "STOP_LOSS_LIMIT":
            if not all(getattr(self, key) is not None for key in ["p", "tp"]):
                raise ValueError(
                    f"When field k (order_type) is of value STOP_LOSS_LIMIT, class PlaceOrderRequest requires fields ['limit_price (p)', 'trigger_price (tp)']"
                )
            elif any(getattr(self, key) is not None for key in ["po"]):
                raise ValueError(
                    f"When field k (order_type) is of value STOP_LOSS_LIMIT, class PlaceOrderRequest should not have fields ['po']"
                )
        elif self.k == "TAKE_PROFIT_LIMIT":
            if not all(getattr(self, key) is not None for key in ["p", "tp"]):
                raise ValueError(
                    f"When field k (order_type) is of value TAKE_PROFIT_LIMIT, class PlaceOrderRequest requires fields ['limit_price (p)', 'trigger_price (tp)']"
                )
            elif any(getattr(self, key) is not None for key in ["po"]):
                raise ValueError(
                    f"When field k (order_type) is of value TAKE_PROFIT_LIMIT, class PlaceOrderRequest should not have fields ['po']"
                )
        elif self.k == "BRACKET":
            if not all(getattr(self, key) is not None for key in ["p", "po"]):
                raise ValueError(
                    f"When field k (order_type) is of value BRACKET, class PlaceOrderRequest requires fields ['limit_price (p)', 'post_only (po)']"
                )
            elif any(getattr(self, key) is not None for key in ["tp"]):
                raise ValueError(
                    f"When field k (order_type) is of value BRACKET, class PlaceOrderRequest should not have fields ['tp']"
                )
