# app/modules/procurement/schemas.py
from pydantic import BaseModel
from typing import Optional, List
from uuid import UUID
from datetime import date, datetime
from decimal import Decimal
 
# ── PO DETAIL SCHEMAS ────────────────────────────────
class RmPoDetailCreate(BaseModel):
    """
    Payload schema for a single line item within a new Purchase Order.
    Includes the requested quantity, unit price, and applicable GST.
    """
    rm_id: UUID
    order_qty: float
    unit_price: float
    gst_percent: Optional[float] = 0.0
 
class RmPoDetailResponse(BaseModel):
    """
    Schema for serializing a PO line item in the API response.
    Includes calculated fields like `line_amount` and the fulfillment `line_status`.
    """
    po_detail_id: UUID
    po_id: UUID
    rm_id: UUID
    order_qty: float
    received_qty: float
    unit_price: float
    gst_percent: Optional[float]
    line_amount: Optional[float]
    line_status: str
    created_at: datetime
 
    class Config:
        from_attributes = True
 
# ── PO SCHEMAS ───────────────────────────────────────
class RmPurchaseOrderCreate(BaseModel):
    """
    Payload schema for creating a new Purchase Order (Header).
    Contains a nested list of `details` representing the line items.
    """
    po_number: Optional[str] = None  # assigned on save when left blank
    vendor_id: UUID
    order_date: date
    expected_delivery_date: Optional[date] = None
    status_id: Optional[UUID] = None
    notes: Optional[str] = None
    details: List[RmPoDetailCreate] = []
 
class RmPurchaseOrderResponse(BaseModel):
    """
    Schema for serializing a complete Purchase Order.
    Includes the aggregated `total_amount` and the nested list of line item `details`.
    """
    po_id: UUID
    po_number: Optional[str]
    vendor_id: Optional[UUID]
    order_date: date
    expected_delivery_date: Optional[date]
    status_id: Optional[UUID]
    total_amount: Optional[float]
    notes: Optional[str]
    created_by: Optional[UUID] = None
    approved_by: Optional[UUID] = None
    approved_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    details: List[RmPoDetailResponse] = []
 
    class Config:
        from_attributes = True

class RmPurchaseOrderStatusUpdate(BaseModel):
    """
    Payload schema for updating the lifecycle status of a PO 
    (e.g., from DRAFT to APPROVED).
    """
    status_id: UUID
 
# ── GRN DETAIL SCHEMAS ───────────────────────────────
class GrnDetailCreate(BaseModel):
    """
    Payload schema for a single line item within a new Goods Receipt Note (GRN).
    Captures how much was received, accepted, and rejected (with reasons).
    """
    po_detail_id: UUID
    rm_id: UUID
    received_qty: float
    accepted_qty: Optional[float] = None
    rejected_qty: Optional[float] = 0.0
    rejection_reason: Optional[str] = None
    store_id: UUID
 
class GrnDetailResponse(BaseModel):
    """
    Schema for serializing a GRN line item in the API response.
    """
    grn_detail_id: UUID
    grn_id: Optional[UUID]
    po_detail_id: Optional[UUID]
    rm_id: Optional[UUID]
    received_qty: float
    accepted_qty: Optional[float]
    rejected_qty: Optional[float]
    rejection_reason: Optional[str]
    store_id: Optional[UUID]
    created_at: datetime
 
    class Config:
        from_attributes = True
 
# ── GRN SCHEMAS ──────────────────────────────────────
class RmReceivingLogCreate(BaseModel):
    """
    Payload schema for logging a new Goods Receipt Note (GRN Header).
    Links the delivery back to the original `po_id` and contains nested `details`.
    """
    grn_number: Optional[str] = None  # assigned on save when left blank
    po_id: UUID
    vendor_id: UUID
    asn_id: Optional[UUID] = None
    received_date: date
    vehicle_number: Optional[str] = None
    dc_number: Optional[str] = None
    grn_status: Optional[str] = "PENDING_QA"
    remarks: Optional[str] = None
    details: List[GrnDetailCreate] = []
 
