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

from __future__ import annotations
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 Order(Struct, omit_defaults=True):
    a: Annotated[str, Meta(title="account")]
    d: Annotated[OrderDir, Meta(title="dir")]
    id: definitions.OrderId
    o: Annotated[definitions.OrderStatus, Meta(title="status")]
    q: Annotated[Decimal, Meta(title="quantity")]
    s: Annotated[str, Meta(title="symbol")]
    src: Annotated[definitions.OrderSource, Meta(title="source")]
    tif: Annotated[TimeInForce, Meta(title="time_in_force")]
    tn: Annotated[int, Meta(ge=0, title="recv_time_ns")]
    ts: Annotated[
        int,
        Meta(
            description="Timestamp that the Architect OMS first received the order.\n\nFor reconciled orders, this could be very far in the future relative to the exchange order timestamp.",
            title="recv_time",
        ),
    ]
    """
    Timestamp that the Architect OMS first received the order.

    For reconciled orders, this could be very far in the future relative to the exchange order timestamp.
    """
    u: Annotated[definitions.UserId, Meta(title="trader")]
    ve: Annotated[str, Meta(title="execution_venue")]
    xq: Annotated[Decimal, Meta(title="filled_quantity")]
    k: Annotated[definitions.OrderType, Meta(title="order_type")]
    eid: Optional[Annotated[Optional[str], Meta(title="exchange_order_id")]] = None
    pid: Optional[Annotated[Optional[definitions.OrderId], Meta(title="parent_id")]] = (
        None
    )
    r: Optional[
        Annotated[Optional[definitions.OrderRejectReason], Meta(title="reject_reason")]
    ] = None
    rm: Optional[Annotated[Optional[str], Meta(title="reject_message")]] = None
    ss: Optional[Annotated[Optional[bool], Meta(title="is_short_sale")]] = None
    xp: Optional[Annotated[Optional[Decimal], Meta(title="average_fill_price")]] = 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,
        account: str,
        dir: OrderDir,
        id: definitions.OrderId,
        status: definitions.OrderStatus,
        quantity: Decimal,
        symbol: str,
        source: definitions.OrderSource,
        time_in_force: TimeInForce,
        recv_time_ns: int,
        recv_time: int,
        trader: definitions.UserId,
        execution_venue: str,
        filled_quantity: Decimal,
        order_type: definitions.OrderType,
        exchange_order_id: Optional[str] = None,
        parent_id: Optional[definitions.OrderId] = None,
        reject_reason: Optional[definitions.OrderRejectReason] = None,
        reject_message: Optional[str] = None,
        is_short_sale: Optional[bool] = None,
        average_fill_price: Optional[Decimal] = 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(
            account,
            dir,
            id,
            status,
            quantity,
            symbol,
            source,
            time_in_force,
            recv_time_ns,
            recv_time,
            trader,
            execution_venue,
            filled_quantity,
            order_type,
            exchange_order_id,
            parent_id,
            reject_reason,
            reject_message,
            is_short_sale,
            average_fill_price,
            limit_price,
            post_only,
            trigger_price,
            stop_loss,
            take_profit_price,
        )

    def __str__(self) -> str:
        return f"Order(account={self.a},dir={self.d},id={self.id},status={self.o},quantity={self.q},symbol={self.s},source={self.src},time_in_force={self.tif},recv_time_ns={self.tn},recv_time={self.ts},trader={self.u},execution_venue={self.ve},filled_quantity={self.xq},order_type={self.k},exchange_order_id={self.eid},parent_id={self.pid},reject_reason={self.r},reject_message={self.rm},is_short_sale={self.ss},average_fill_price={self.xp},limit_price={self.p},post_only={self.po},trigger_price={self.tp},stop_loss={self.sl},take_profit_price={self.tpp})"

    @property
    def account(self) -> str:
        return self.a

    @account.setter
    def account(self, value: str) -> None:
        self.a = value

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

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

    @property
    def status(self) -> definitions.OrderStatus:
        return self.o

    @status.setter
    def status(self, value: definitions.OrderStatus) -> None:
        self.o = 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 source(self) -> definitions.OrderSource:
        return self.src

    @source.setter
    def source(self, value: definitions.OrderSource) -> None:
        self.src = 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 recv_time_ns(self) -> int:
        return self.tn

    @recv_time_ns.setter
    def recv_time_ns(self, value: int) -> None:
        self.tn = value

    @property
    def recv_time(self) -> int:
        return self.ts

    @recv_time.setter
    def recv_time(self, value: int) -> None:
        self.ts = value

    @property
    def trader(self) -> definitions.UserId:
        return self.u

    @trader.setter
    def trader(self, value: definitions.UserId) -> None:
        self.u = value

    @property
    def execution_venue(self) -> str:
        return self.ve

    @execution_venue.setter
    def execution_venue(self, value: str) -> None:
        self.ve = value

    @property
    def filled_quantity(self) -> Decimal:
        return self.xq

    @filled_quantity.setter
    def filled_quantity(self, value: Decimal) -> None:
        self.xq = 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 exchange_order_id(self) -> Optional[str]:
        return self.eid

    @exchange_order_id.setter
    def exchange_order_id(self, value: Optional[str]) -> None:
        self.eid = 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 reject_reason(self) -> Optional[definitions.OrderRejectReason]:
        return self.r

    @reject_reason.setter
    def reject_reason(self, value: Optional[definitions.OrderRejectReason]) -> None:
        self.r = value

    @property
    def reject_message(self) -> Optional[str]:
        return self.rm

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

    @property
    def is_short_sale(self) -> Optional[bool]:
        return self.ss

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

    @property
    def average_fill_price(self) -> Optional[Decimal]:
        return self.xp

    @average_fill_price.setter
    def average_fill_price(self, value: Optional[Decimal]) -> None:
        self.xp = 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

    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 Order 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 Order 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 Order 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 Order 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 Order 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 Order 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 Order 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 Order should not have fields ['tp']"
                )
