# ================================================================
# services/production/app/models/production.py
# ================================================================
"""
Production models for the production service
"""

from sqlalchemy import Column, String, Integer, Float, DateTime, Boolean, Text, JSON, Enum as SQLEnum
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func
from datetime import datetime, timezone
from typing import Dict, Any, Optional
import uuid
import enum

from shared.database.base import Base


class ProductionStatus(str, enum.Enum):
    """Production batch status enumeration"""
    PENDING = "PENDING"
    IN_PROGRESS = "IN_PROGRESS"
    COMPLETED = "COMPLETED"
    CANCELLED = "CANCELLED"
    ON_HOLD = "ON_HOLD"
    QUALITY_CHECK = "QUALITY_CHECK"
    FAILED = "FAILED"


class ProductionPriority(str, enum.Enum):
    """Production priority levels"""
    LOW = "LOW"
    MEDIUM = "MEDIUM"
    HIGH = "HIGH"
    URGENT = "URGENT"




class ProductionBatch(Base):
    """Production batch model for tracking individual production runs"""
    __tablename__ = "production_batches"
    
    # 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)
    batch_number = Column(String(50), nullable=False, unique=True, index=True)
    
    # Product and recipe information
    product_id = Column(UUID(as_uuid=True), nullable=False, index=True)  # Reference to inventory/recipes
    product_name = Column(String(255), nullable=False)
    recipe_id = Column(UUID(as_uuid=True), nullable=True)
    
    # Production planning
    planned_start_time = Column(DateTime(timezone=True), nullable=False)
    planned_end_time = Column(DateTime(timezone=True), nullable=False)
    planned_quantity = Column(Float, nullable=False)
    planned_duration_minutes = Column(Integer, nullable=False)
    
    # Actual production tracking
    actual_start_time = Column(DateTime(timezone=True), nullable=True)
    actual_end_time = Column(DateTime(timezone=True), nullable=True)
    actual_quantity = Column(Float, nullable=True)
    actual_duration_minutes = Column(Integer, nullable=True)
    
    # Status and priority
    status = Column(SQLEnum(ProductionStatus), nullable=False, default=ProductionStatus.PENDING, index=True)
    priority = Column(SQLEnum(ProductionPriority), nullable=False, default=ProductionPriority.MEDIUM)
    
    # Cost tracking
    estimated_cost = Column(Float, nullable=True)
    actual_cost = Column(Float, nullable=True)
    labor_cost = Column(Float, nullable=True)
    material_cost = Column(Float, nullable=True)
    overhead_cost = Column(Float, nullable=True)
    
    # Quality metrics
    yield_percentage = Column(Float, nullable=True)  # actual/planned quantity
    quality_score = Column(Float, nullable=True)
    waste_quantity = Column(Float, nullable=True)
    defect_quantity = Column(Float, nullable=True)
    
    # Equipment and resources
    equipment_used = Column(JSON, nullable=True)  # List of equipment IDs
    staff_assigned = Column(JSON, nullable=True)  # List of staff IDs
    station_id = Column(String(50), nullable=True)
    
    # Business context
    order_id = Column(UUID(as_uuid=True), nullable=True)  # Associated customer order
    forecast_id = Column(UUID(as_uuid=True), nullable=True)  # Associated demand forecast
    is_rush_order = Column(Boolean, default=False)
    is_special_recipe = Column(Boolean, default=False)
    
    # Notes and tracking
    production_notes = Column(Text, nullable=True)
    quality_notes = Column(Text, nullable=True)
    delay_reason = Column(String(255), nullable=True)
    cancellation_reason = Column(String(255), nullable=True)
    
    # Timestamps
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    completed_at = Column(DateTime(timezone=True), nullable=True)
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary following shared pattern"""
        return {
            "id": str(self.id),
            "tenant_id": str(self.tenant_id),
            "batch_number": self.batch_number,
            "product_id": str(self.product_id),
            "product_name": self.product_name,
            "recipe_id": str(self.recipe_id) if self.recipe_id else None,
            "planned_start_time": self.planned_start_time.isoformat() if self.planned_start_time else None,
            "planned_end_time": self.planned_end_time.isoformat() if self.planned_end_time else None,
            "planned_quantity": self.planned_quantity,
            "planned_duration_minutes": self.planned_duration_minutes,
            "actual_start_time": self.actual_start_time.isoformat() if self.actual_start_time else None,
            "actual_end_time": self.actual_end_time.isoformat() if self.actual_end_time else None,
            "actual_quantity": self.actual_quantity,
            "actual_duration_minutes": self.actual_duration_minutes,
            "status": self.status.value if self.status else None,
            "priority": self.priority.value if self.priority else None,
            "estimated_cost": self.estimated_cost,
            "actual_cost": self.actual_cost,
            "labor_cost": self.labor_cost,
            "material_cost": self.material_cost,
            "overhead_cost": self.overhead_cost,
            "yield_percentage": self.yield_percentage,
            "quality_score": self.quality_score,
            "waste_quantity": self.waste_quantity,
            "defect_quantity": self.defect_quantity,
            "equipment_used": self.equipment_used,
            "staff_assigned": self.staff_assigned,
            "station_id": self.station_id,
            "order_id": str(self.order_id) if self.order_id else None,
            "forecast_id": str(self.forecast_id) if self.forecast_id else None,
            "is_rush_order": self.is_rush_order,
            "is_special_recipe": self.is_special_recipe,
            "production_notes": self.production_notes,
            "quality_notes": self.quality_notes,
            "delay_reason": self.delay_reason,
            "cancellation_reason": self.cancellation_reason,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
            "completed_at": self.completed_at.isoformat() if self.completed_at else None,
        }


class ProductionSchedule(Base):
    """Production schedule model for planning and tracking daily production"""
    __tablename__ = "production_schedules"
    
    # 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)
    
    # Schedule information
    schedule_date = Column(DateTime(timezone=True), nullable=False, index=True)
    shift_start = Column(DateTime(timezone=True), nullable=False)
    shift_end = Column(DateTime(timezone=True), nullable=False)
    
    # Capacity planning
    total_capacity_hours = Column(Float, nullable=False)
    planned_capacity_hours = Column(Float, nullable=False)
    actual_capacity_hours = Column(Float, nullable=True)
    overtime_hours = Column(Float, nullable=True, default=0.0)
    
    # Staff and equipment
    staff_count = Column(Integer, nullable=False)
    equipment_capacity = Column(JSON, nullable=True)  # Equipment availability
    station_assignments = Column(JSON, nullable=True)  # Station schedules
    
    # Production metrics
    total_batches_planned = Column(Integer, nullable=False, default=0)
    total_batches_completed = Column(Integer, nullable=True, default=0)
    total_quantity_planned = Column(Float, nullable=False, default=0.0)
    total_quantity_produced = Column(Float, nullable=True, default=0.0)
    
    # Status tracking
    is_finalized = Column(Boolean, default=False)
    is_active = Column(Boolean, default=True)
    
    # Performance metrics
    efficiency_percentage = Column(Float, nullable=True)
    utilization_percentage = Column(Float, nullable=True)
    on_time_completion_rate = Column(Float, nullable=True)
    
    # Notes and adjustments
    schedule_notes = Column(Text, nullable=True)
    schedule_adjustments = Column(JSON, nullable=True)  # Track changes made
    
    # Timestamps
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    finalized_at = Column(DateTime(timezone=True), nullable=True)
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary following shared pattern"""
        return {
            "id": str(self.id),
            "tenant_id": str(self.tenant_id),
            "schedule_date": self.schedule_date.isoformat() if self.schedule_date else None,
            "shift_start": self.shift_start.isoformat() if self.shift_start else None,
            "shift_end": self.shift_end.isoformat() if self.shift_end else None,
            "total_capacity_hours": self.total_capacity_hours,
            "planned_capacity_hours": self.planned_capacity_hours,
            "actual_capacity_hours": self.actual_capacity_hours,
            "overtime_hours": self.overtime_hours,
            "staff_count": self.staff_count,
            "equipment_capacity": self.equipment_capacity,
            "station_assignments": self.station_assignments,
            "total_batches_planned": self.total_batches_planned,
            "total_batches_completed": self.total_batches_completed,
            "total_quantity_planned": self.total_quantity_planned,
            "total_quantity_produced": self.total_quantity_produced,
            "is_finalized": self.is_finalized,
            "is_active": self.is_active,
            "efficiency_percentage": self.efficiency_percentage,
            "utilization_percentage": self.utilization_percentage,
            "on_time_completion_rate": self.on_time_completion_rate,
            "schedule_notes": self.schedule_notes,
            "schedule_adjustments": self.schedule_adjustments,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
            "finalized_at": self.finalized_at.isoformat() if self.finalized_at else None,
        }


