# ================================================================
# services/procurement/app/models/procurement_plan.py
# ================================================================
"""
Procurement Planning Models
Migrated from Orders Service
"""

import uuid
from datetime import datetime, date
from decimal import Decimal
from sqlalchemy import Column, String, Boolean, DateTime, Date, Numeric, Text, Integer, ForeignKey
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func

from shared.database.base import Base


class ProcurementPlan(Base):
    """Master procurement plan for coordinating supply needs across orders and production"""
    __tablename__ = "procurement_plans"

    # Primary identification
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    plan_number = Column(String(50), nullable=False, unique=True, index=True)

    # Plan scope and timing
    plan_date = Column(Date, nullable=False, index=True)
    plan_period_start = Column(Date, nullable=False)
    plan_period_end = Column(Date, nullable=False)
    planning_horizon_days = Column(Integer, nullable=False, default=14)

    # Plan status and lifecycle
    status = Column(String(50), nullable=False, default="draft", index=True)
    # Status values: draft, pending_approval, approved, in_execution, completed, cancelled

    plan_type = Column(String(50), nullable=False, default="regular")  # regular, emergency, seasonal
    priority = Column(String(20), nullable=False, default="normal")  # high, normal, low

    # Business model context
    business_model = Column(String(50), nullable=True)  # individual_bakery, central_bakery
    procurement_strategy = Column(String(50), nullable=False, default="just_in_time")  # just_in_time, bulk, mixed

    # Plan totals and summary
    total_requirements = Column(Integer, nullable=False, default=0)
    total_estimated_cost = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    total_approved_cost = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    cost_variance = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))

    # Demand analysis
    total_demand_orders = Column(Integer, nullable=False, default=0)
    total_demand_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    total_production_requirements = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    safety_stock_buffer = Column(Numeric(5, 2), nullable=False, default=Decimal("20.00"))  # Percentage

    # Supplier coordination
    primary_suppliers_count = Column(Integer, nullable=False, default=0)
    backup_suppliers_count = Column(Integer, nullable=False, default=0)
    supplier_diversification_score = Column(Numeric(3, 1), nullable=True)  # 1.0 to 10.0

    # Risk assessment
    supply_risk_level = Column(String(20), nullable=False, default="low")  # low, medium, high, critical
    demand_forecast_confidence = Column(Numeric(3, 1), nullable=True)  # 1.0 to 10.0
    seasonality_adjustment = Column(Numeric(5, 2), nullable=False, default=Decimal("0.00"))

    # Execution tracking
    approved_at = Column(DateTime(timezone=True), nullable=True)
    approved_by = Column(UUID(as_uuid=True), nullable=True)
    execution_started_at = Column(DateTime(timezone=True), nullable=True)
    execution_completed_at = Column(DateTime(timezone=True), nullable=True)

    # Performance metrics
    fulfillment_rate = Column(Numeric(5, 2), nullable=True)  # Percentage
    on_time_delivery_rate = Column(Numeric(5, 2), nullable=True)  # Percentage
    cost_accuracy = Column(Numeric(5, 2), nullable=True)  # Percentage
    quality_score = Column(Numeric(3, 1), nullable=True)  # 1.0 to 10.0

    # Integration data
    source_orders = Column(JSONB, nullable=True)  # Orders that drove this plan
    production_schedules = Column(JSONB, nullable=True)  # Associated production schedules
    inventory_snapshots = Column(JSONB, nullable=True)  # Inventory levels at planning time
    forecast_data = Column(JSONB, nullable=True)  # Forecasting service data used for this plan

    # Communication and collaboration
    stakeholder_notifications = Column(JSONB, nullable=True)  # Who was notified and when
    approval_workflow = Column(JSONB, nullable=True)  # Approval chain and status

    # Special considerations
    special_requirements = Column(Text, nullable=True)
    seasonal_adjustments = Column(JSONB, nullable=True)
    emergency_provisions = Column(JSONB, nullable=True)

    # External references
    erp_reference = Column(String(100), nullable=True)
    supplier_portal_reference = Column(String(100), nullable=True)

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
    created_by = Column(UUID(as_uuid=True), nullable=True)
    updated_by = Column(UUID(as_uuid=True), nullable=True)

    # Additional metadata
    plan_metadata = Column(JSONB, nullable=True)

    # Relationships
    requirements = relationship("ProcurementRequirement", back_populates="plan", cascade="all, delete-orphan")


