# services/suppliers/app/schemas/suppliers.py
"""
Pydantic schemas for supplier-related API requests and responses
"""

from pydantic import BaseModel, Field, EmailStr
from typing import List, Optional, Dict, Any, Union
from uuid import UUID
from datetime import datetime
from decimal import Decimal

from app.models.suppliers import (
    SupplierType, SupplierStatus, PaymentTerms,
    QualityRating
)

# NOTE: PO, Delivery, and Invoice schemas remain for backward compatibility
# The primary implementation has moved to Procurement Service (services/procurement/)
# These schemas support legacy endpoints in suppliers service (app/api/purchase_orders.py)
#
# Migration Status:
# - ✅ Procurement Service fully operational with enhanced features
# - ⚠️  Supplier service endpoints still active for backward compatibility
# - 📋 Deprecation Timeline: Q2 2026 (after 6-month dual-operation period)
#
# Action Required:
# 1. All new integrations should use Procurement Service endpoints
# 2. Update client applications to use ProcurementServiceClient
# 3. Monitor usage of supplier service PO endpoints via logs
# 4. Plan migration of remaining clients by Q1 2026


# ============================================================================
# SUPPLIER SCHEMAS
# ============================================================================

class SupplierCreate(BaseModel):
    """Schema for creating suppliers"""
    name: str = Field(..., min_length=1, max_length=255)
    supplier_code: Optional[str] = Field(None, max_length=50)
    tax_id: Optional[str] = Field(None, max_length=50)
    registration_number: Optional[str] = Field(None, max_length=100)
    supplier_type: SupplierType
    contact_person: Optional[str] = Field(None, max_length=200)
    email: Optional[EmailStr] = None
    phone: Optional[str] = Field(None, max_length=30)
    mobile: Optional[str] = Field(None, max_length=30)
    website: Optional[str] = Field(None, max_length=255)
    
    # Address
    address_line1: Optional[str] = Field(None, max_length=255)
    address_line2: Optional[str] = Field(None, max_length=255)
    city: Optional[str] = Field(None, max_length=100)
    state_province: Optional[str] = Field(None, max_length=100)
    postal_code: Optional[str] = Field(None, max_length=20)
    country: Optional[str] = Field(None, max_length=100)
    
    # Business terms
    payment_terms: PaymentTerms = PaymentTerms.net_30
    credit_limit: Optional[Decimal] = Field(None, ge=0)
    currency: str = Field(default="EUR", max_length=3)
    standard_lead_time: int = Field(default=3, ge=0, le=365)
    minimum_order_amount: Optional[Decimal] = Field(None, ge=0)
    delivery_area: Optional[str] = Field(None, max_length=255)
    
    # Additional information
    notes: Optional[str] = None
    certifications: Optional[Union[Dict[str, Any], List[str]]] = None
    business_hours: Optional[Dict[str, Any]] = None
    specializations: Optional[Dict[str, Any]] = None


class SupplierUpdate(BaseModel):
    """Schema for updating suppliers"""
    name: Optional[str] = Field(None, min_length=1, max_length=255)
    supplier_code: Optional[str] = Field(None, max_length=50)
    tax_id: Optional[str] = Field(None, max_length=50)
    registration_number: Optional[str] = Field(None, max_length=100)
    supplier_type: Optional[SupplierType] = None
    status: Optional[SupplierStatus] = None
    contact_person: Optional[str] = Field(None, max_length=200)
    email: Optional[EmailStr] = None
    phone: Optional[str] = Field(None, max_length=30)
    mobile: Optional[str] = Field(None, max_length=30)
    website: Optional[str] = Field(None, max_length=255)
    
    # Address
    address_line1: Optional[str] = Field(None, max_length=255)
    address_line2: Optional[str] = Field(None, max_length=255)
    city: Optional[str] = Field(None, max_length=100)
    state_province: Optional[str] = Field(None, max_length=100)
    postal_code: Optional[str] = Field(None, max_length=20)
    country: Optional[str] = Field(None, max_length=100)
    
    # Business terms
    payment_terms: Optional[PaymentTerms] = None
    credit_limit: Optional[Decimal] = Field(None, ge=0)
    currency: Optional[str] = Field(None, max_length=3)
    standard_lead_time: Optional[int] = Field(None, ge=0, le=365)
    minimum_order_amount: Optional[Decimal] = Field(None, ge=0)
    delivery_area: Optional[str] = Field(None, max_length=255)
    
    # Additional information
    notes: Optional[str] = None
    certifications: Optional[Union[Dict[str, Any], List[str]]] = None
    business_hours: Optional[Dict[str, Any]] = None
    specializations: Optional[Dict[str, Any]] = None