class ProductionCapacity(Base):
    """Production capacity model for tracking equipment and resource availability"""
    __tablename__ = "production_capacity"
    
    # 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)
    
    # Capacity definition
    resource_type = Column(String(50), nullable=False)  # equipment, staff, station
    resource_id = Column(String(100), nullable=False)
    resource_name = Column(String(255), nullable=False)
    
    # Time period
    date = Column(DateTime(timezone=True), nullable=False, index=True)
    start_time = Column(DateTime(timezone=True), nullable=False)
    end_time = Column(DateTime(timezone=True), nullable=False)
    
    # Capacity metrics
    total_capacity_units = Column(Float, nullable=False)  # Total available capacity
    allocated_capacity_units = Column(Float, nullable=False, default=0.0)
    remaining_capacity_units = Column(Float, nullable=False)
    
    # Status
    is_available = Column(Boolean, default=True)
    is_maintenance = Column(Boolean, default=False)
    is_reserved = Column(Boolean, default=False)
    
    # Equipment specific
    equipment_type = Column(String(100), nullable=True)
    max_batch_size = Column(Float, nullable=True)
    min_batch_size = Column(Float, nullable=True)
    setup_time_minutes = Column(Integer, nullable=True)
    cleanup_time_minutes = Column(Integer, nullable=True)
    
    # Performance tracking
    efficiency_rating = Column(Float, nullable=True)
    maintenance_status = Column(String(50), nullable=True)
    last_maintenance_date = Column(DateTime(timezone=True), nullable=True)
    
    # Notes
    notes = Column(Text, nullable=True)
    restrictions = Column(JSON, nullable=True)  # Product type restrictions, etc.
    
    # Timestamps
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary following shared pattern"""
        return {
            "id": str(self.id),
            "tenant_id": str(self.tenant_id),
            "resource_type": self.resource_type,
            "resource_id": self.resource_id,
            "resource_name": self.resource_name,
            "date": self.date.isoformat() if self.date else None,
            "start_time": self.start_time.isoformat() if self.start_time else None,
            "end_time": self.end_time.isoformat() if self.end_time else None,
            "total_capacity_units": self.total_capacity_units,
            "allocated_capacity_units": self.allocated_capacity_units,
            "remaining_capacity_units": self.remaining_capacity_units,
            "is_available": self.is_available,
            "is_maintenance": self.is_maintenance,
            "is_reserved": self.is_reserved,
            "equipment_type": self.equipment_type,
            "max_batch_size": self.max_batch_size,
            "min_batch_size": self.min_batch_size,
            "setup_time_minutes": self.setup_time_minutes,
            "cleanup_time_minutes": self.cleanup_time_minutes,
            "efficiency_rating": self.efficiency_rating,
            "maintenance_status": self.maintenance_status,
            "last_maintenance_date": self.last_maintenance_date.isoformat() if self.last_maintenance_date else None,
            "notes": self.notes,
            "restrictions": self.restrictions,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }


class QualityCheck(Base):
    """Quality check model for tracking production quality metrics"""
    __tablename__ = "quality_checks"
    
    # 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)
    batch_id = Column(UUID(as_uuid=True), nullable=False, index=True)  # FK to ProductionBatch
    
    # Check information
    check_type = Column(String(50), nullable=False)  # visual, weight, temperature, etc.
    check_time = Column(DateTime(timezone=True), nullable=False)
    checker_id = Column(String(100), nullable=True)  # Staff member who performed check
    
    # Quality metrics
    quality_score = Column(Float, nullable=False)  # 1-10 scale
    pass_fail = Column(Boolean, nullable=False)
    defect_count = Column(Integer, nullable=False, default=0)
    defect_types = Column(JSON, nullable=True)  # List of defect categories
    
    # Measurements
    measured_weight = Column(Float, nullable=True)
    measured_temperature = Column(Float, nullable=True)
    measured_moisture = Column(Float, nullable=True)
    measured_dimensions = Column(JSON, nullable=True)
    
    # Standards comparison
    target_weight = Column(Float, nullable=True)
    target_temperature = Column(Float, nullable=True)
    target_moisture = Column(Float, nullable=True)
    tolerance_percentage = Column(Float, nullable=True)
    
    # Results
    within_tolerance = Column(Boolean, nullable=True)
    corrective_action_needed = Column(Boolean, default=False)
    corrective_actions = Column(JSON, nullable=True)
    
    # Notes and documentation
    check_notes = Column(Text, nullable=True)
    photos_urls = Column(JSON, nullable=True)  # URLs to quality check photos
    certificate_url = Column(String(500), nullable=True)
    
    # Timestamps
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary following shared pattern"""
        return {
            "id": str(self.id),
            "tenant_id": str(self.tenant_id),
            "batch_id": str(self.batch_id),
            "check_type": self.check_type,
            "check_time": self.check_time.isoformat() if self.check_time else None,
            "checker_id": self.checker_id,
            "quality_score": self.quality_score,
            "pass_fail": self.pass_fail,
            "defect_count": self.defect_count,
            "defect_types": self.defect_types,
            "measured_weight": self.measured_weight,
            "measured_temperature": self.measured_temperature,
            "measured_moisture": self.measured_moisture,
            "measured_dimensions": self.measured_dimensions,
            "target_weight": self.target_weight,
            "target_temperature": self.target_temperature,
            "target_moisture": self.target_moisture,
            "tolerance_percentage": self.tolerance_percentage,
            "within_tolerance": self.within_tolerance,
            "corrective_action_needed": self.corrective_action_needed,
            "corrective_actions": self.corrective_actions,
            "check_notes": self.check_notes,
            "photos_urls": self.photos_urls,
            "certificate_url": self.certificate_url,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }


