"""
=========================================
CV6 AI Trading OS — Trading Events
=========================================
Every material change to trading state is expressed as ONE immutable
TradingEvent. Producers (execution paths, broker-fill confirmation,
position monitor) emit events; the single consumer is the
TradingStateManager, which is the only thing allowed to mutate state.

This is the backbone of the "one source of truth" architecture: no
module updates positions/capital/PnL directly — it emits an event and
lets the state manager apply it.
"""

import time
import uuid
from dataclasses import dataclass, field, asdict
from enum import Enum
from typing import Optional


class EventType(str, Enum):
    ORDER_PLACED           = "ORDER_PLACED"
    ORDER_FILLED           = "ORDER_FILLED"
    ORDER_PARTIALLY_FILLED = "ORDER_PARTIALLY_FILLED"
    ORDER_REJECTED         = "ORDER_REJECTED"
    POSITION_CLOSED        = "POSITION_CLOSED"
    PRICE_TICK             = "PRICE_TICK"


@dataclass
class TradingEvent:
    event_type:      EventType
    symbol:          str
    broker:          str   = ""
    exchange:        str   = "NSE"
    side:            str   = ""      # BUY | SELL (of the order/position)
    order_id:        str   = ""
    quantity:        int   = 0       # intended qty
    filled_quantity: int   = 0       # confirmed filled qty
    price:           float = 0.0     # intended/limit price
    avg_price:       float = 0.0     # confirmed avg fill price
    fill_status:     str   = ""      # FILLED | PARTIALLY_FILLED | REJECTED | ...
    pnl:             float = 0.0     # realized P&L (POSITION_CLOSED only)
    reason:          str   = ""      # exit/reject reason
    style:           str   = ""      # INTRADAY | SWING | FNO | SCALPING | LONG_TERM
    strategy:        str   = ""
    stop_loss:       float = 0.0
    target_price:    float = 0.0
    sl_order_id:     str   = ""      # broker-side stop-loss order id (Tier-1)
    ai_confidence:   float = 0.0
    charges:         float = 0.0
    mode:            str   = "REAL"  # REAL | PAPER
    ltp:             float = 0.0     # PRICE_TICK only
    source:          str   = ""      # which producer emitted this (audit)
    event_id:        str   = field(default_factory=lambda: str(uuid.uuid4()))
    ts:              float = field(default_factory=time.time)

    def to_dict(self) -> dict:
        d = asdict(self)
        et = self.event_type
        d["event_type"] = et.value if isinstance(et, EventType) else str(et)
        return d