class SupplierApproval(BaseModel):
    """Schema for supplier approval/rejection"""
    action: str = Field(..., pattern="^(approve|reject)$")
    notes: Optional[str] = None


class SupplierResponse(BaseModel):
    """Schema for supplier responses"""
    id: UUID
    tenant_id: UUID
    name: str
    supplier_code: Optional[str] = None
    tax_id: Optional[str] = None
    registration_number: Optional[str] = None
    supplier_type: SupplierType
    status: SupplierStatus
    contact_person: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    mobile: Optional[str] = None
    website: Optional[str] = None
    
    # Address
    address_line1: Optional[str] = None
    address_line2: Optional[str] = None
    city: Optional[str] = None
    state_province: Optional[str] = None
    postal_code: Optional[str] = None
    country: Optional[str] = None
    
    # Business terms
    payment_terms: PaymentTerms
    credit_limit: Optional[Decimal] = None
    currency: str
    standard_lead_time: int
    minimum_order_amount: Optional[Decimal] = None
    delivery_area: Optional[str] = None
    
    # Performance metrics
    quality_rating: Optional[float] = None
    delivery_rating: Optional[float] = None
    total_orders: int
    total_amount: Decimal
    
    # Approval info
    approved_by: Optional[UUID] = None
    approved_at: Optional[datetime] = None
    rejection_reason: Optional[str] = None
    
    # Additional information
    notes: Optional[str] = None
    certifications: Optional[Union[Dict[str, Any], List[str]]] = None
    business_hours: Optional[Dict[str, Any]] = None
    specializations: Optional[Dict[str, Any]] = None
    
    # Audit fields
    created_at: datetime
    updated_at: datetime
    created_by: UUID
    updated_by: UUID

    class Config:
        from_attributes = True


class SupplierSummary(BaseModel):
    """Schema for supplier summary (list view)"""
    id: UUID
    name: str
    supplier_code: Optional[str] = None
    supplier_type: SupplierType
    status: SupplierStatus
    contact_person: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    city: Optional[str] = None
    country: Optional[str] = None

    # Business terms - Added for list view
    payment_terms: PaymentTerms
    standard_lead_time: int
    minimum_order_amount: Optional[Decimal] = None

    # Performance metrics
    quality_rating: Optional[float] = None
    delivery_rating: Optional[float] = None
    total_orders: int
    total_amount: Decimal
    created_at: datetime

    class Config:
        from_attributes = True


class SupplierDeletionSummary(BaseModel):
    """Schema for supplier deletion summary"""
    supplier_name: str
    deleted_price_lists: int = 0
    deleted_quality_reviews: int = 0
    deleted_performance_metrics: int = 0
    deleted_alerts: int = 0
    deleted_scorecards: int = 0
    deletion_timestamp: datetime

    class Config:
        from_attributes = True


# ============================================================================
# PURCHASE ORDER SCHEMAS
# ============================================================================

class PurchaseOrderItemCreate(BaseModel):
    """Schema for creating purchase order items"""
    inventory_product_id: UUID
    product_code: Optional[str] = Field(None, max_length=100)
    ordered_quantity: int = Field(..., gt=0)
    unit_of_measure: str = Field(..., max_length=20)
    unit_price: Decimal = Field(..., gt=0)
    quality_requirements: Optional[str] = None
    item_notes: Optional[str] = None


