"""
SCM Domain Entities — Request for Quotation (RFQ).

درخواست استعلام، آیتم‌ها، پاسخ تأمین‌کنندگان.
"""
from dataclasses import dataclass, field
from datetime import date, datetime
from decimal import Decimal
from enum import Enum
from typing import Optional, List
from uuid import UUID

from shared.base_classes.entity import TenantEntity


class RFQStatus(str, Enum):
    DRAFT = "DRAFT"
    SENT = "SENT"
    CLOSED = "CLOSED"
    CANCELLED = "CANCELLED"
    AWARDED = "AWARDED"


class RFQResponseStatus(str, Enum):
    PENDING = "PENDING"
    RECEIVED = "RECEIVED"
    AWARDED = "AWARDED"
    REJECTED = "REJECTED"


@dataclass
class RFQLine(TenantEntity):
    """آیتم استعلام."""
    rfq_id: Optional[UUID] = None
    line_number: int = 0
    item_id: Optional[UUID] = None
    item_code: str = ""
    item_name: str = ""
    description: str = ""
    quantity: Decimal = Decimal("0")
    uom_id: Optional[UUID] = None
    uom_code: str = ""
    required_date: Optional[date] = None
    notes: str = ""


@dataclass
class RFQVendorResponseLine(TenantEntity):
    """آیتم پاسخ تأمین‌کننده."""
    response_id: Optional[UUID] = None
    rfq_line_id: Optional[UUID] = None
    line_number: int = 0
    unit_price: Decimal = Decimal("0")
    total_price: Decimal = Decimal("0")
    delivery_days: int = 0
    notes: str = ""

    def calculate_total(self, quantity: Decimal):
        self.total_price = self.unit_price * quantity


@dataclass
class RFQVendorResponse(TenantEntity):
    """پاسخ تأمین‌کننده به استعلام."""
    rfq_id: Optional[UUID] = None
    vendor_id: Optional[UUID] = None
    vendor_name: str = ""
    status: RFQResponseStatus = RFQResponseStatus.PENDING
    response_date: Optional[date] = None
    validity_date: Optional[date] = None
    total_amount: Decimal = Decimal("0")
    currency_code: str = "IRR"
    payment_terms: str = ""
    delivery_terms: str = ""
    notes: str = ""
    lines: List[RFQVendorResponseLine] = field(default_factory=list)

    def calculate_total(self):
        self.total_amount = sum(line.total_price for line in self.lines)


@dataclass
class RFQ(TenantEntity):
    """درخواست استعلام — Aggregate Root."""
    rfq_number: str = ""
    title: str = ""
    description: str = ""
    status: RFQStatus = RFQStatus.DRAFT

    # Source
    pr_id: Optional[UUID] = None
    pr_number: str = ""

    # Dates
    issue_date: Optional[date] = None
    closing_date: Optional[date] = None
    required_date: Optional[date] = None

    # Buyer
    buyer_id: Optional[UUID] = None
    buyer_name: str = ""

    currency_code: str = "IRR"
    notes: str = ""

    # Related
    lines: List[RFQLine] = field(default_factory=list)
    vendor_responses: List[RFQVendorResponse] = field(default_factory=list)
    invited_vendor_ids: List[UUID] = field(default_factory=list)

    def send(self):
        """ارسال استعلام به تأمین‌کنندگان."""
        if self.status != RFQStatus.DRAFT:
            raise ValueError("Only DRAFT RFQs can be sent")
        if not self.lines:
            raise ValueError("RFQ must have at least one line")
        if not self.invited_vendor_ids:
            raise ValueError("At least one vendor must be invited")
        self.status = RFQStatus.SENT
        self.issue_date = date.today()

    def close(self):
        """بستن استعلام."""
        if self.status != RFQStatus.SENT:
            raise ValueError("Only SENT RFQs can be closed")
        self.status = RFQStatus.CLOSED

    def award(self, vendor_id: UUID):
        """واگذاری به تأمین‌کننده."""
        if self.status not in (RFQStatus.SENT, RFQStatus.CLOSED):
            raise ValueError("Cannot award this RFQ")
        for resp in self.vendor_responses:
            if resp.vendor_id == vendor_id:
                resp.status = RFQResponseStatus.AWARDED
            else:
                resp.status = RFQResponseStatus.REJECTED
        self.status = RFQStatus.AWARDED

    def cancel(self):
        if self.status in (RFQStatus.AWARDED, RFQStatus.CANCELLED):
            raise ValueError("Cannot cancel this RFQ")
        self.status = RFQStatus.CANCELLED

    def validate(self):
        if not self.rfq_number:
            raise ValueError("RFQ number is required")