class ProcurementRequirement(Base):
    """Individual procurement requirements within a procurement plan"""
    __tablename__ = "procurement_requirements"

    # Primary identification
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    plan_id = Column(UUID(as_uuid=True), ForeignKey("procurement_plans.id", ondelete="CASCADE"), nullable=False)
    requirement_number = Column(String(50), nullable=False, index=True)

    # Product/ingredient information
    product_id = Column(UUID(as_uuid=True), nullable=False, index=True)  # Reference to products/ingredients
    product_name = Column(String(200), nullable=False)
    product_sku = Column(String(100), nullable=True)
    product_category = Column(String(100), nullable=True)
    product_type = Column(String(50), nullable=False, default="ingredient")  # ingredient, packaging, supplies

    # Local production tracking
    is_locally_produced = Column(Boolean, nullable=False, default=False)  # If true, this is for a locally-produced item
    recipe_id = Column(UUID(as_uuid=True), nullable=True)  # Recipe used for BOM explosion
    parent_requirement_id = Column(UUID(as_uuid=True), nullable=True)  # If this is from BOM explosion
    bom_explosion_level = Column(Integer, nullable=False, default=0)  # Depth in BOM tree

    # Requirement details
    required_quantity = Column(Numeric(12, 3), nullable=False)
    unit_of_measure = Column(String(50), nullable=False)
    safety_stock_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    total_quantity_needed = Column(Numeric(12, 3), nullable=False)

    # Current inventory situation
    current_stock_level = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    reserved_stock = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    available_stock = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    net_requirement = Column(Numeric(12, 3), nullable=False)

    # Demand breakdown
    order_demand = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    production_demand = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    forecast_demand = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    buffer_demand = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))

    # Supplier information
    preferred_supplier_id = Column(UUID(as_uuid=True), nullable=True)
    backup_supplier_id = Column(UUID(as_uuid=True), nullable=True)
    supplier_name = Column(String(200), nullable=True)
    supplier_lead_time_days = Column(Integer, nullable=True)
    minimum_order_quantity = Column(Numeric(12, 3), nullable=True)

    # Pricing and cost
    estimated_unit_cost = Column(Numeric(10, 4), nullable=True)
    estimated_total_cost = Column(Numeric(12, 2), nullable=True)
    last_purchase_cost = Column(Numeric(10, 4), nullable=True)
    cost_variance = Column(Numeric(10, 2), nullable=False, default=Decimal("0.00"))

    # Timing requirements
    required_by_date = Column(Date, nullable=False)
    lead_time_buffer_days = Column(Integer, nullable=False, default=1)
    suggested_order_date = Column(Date, nullable=False)
    latest_order_date = Column(Date, nullable=False)

    # Quality and specifications
    quality_specifications = Column(JSONB, nullable=True)
    special_requirements = Column(Text, nullable=True)
    storage_requirements = Column(String(200), nullable=True)
    shelf_life_days = Column(Integer, nullable=True)

    # Requirement status
    status = Column(String(50), nullable=False, default="pending")
    # Status values: pending, approved, ordered, partially_received, received, cancelled

    priority = Column(String(20), nullable=False, default="normal")  # critical, high, normal, low
    risk_level = Column(String(20), nullable=False, default="low")  # low, medium, high, critical

    # Purchase order tracking
    purchase_order_id = Column(UUID(as_uuid=True), nullable=True)
    purchase_order_number = Column(String(50), nullable=True)
    ordered_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    ordered_at = Column(DateTime(timezone=True), nullable=True)

    # Delivery tracking
    expected_delivery_date = Column(Date, nullable=True)
    actual_delivery_date = Column(Date, nullable=True)
    received_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    delivery_status = Column(String(50), nullable=False, default="pending")

    # Performance tracking
    fulfillment_rate = Column(Numeric(5, 2), nullable=True)  # Percentage
    on_time_delivery = Column(Boolean, nullable=True)
    quality_rating = Column(Numeric(3, 1), nullable=True)  # 1.0 to 10.0

    # Source traceability
    source_orders = Column(JSONB, nullable=True)  # Orders that contributed to this requirement
    source_production_batches = Column(JSONB, nullable=True)  # Production batches needing this
    demand_analysis = Column(JSONB, nullable=True)  # Detailed demand breakdown

    # Smart procurement calculation metadata
    calculation_method = Column(String(100), nullable=True)  # Method used: REORDER_POINT_TRIGGERED, FORECAST_DRIVEN_PROACTIVE, etc.
    ai_suggested_quantity = Column(Numeric(12, 3), nullable=True)  # Pure AI forecast quantity
    adjusted_quantity = Column(Numeric(12, 3), nullable=True)  # Final quantity after applying constraints
    adjustment_reason = Column(Text, nullable=True)  # Human-readable explanation of adjustments
    price_tier_applied = Column(JSONB, nullable=True)  # Price tier information if applicable
    supplier_minimum_applied = Column(Boolean, nullable=False, default=False)  # Whether supplier minimum was enforced
    storage_limit_applied = Column(Boolean, nullable=False, default=False)  # Whether storage limit was hit
    reorder_rule_applied = Column(Boolean, nullable=False, default=False)  # Whether reorder rules were used

    # Approval and authorization
    approved_quantity = Column(Numeric(12, 3), nullable=True)
    approved_cost = Column(Numeric(12, 2), nullable=True)
    approved_at = Column(DateTime(timezone=True), nullable=True)
    approved_by = Column(UUID(as_uuid=True), nullable=True)

    # Notes and communication
    procurement_notes = Column(Text, nullable=True)
    supplier_communication = Column(JSONB, nullable=True)

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)

    # Additional metadata
    requirement_metadata = Column(JSONB, nullable=True)

    # Relationships
    plan = relationship("ProcurementPlan", back_populates="requirements")