class PurchaseOrderItemUpdate(BaseModel):
    """Schema for updating purchase order items"""
    ordered_quantity: Optional[int] = Field(None, gt=0)
    unit_price: Optional[Decimal] = Field(None, gt=0)
    quality_requirements: Optional[str] = None
    item_notes: Optional[str] = None


class PurchaseOrderItemResponse(BaseModel):
    """Schema for purchase order item responses"""
    id: UUID
    tenant_id: UUID
    purchase_order_id: UUID
    price_list_item_id: Optional[UUID] = None
    inventory_product_id: UUID
    product_code: Optional[str] = None
    ordered_quantity: int
    unit_of_measure: str
    unit_price: Decimal
    line_total: Decimal
    received_quantity: int
    remaining_quantity: int
    quality_requirements: Optional[str] = None
    item_notes: Optional[str] = None
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True


class PurchaseOrderCreate(BaseModel):
    """Schema for creating purchase orders"""
    supplier_id: UUID
    reference_number: Optional[str] = Field(None, max_length=100)
    priority: str = Field(default="normal", max_length=20)
    required_delivery_date: Optional[datetime] = None
    
    # Delivery information
    delivery_address: Optional[str] = None
    delivery_instructions: Optional[str] = None
    delivery_contact: Optional[str] = Field(None, max_length=200)
    delivery_phone: Optional[str] = Field(None, max_length=30)
    
    # Financial information
    tax_amount: Decimal = Field(default=0, ge=0)
    shipping_cost: Decimal = Field(default=0, ge=0)
    discount_amount: Decimal = Field(default=0, ge=0)
    
    # Additional information
    notes: Optional[str] = None
    internal_notes: Optional[str] = None
    terms_and_conditions: Optional[str] = None
    
    # Items
    items: List[PurchaseOrderItemCreate] = Field(..., min_items=1)


class PurchaseOrderUpdate(BaseModel):
    """Schema for updating purchase orders"""
    reference_number: Optional[str] = Field(None, max_length=100)
    priority: Optional[str] = Field(None, max_length=20)
    required_delivery_date: Optional[datetime] = None
    estimated_delivery_date: Optional[datetime] = None
    
    # Delivery information
    delivery_address: Optional[str] = None
    delivery_instructions: Optional[str] = None
    delivery_contact: Optional[str] = Field(None, max_length=200)
    delivery_phone: Optional[str] = Field(None, max_length=30)
    
    # Financial information
    tax_amount: Optional[Decimal] = Field(None, ge=0)
    shipping_cost: Optional[Decimal] = Field(None, ge=0)
    discount_amount: Optional[Decimal] = Field(None, ge=0)
    
    # Additional information
    notes: Optional[str] = None
    internal_notes: Optional[str] = None
    terms_and_conditions: Optional[str] = None
    
    # Supplier communication
    supplier_reference: Optional[str] = Field(None, max_length=100)


class PurchaseOrderStatusUpdate(BaseModel):
    """Schema for updating purchase order status"""
    status: str  # PurchaseOrderStatus - moved to Procurement Service
    notes: Optional[str] = None


class PurchaseOrderApproval(BaseModel):
    """Schema for purchase order approval/rejection"""
    action: str = Field(..., pattern="^(approve|reject)$")
    notes: Optional[str] = None


class PurchaseOrderResponse(BaseModel):
    """Schema for purchase order responses"""
    id: UUID
    tenant_id: UUID
    supplier_id: UUID
    po_number: str
    reference_number: Optional[str] = None
    status: str  # PurchaseOrderStatus
    priority: str
    order_date: datetime
    required_delivery_date: Optional[datetime] = None
    estimated_delivery_date: Optional[datetime] = None
    
    # Financial information
    subtotal: Decimal
    tax_amount: Decimal
    shipping_cost: Decimal
    discount_amount: Decimal
    total_amount: Decimal
    currency: str
    
    # Delivery information
    delivery_address: Optional[str] = None
    delivery_instructions: Optional[str] = None
    delivery_contact: Optional[str] = None
    delivery_phone: Optional[str] = None
    
    # Approval workflow
    requires_approval: bool
    approved_by: Optional[UUID] = None
    approved_at: Optional[datetime] = None
    rejection_reason: Optional[str] = None
    
    # Communication tracking
    sent_to_supplier_at: Optional[datetime] = None
    supplier_confirmation_date: Optional[datetime] = None
    supplier_reference: Optional[str] = None
    
    # Additional information
    notes: Optional[str] = None
    internal_notes: Optional[str] = None
    terms_and_conditions: Optional[str] = None
    
    # Audit fields
    created_at: datetime
    updated_at: datetime
    created_by: UUID
    updated_by: UUID
    
    # Related data (populated separately)
    supplier: Optional[SupplierSummary] = None
    items: Optional[List[PurchaseOrderItemResponse]] = None

    class Config:
        from_attributes = True


