"""
Inventory Public Events — Contract v1.

رویدادهای عمومی ماژول انبار که سایر ماژول‌ها می‌توانند subscribe کنند.
هیچ ماژول دیگری نباید مستقیم از domain events وارد کند.
"""
from dataclasses import dataclass, field
from datetime import datetime
from decimal import Decimal
from typing import Optional
from uuid import UUID


# ═══════════════════════════════════════════════════
# Base
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class InventoryEvent:
    """رویداد پایه ماژول انبار."""
    event_id: UUID
    tenant_id: UUID
    occurred_at: datetime
    version: int = 1


# ═══════════════════════════════════════════════════
# Item Events (public)
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class ItemCreated(InventoryEvent):
    """کالای جدید ایجاد شد."""
    event_type: str = "inventory.item.created"
    item_id: UUID = None
    item_code: str = ""
    item_name: str = ""
    item_type_id: Optional[UUID] = None
    item_group_id: Optional[UUID] = None


@dataclass(frozen=True)
class ItemUpdated(InventoryEvent):
    """اطلاعات کالا بروزرسانی شد."""
    event_type: str = "inventory.item.updated"
    item_id: UUID = None
    item_code: str = ""
    changed_fields: list = field(default_factory=list)


@dataclass(frozen=True)
class ItemDeactivated(InventoryEvent):
    """کالا غیرفعال شد."""
    event_type: str = "inventory.item.deactivated"
    item_id: UUID = None
    item_code: str = ""


# ═══════════════════════════════════════════════════
# Stock Movement Events (public)
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class GoodsReceived(InventoryEvent):
    """رسید کالا ثبت شد."""
    event_type: str = "inventory.stock.goods_received"
    sle_id: UUID = None
    item_id: UUID = None
    item_code: str = ""
    warehouse_id: UUID = None
    quantity: Decimal = Decimal("0")
    uom_code: str = ""
    unit_cost: Decimal = Decimal("0")
    source_document_type: str = ""
    source_document_id: Optional[UUID] = None


@dataclass(frozen=True)
class GoodsIssued(InventoryEvent):
    """حواله کالا ثبت شد."""
    event_type: str = "inventory.stock.goods_issued"
    sle_id: UUID = None
    item_id: UUID = None
    item_code: str = ""
    warehouse_id: UUID = None
    quantity: Decimal = Decimal("0")
    uom_code: str = ""
    unit_cost: Decimal = Decimal("0")
    source_document_type: str = ""
    source_document_id: Optional[UUID] = None


@dataclass(frozen=True)
class StockTransferred(InventoryEvent):
    """موجودی بین انبارها جابجا شد."""
    event_type: str = "inventory.stock.transferred"
    item_id: UUID = None
    item_code: str = ""
    from_warehouse_id: UUID = None
    to_warehouse_id: UUID = None
    quantity: Decimal = Decimal("0")


@dataclass(frozen=True)
class StockAdjusted(InventoryEvent):
    """موجودی تعدیل شد."""
    event_type: str = "inventory.stock.adjusted"
    item_id: UUID = None
    item_code: str = ""
    warehouse_id: UUID = None
    adjustment_quantity: Decimal = Decimal("0")
    reason_code: str = ""


# ═══════════════════════════════════════════════════
# Batch & Serial Events (public)
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class BatchCreated(InventoryEvent):
    """بچ جدید ایجاد شد."""
    event_type: str = "inventory.batch.created"
    batch_id: UUID = None
    batch_number: str = ""
    item_id: UUID = None
    item_code: str = ""
    expiry_date: Optional[str] = None  # ISO format


@dataclass(frozen=True)
class BatchExpired(InventoryEvent):
    """بچ منقضی شد."""
    event_type: str = "inventory.batch.expired"
    batch_id: UUID = None
    batch_number: str = ""
    item_id: UUID = None


@dataclass(frozen=True)
class SerialCreated(InventoryEvent):
    """شماره سریال ایجاد شد."""
    event_type: str = "inventory.serial.created"
    serial_id: UUID = None
    serial_no: str = ""
    item_id: UUID = None
    item_code: str = ""


# ═══════════════════════════════════════════════════
# Reservation Events (public)
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class StockReserved(InventoryEvent):
    """موجودی رزرو شد."""
    event_type: str = "inventory.reservation.created"
    reservation_id: UUID = None
    item_id: UUID = None
    warehouse_id: UUID = None
    quantity: Decimal = Decimal("0")
    source_document_type: str = ""
    source_document_id: Optional[UUID] = None


@dataclass(frozen=True)
class ReservationReleased(InventoryEvent):
    """رزرو آزاد شد."""
    event_type: str = "inventory.reservation.released"
    reservation_id: UUID = None
    item_id: UUID = None
    quantity: Decimal = Decimal("0")


# ═══════════════════════════════════════════════════
# Quality Events (public)
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class InspectionCompleted(InventoryEvent):
    """بازرسی کیفی تکمیل شد."""
    event_type: str = "inventory.inspection.completed"
    inspection_lot_id: UUID = None
    item_id: UUID = None
    quality_decision: str = ""  # ACCEPTED/REJECTED/CONDITIONAL


@dataclass(frozen=True)
class PhysicalInventoryCompleted(InventoryEvent):
    """شمارش فیزیکی تکمیل شد."""
    event_type: str = "inventory.physical_inventory.completed"
    physical_inventory_id: UUID = None
    warehouse_id: Optional[UUID] = None
    total_variance_value: Decimal = Decimal("0")


# ═══════════════════════════════════════════════════
# Costing Events (public)
# ═══════════════════════════════════════════════════

@dataclass(frozen=True)
class FinancialPostingReady(InventoryEvent):
    """ارسال مالی آماده ارسال به حسابداری."""
    event_type: str = "inventory.financial_posting.ready"
    posting_id: UUID = None
    sle_id: UUID = None
    debit_account: str = ""
    credit_account: str = ""
    amount: Decimal = Decimal("0")
    currency_code: str = "IRR"
