import enum
from dataclasses import dataclass
from datetime import date

from django.db.models import TextChoices
from pydantic import BaseModel


class ExecutionStatus(TextChoices):
    PENDING = "PENDING", "Pending"
    IN_DRAFT = "IN_DRAFT", "In Draft"
    COMPLETED = "COMPLETED", "Completed"
    CANCELLED = "CANCELLED", "Cancelled"
    REJECTED = "REJECTED", "Rejected"
    FAILED = "FAILED", "Failed"
    UNKNOWN = "UNKNOWN", "Unknown"


class ExecutionInstruction(TextChoices):
    MARKET_ON_CLOSE = "MARKET_ON_CLOSE", "Market On Close"  # no parameter
    GUARANTEED_MARKET_ON_CLOSE = "GUARANTEED_MARKET_ON_CLOSE", "Guaranteed Market On Close"  # no parameter
    GUARANTEED_MARKET_ON_OPEN = "GUARANTEED_MARKET_ON_OPEN", "Guaranteed Market On Open"  # no parameter
    GPW_MARKET_ON_CLOSE = "GPW_MARKET_ON_CLOSE", "GPW Market On Close"  # no parameter
    MARKET_ON_OPEN = "MARKET_ON_OPEN", "Market On Open"  # no parameter
    IN_LINE_WITH_VOLUME = "IN_LINE_WITH_VOLUME", "In Line With Volume"  # 1 parameter "Percentage"
    LIMIT_ORDER = "LIMIT_ORDER", "Limit Order"  # 2 parameters "limit and cutoff"
    VWAP = "VWAP", "VWAP"  # 2 parameters
    TWAP = "TWAP", "TWAP"  # 2 paramters


@dataclass(frozen=True)
class Order:
    class AssetType(enum.Enum):
        EQUITY = "EQUITY"
        AMERICAN_DEPOSITORY_RECEIPT = "AMERICAN_DEPOSITORY_RECEIPT"

    id: int | str
    trade_date: date
    target_weight: float

    # Instrument identifier
    asset_class: AssetType = AssetType.EQUITY
    refinitiv_identifier_code: str | None = None
    bloomberg_ticker: str | None = None
    sedol: str | None = None

    weighting: float | None = None
    target_shares: float | None = None
    shares: float | None = None
    execution_price: float | None = None
    execution_instruction: ExecutionInstruction = ExecutionInstruction.MARKET_ON_CLOSE.value
    execution_instruction_parameters: dict | None = None
    comment: str = ""


class RebalancingResponse(BaseModel):
    message: str
    status: ExecutionStatus
    execution_kwargs: dict
    orders: list[Order]