class PurchaseOrderSummary(BaseModel):
    """Schema for purchase order summary (list view)"""
    id: UUID
    po_number: str
    supplier_id: UUID
    supplier_name: Optional[str] = None
    status: str  # PurchaseOrderStatus
    priority: str
    order_date: datetime
    required_delivery_date: Optional[datetime] = None
    total_amount: Decimal
    currency: str
    created_at: datetime

    class Config:
        from_attributes = True


# ============================================================================
# DELIVERY SCHEMAS  
# ============================================================================

class DeliveryItemCreate(BaseModel):
    """Schema for creating delivery items"""
    purchase_order_item_id: UUID
    inventory_product_id: UUID
    ordered_quantity: int = Field(..., gt=0)
    delivered_quantity: int = Field(..., ge=0)
    accepted_quantity: int = Field(..., ge=0)
    rejected_quantity: int = Field(default=0, ge=0)
    
    # Quality information
    batch_lot_number: Optional[str] = Field(None, max_length=100)
    expiry_date: Optional[datetime] = None
    quality_grade: Optional[str] = Field(None, max_length=20)
    
    # Issues and notes
    quality_issues: Optional[str] = None
    rejection_reason: Optional[str] = None
    item_notes: Optional[str] = None


class DeliveryItemResponse(BaseModel):
    """Schema for delivery item responses"""
    id: UUID
    tenant_id: UUID
    delivery_id: UUID
    purchase_order_item_id: UUID
    inventory_product_id: UUID
    ordered_quantity: int
    delivered_quantity: int
    accepted_quantity: int
    rejected_quantity: int
    batch_lot_number: Optional[str] = None
    expiry_date: Optional[datetime] = None
    quality_grade: Optional[str] = None
    quality_issues: Optional[str] = None
    rejection_reason: Optional[str] = None
    item_notes: Optional[str] = None
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True


class DeliveryCreate(BaseModel):
    """Schema for creating deliveries"""
    purchase_order_id: UUID
    supplier_id: UUID
    supplier_delivery_note: Optional[str] = Field(None, max_length=100)
    scheduled_date: Optional[datetime] = None
    estimated_arrival: Optional[datetime] = None
    
    # Delivery details
    delivery_address: Optional[str] = None
    delivery_contact: Optional[str] = Field(None, max_length=200)
    delivery_phone: Optional[str] = Field(None, max_length=30)
    carrier_name: Optional[str] = Field(None, max_length=200)
    tracking_number: Optional[str] = Field(None, max_length=100)
    
    # Additional information
    notes: Optional[str] = None
    
    # Items
    items: List[DeliveryItemCreate] = Field(..., min_items=1)


class DeliveryUpdate(BaseModel):
    """Schema for updating deliveries"""
    supplier_delivery_note: Optional[str] = Field(None, max_length=100)
    scheduled_date: Optional[datetime] = None
    estimated_arrival: Optional[datetime] = None
    actual_arrival: Optional[datetime] = None
    
    # Delivery details
    delivery_address: Optional[str] = None
    delivery_contact: Optional[str] = Field(None, max_length=200)
    delivery_phone: Optional[str] = Field(None, max_length=30)
    carrier_name: Optional[str] = Field(None, max_length=200)
    tracking_number: Optional[str] = Field(None, max_length=100)
    
    # Quality inspection
    inspection_passed: Optional[bool] = None
    inspection_notes: Optional[str] = None
    quality_issues: Optional[Dict[str, Any]] = None
    
    # Additional information
    notes: Optional[str] = None