class RmReceivingLogResponse(BaseModel):
    """
    Schema for serializing a complete Goods Receipt Note (GRN).
    Includes nested line item details.
    """
    grn_id: UUID
    grn_number: Optional[str]
    po_id: Optional[UUID]
    vendor_id: Optional[UUID]
    asn_id: Optional[UUID] = None
    received_date: date
    vehicle_number: Optional[str]
    dc_number: Optional[str]
    grn_status: str
    remarks: Optional[str]
    created_by: Optional[UUID] = None
    approved_by: Optional[UUID] = None
    approved_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    details: List[GrnDetailResponse] = []
 
    class Config:
        from_attributes = True

# ── DEBIT NOTES ─────────────────────────────────────────
class DebitNoteCreate(BaseModel):
    vendor_id: UUID
    rejection_id: Optional[UUID] = None
    po_id: Optional[UUID] = None
    dn_number: Optional[str] = None  # assigned on save when left blank
    amount: Decimal
    reason: str
    # Every debit note starts life as DRAFT — there is no client-settable status here.
    # Moving to APPROVED only ever happens through POST /debit-notes/{id}/approve, which is
    # gated on the PROCUREMENT 'approve' permission (plus the self-approval check). A
    # client-supplied status would let anyone with mere 'create' rights self-approve on
    # creation, bypassing that gate entirely.

class DebitNoteResponse(BaseModel):
    debit_note_id: UUID
    vendor_id: UUID
    rejection_id: Optional[UUID]
    dn_number: str
    amount: float
    reason: str
    status: str
    created_by: Optional[UUID] = None
    approved_by: Optional[UUID] = None
    approved_at: Optional[datetime] = None
    created_at: datetime
    
    class Config:
        from_attributes = True


# ── MONTHLY PROCUREMENT PLAN SCHEMAS ─────────────────
class MonthlyPlanLineCreate(BaseModel):
    """Payload for a single RM line when creating/updating a monthly plan."""
    rm_id: UUID
    planned_qty: float

class MonthlyPlanLineResponse(BaseModel):
    """
    Serialised plan line including live-computed PO and GRN quantities.
    """
    line_id: UUID
    plan_id: UUID
    rm_id: UUID
    planned_qty: float
    ordered_qty: float = 0.0   # computed, never stored
    received_qty: float = 0.0  # computed from GRN details, never stored
    created_at: datetime

    class Config:
        from_attributes = True

class MonthlyPlanCreate(BaseModel):
    """Payload for creating a new monthly procurement plan (header + lines)."""
    vendor_id: UUID
    plan_year: int
    plan_month: int   # 1-12
    notes: Optional[str] = None
    lines: List[MonthlyPlanLineCreate] = []

class MonthlyPlanUpdate(BaseModel):
    """Payload for editing an existing plan — replaces all lines and updates notes."""
    notes: Optional[str] = None
    lines: List[MonthlyPlanLineCreate] = []

class MonthlyPlanResponse(BaseModel):
    """Full plan response including enriched line items with ordered_qty."""
    plan_id: UUID
    vendor_id: UUID
    plan_year: int
    plan_month: int
    notes: Optional[str]
    created_by: Optional[UUID] = None
    created_at: datetime
    updated_at: datetime
    lines: List[MonthlyPlanLineResponse] = []

    class Config:
        from_attributes = True

# -- PROCUREMENT ENGINE SCHEMAS --
class ChassisMoveRequest(BaseModel):
    chassis_ids: List[UUID]

class ProcurementBomItem(BaseModel):
    rm_id: UUID
    rm_name: Optional[str] = None
    rm_code: Optional[str] = None
    required_qty: float
    available_qty: Optional[float] = None
    shortage_qty: Optional[float] = None
    category: str = 'Base BOM'

class ProcurementSimulationResponse(BaseModel):
    chassis_id: UUID
    chassis_number: str
    bom_items: List[ProcurementBomItem]

class ProcurementConfirmRequest(BaseModel):
    chassis_id: UUID
    final_bom: List[ProcurementBomItem]

class RmPurchaseRequestDetailResponse(BaseModel):
    request_detail_id: UUID
    rm_id: UUID
    shortage_qty: float
    affected_chassis: List[str]
    reason: Optional[str]
    
    class Config:
        from_attributes = True

class RmPurchaseRequestResponse(BaseModel):
    request_id: UUID
    request_number: str
    status: str
    requested_by: Optional[UUID]
    created_at: datetime
    details: List[RmPurchaseRequestDetailResponse] = []

    class Config:
        from_attributes = True