class DeliveryStatusUpdate(BaseModel):
    """Schema for updating delivery status"""
    status: str  # DeliveryStatus
    notes: Optional[str] = None
    update_timestamps: bool = Field(default=True)


class DeliveryReceiptConfirmation(BaseModel):
    """Schema for confirming delivery receipt"""
    inspection_passed: bool = True
    inspection_notes: Optional[str] = None
    quality_issues: Optional[Dict[str, Any]] = None
    notes: Optional[str] = None


class DeliveryResponse(BaseModel):
    """Schema for delivery responses"""
    id: UUID
    tenant_id: UUID
    purchase_order_id: UUID
    supplier_id: UUID
    delivery_number: str
    supplier_delivery_note: Optional[str] = None
    status: str  # DeliveryStatus
    
    # Timing
    scheduled_date: Optional[datetime] = None
    estimated_arrival: Optional[datetime] = None
    actual_arrival: Optional[datetime] = None
    completed_at: Optional[datetime] = None
    
    # Delivery details
    delivery_address: Optional[str] = None
    delivery_contact: Optional[str] = None
    delivery_phone: Optional[str] = None
    carrier_name: Optional[str] = None
    tracking_number: Optional[str] = None
    
    # Quality inspection
    inspection_passed: Optional[bool] = None
    inspection_notes: Optional[str] = None
    quality_issues: Optional[Dict[str, Any]] = None
    
    # Receipt information
    received_by: Optional[UUID] = None
    received_at: Optional[datetime] = None
    
    # Additional information
    notes: Optional[str] = None
    photos: Optional[Dict[str, Any]] = None
    
    # Audit fields
    created_at: datetime
    updated_at: datetime
    created_by: UUID
    
    # Related data
    supplier: Optional[SupplierSummary] = None
    purchase_order: Optional[PurchaseOrderSummary] = None
    items: Optional[List[DeliveryItemResponse]] = None

    class Config:
        from_attributes = True


class DeliverySummary(BaseModel):
    """Schema for delivery summary (list view)"""
    id: UUID
    delivery_number: str
    supplier_id: UUID
    supplier_name: Optional[str] = None
    purchase_order_id: UUID
    po_number: Optional[str] = None
    status: str  # DeliveryStatus
    scheduled_date: Optional[datetime] = None
    actual_arrival: Optional[datetime] = None
    inspection_passed: Optional[bool] = None
    created_at: datetime

    class Config:
        from_attributes = True


# ============================================================================
# SEARCH AND FILTER SCHEMAS
# ============================================================================

class SupplierSearchParams(BaseModel):
    """Search parameters for suppliers"""
    search_term: Optional[str] = Field(None, max_length=100)
    supplier_type: Optional[SupplierType] = None
    status: Optional[SupplierStatus] = None
    limit: int = Field(default=50, ge=1, le=1000)
    offset: int = Field(default=0, ge=0)


class PurchaseOrderSearchParams(BaseModel):
    """Search parameters for purchase orders"""
    supplier_id: Optional[UUID] = None
    status: Optional[str] = None  # PurchaseOrderStatus
    priority: Optional[str] = None
    date_from: Optional[datetime] = None
    date_to: Optional[datetime] = None
    search_term: Optional[str] = Field(None, max_length=100)
    limit: int = Field(default=50, ge=1, le=1000)
    offset: int = Field(default=0, ge=0)


class DeliverySearchParams(BaseModel):
    """Search parameters for deliveries"""
    supplier_id: Optional[UUID] = None
    status: Optional[str] = None  # DeliveryStatus
    date_from: Optional[datetime] = None
    date_to: Optional[datetime] = None
    search_term: Optional[str] = Field(None, max_length=100)
    limit: int = Field(default=50, ge=1, le=1000)
    offset: int = Field(default=0, ge=0)


# ============================================================================
# SUPPLIER PRICE LIST SCHEMAS
# ============================================================================

class SupplierPriceListCreate(BaseModel):
    """Schema for creating supplier price list items"""
    inventory_product_id: UUID
    product_code: Optional[str] = Field(None, max_length=100)
    unit_price: Decimal = Field(..., gt=0)
    unit_of_measure: str = Field(..., max_length=20)
    minimum_order_quantity: Optional[int] = Field(None, ge=1)
    price_per_unit: Decimal = Field(..., gt=0)
    tier_pricing: Optional[Dict[str, Any]] = None  # [{quantity: 100, price: 2.50}, ...]
    effective_date: Optional[datetime] = Field(default_factory=lambda: datetime.now())
    expiry_date: Optional[datetime] = None
    is_active: bool = True
    brand: Optional[str] = Field(None, max_length=100)
    packaging_size: Optional[str] = Field(None, max_length=50)
    origin_country: Optional[str] = Field(None, max_length=100)
    shelf_life_days: Optional[int] = None
    storage_requirements: Optional[str] = None
    quality_specs: Optional[Dict[str, Any]] = None
    allergens: Optional[Dict[str, Any]] = None


class SupplierPriceListUpdate(BaseModel):
    """Schema for updating supplier price list items"""
    unit_price: Optional[Decimal] = Field(None, gt=0)
    unit_of_measure: Optional[str] = Field(None, max_length=20)
    minimum_order_quantity: Optional[int] = Field(None, ge=1)
    tier_pricing: Optional[Dict[str, Any]] = None
    effective_date: Optional[datetime] = None
    expiry_date: Optional[datetime] = None
    is_active: Optional[bool] = None
    brand: Optional[str] = Field(None, max_length=100)
    packaging_size: Optional[str] = Field(None, max_length=50)
    origin_country: Optional[str] = Field(None, max_length=100)
    shelf_life_days: Optional[int] = None
    storage_requirements: Optional[str] = None
    quality_specs: Optional[Dict[str, Any]] = None
    allergens: Optional[Dict[str, Any]] = None


class SupplierPriceListResponse(BaseModel):
    """Schema for supplier price list responses"""
    id: UUID
    tenant_id: UUID
    supplier_id: UUID
    inventory_product_id: UUID
    product_code: Optional[str] = None
    unit_price: Decimal
    unit_of_measure: str
    minimum_order_quantity: Optional[int] = None
    price_per_unit: Decimal
    tier_pricing: Optional[Dict[str, Any]] = None
    effective_date: datetime
    expiry_date: Optional[datetime] = None
    is_active: bool
    brand: Optional[str] = None
    packaging_size: Optional[str] = None
    origin_country: Optional[str] = None
    shelf_life_days: Optional[int] = None
    storage_requirements: Optional[str] = None
    quality_specs: Optional[Dict[str, Any]] = None
    allergens: Optional[Dict[str, Any]] = None
    created_at: datetime
    updated_at: datetime
    created_by: UUID
    updated_by: UUID

    class Config:
        from_attributes = True


# ============================================================================
# STATISTICS AND REPORTING SCHEMAS
# ============================================================================

class SupplierStatistics(BaseModel):
    """Schema for supplier statistics"""
    total_suppliers: int
    active_suppliers: int
    pending_suppliers: int
    avg_quality_rating: float
    avg_delivery_rating: float
    total_spend: float


class PurchaseOrderStatistics(BaseModel):
    """Schema for purchase order statistics"""
    total_orders: int
    status_counts: Dict[str, int]
    this_month_orders: int
    this_month_spend: float
    avg_order_value: float
    overdue_count: int
    pending_approval: int


class DeliveryPerformanceStats(BaseModel):
    """Schema for delivery performance statistics"""
    total_deliveries: int
    on_time_deliveries: int
    late_deliveries: int
    failed_deliveries: int
    on_time_percentage: float
    avg_delay_hours: float
    quality_pass_rate: float


class DeliverySummaryStats(BaseModel):
    """Schema for delivery summary statistics"""
    todays_deliveries: int
    this_week_deliveries: int
    overdue_deliveries: int
    in_transit_deliveries: int
