# ================================================================
# services/inventory/app/models/food_safety.py
# ================================================================
"""
Food safety and compliance models for Inventory Service
"""

import uuid
import enum
from datetime import datetime
from typing import Dict, Any, Optional
from sqlalchemy import Column, String, DateTime, Float, Integer, Text, Boolean, Numeric, ForeignKey, Enum as SQLEnum
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func

from shared.database.base import Base


class FoodSafetyStandard(enum.Enum):
    """Food safety standards and certifications"""
    HACCP = "haccp"
    FDA = "fda"
    USDA = "usda"
    FSMA = "fsma"
    SQF = "sqf"
    BRC = "brc"
    IFS = "ifs"
    ISO22000 = "iso22000"
    ORGANIC = "organic"
    NON_GMO = "non_gmo"
    ALLERGEN_FREE = "allergen_free"
    KOSHER = "kosher"
    HALAL = "halal"


class ComplianceStatus(enum.Enum):
    """Compliance status for food safety requirements"""
    COMPLIANT = "compliant"
    NON_COMPLIANT = "non_compliant"
    PENDING_REVIEW = "pending_review"
    EXPIRED = "expired"
    WARNING = "warning"


class FoodSafetyAlertType(enum.Enum):
    """Types of food safety alerts"""
    TEMPERATURE_VIOLATION = "temperature_violation"
    EXPIRATION_WARNING = "expiration_warning"
    EXPIRED_PRODUCT = "expired_product"
    CONTAMINATION_RISK = "contamination_risk"
    ALLERGEN_CROSS_CONTAMINATION = "allergen_cross_contamination"
    STORAGE_VIOLATION = "storage_violation"
    QUALITY_DEGRADATION = "quality_degradation"
    RECALL_NOTICE = "recall_notice"
    CERTIFICATION_EXPIRY = "certification_expiry"
    SUPPLIER_COMPLIANCE_ISSUE = "supplier_compliance_issue"


class FoodSafetyCompliance(Base):
    """Food safety compliance tracking for ingredients and products"""
    __tablename__ = "food_safety_compliance"
    
    # 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)
    ingredient_id = Column(UUID(as_uuid=True), ForeignKey("ingredients.id"), nullable=False, index=True)
    
    # Compliance standard
    standard = Column(SQLEnum(FoodSafetyStandard), nullable=False, index=True)
    compliance_status = Column(SQLEnum(ComplianceStatus), nullable=False, default=ComplianceStatus.PENDING_REVIEW)
    
    # Certification details
    certification_number = Column(String(100), nullable=True)
    certifying_body = Column(String(200), nullable=True)
    certification_date = Column(DateTime(timezone=True), nullable=True)
    expiration_date = Column(DateTime(timezone=True), nullable=True, index=True)
    
    # Compliance requirements
    requirements = Column(JSONB, nullable=True)  # Specific requirements for this standard
    compliance_notes = Column(Text, nullable=True)
    documentation_url = Column(String(500), nullable=True)
    
    # Audit information
    last_audit_date = Column(DateTime(timezone=True), nullable=True)
    next_audit_date = Column(DateTime(timezone=True), nullable=True, index=True)
    auditor_name = Column(String(200), nullable=True)
    audit_score = Column(Float, nullable=True)  # 0-100 score
    
    # Risk assessment
    risk_level = Column(String(20), nullable=False, default="medium")  # low, medium, high, critical
    risk_factors = Column(JSONB, nullable=True)  # List of identified risk factors
    mitigation_measures = Column(JSONB, nullable=True)  # Implemented mitigation measures
    
    # Status tracking
    is_active = Column(Boolean, nullable=False, default=True)
    requires_monitoring = Column(Boolean, nullable=False, default=True)
    monitoring_frequency_days = Column(Integer, nullable=True)  # How often to check compliance
    
    # 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)
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert model to dictionary for API responses"""
        return {
            'id': str(self.id),
            'tenant_id': str(self.tenant_id),
            'ingredient_id': str(self.ingredient_id),
            'standard': self.standard.value if self.standard else None,
            'compliance_status': self.compliance_status.value if self.compliance_status else None,
            'certification_number': self.certification_number,
            'certifying_body': self.certifying_body,
            'certification_date': self.certification_date.isoformat() if self.certification_date else None,
            'expiration_date': self.expiration_date.isoformat() if self.expiration_date else None,
            'requirements': self.requirements,
            'compliance_notes': self.compliance_notes,
            'documentation_url': self.documentation_url,
            'last_audit_date': self.last_audit_date.isoformat() if self.last_audit_date else None,
            'next_audit_date': self.next_audit_date.isoformat() if self.next_audit_date else None,
            'auditor_name': self.auditor_name,
            'audit_score': self.audit_score,
            'risk_level': self.risk_level,
            'risk_factors': self.risk_factors,
            'mitigation_measures': self.mitigation_measures,
            'is_active': self.is_active,
            'requires_monitoring': self.requires_monitoring,
            'monitoring_frequency_days': self.monitoring_frequency_days,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None,
            'created_by': str(self.created_by) if self.created_by else None,
            'updated_by': str(self.updated_by) if self.updated_by else None,
        }


class TemperatureLog(Base):
    """Temperature monitoring logs for storage areas"""
    __tablename__ = "temperature_logs"
    
    # 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)
    
    # Location information
    storage_location = Column(String(100), nullable=False, index=True)
    warehouse_zone = Column(String(50), nullable=True)
    equipment_id = Column(String(100), nullable=True)  # Freezer/refrigerator ID
    
    # Temperature readings
    temperature_celsius = Column(Float, nullable=False)
    humidity_percentage = Column(Float, nullable=True)
    target_temperature_min = Column(Float, nullable=True)
    target_temperature_max = Column(Float, nullable=True)
    
    # Status and alerts
    is_within_range = Column(Boolean, nullable=False, default=True)
    alert_triggered = Column(Boolean, nullable=False, default=False)
    deviation_minutes = Column(Integer, nullable=True)  # How long outside range
    
    # Measurement details
    measurement_method = Column(String(50), nullable=False, default="manual")  # manual, automatic, sensor
    device_id = Column(String(100), nullable=True)
    calibration_date = Column(DateTime(timezone=True), nullable=True)
    
    # Timestamp
    recorded_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True)
    
    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    recorded_by = Column(UUID(as_uuid=True), nullable=True)
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert model to dictionary for API responses"""
        return {
            'id': str(self.id),
            'tenant_id': str(self.tenant_id),
            'storage_location': self.storage_location,
            'warehouse_zone': self.warehouse_zone,
            'equipment_id': self.equipment_id,
            'temperature_celsius': self.temperature_celsius,
            'humidity_percentage': self.humidity_percentage,
            'target_temperature_min': self.target_temperature_min,
            'target_temperature_max': self.target_temperature_max,
            'is_within_range': self.is_within_range,
            'alert_triggered': self.alert_triggered,
            'deviation_minutes': self.deviation_minutes,
            'measurement_method': self.measurement_method,
            'device_id': self.device_id,
            'calibration_date': self.calibration_date.isoformat() if self.calibration_date else None,
            'recorded_at': self.recorded_at.isoformat() if self.recorded_at else None,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'recorded_by': str(self.recorded_by) if self.recorded_by else None,
        }


class FoodSafetyAlert(Base):
    """Food safety alerts and notifications"""
    __tablename__ = "food_safety_alerts"
    
    # 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)
    alert_code = Column(String(50), nullable=False, index=True)
    
    # Alert classification
    alert_type = Column(SQLEnum(FoodSafetyAlertType), nullable=False, index=True)
    severity = Column(String(20), nullable=False, default="medium", index=True)  # low, medium, high, critical
    risk_level = Column(String(20), nullable=False, default="medium")
    
    # Source information
    source_entity_type = Column(String(50), nullable=False)  # ingredient, stock, temperature_log, compliance
    source_entity_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    ingredient_id = Column(UUID(as_uuid=True), ForeignKey("ingredients.id"), nullable=True, index=True)
    stock_id = Column(UUID(as_uuid=True), ForeignKey("stock.id"), nullable=True, index=True)
    
    # Alert content
    title = Column(String(200), nullable=False)
    description = Column(Text, nullable=False)
    detailed_message = Column(Text, nullable=True)
    
    # Regulatory and compliance context
    regulatory_requirement = Column(String(100), nullable=True)
    compliance_standard = Column(SQLEnum(FoodSafetyStandard), nullable=True)
    regulatory_action_required = Column(Boolean, nullable=False, default=False)
    
    # Alert conditions and triggers
    trigger_condition = Column(String(200), nullable=True)
    threshold_value = Column(Numeric(15, 4), nullable=True)
    actual_value = Column(Numeric(15, 4), nullable=True)
    
    # Context data
    alert_data = Column(JSONB, nullable=True)  # Additional context-specific data
    environmental_factors = Column(JSONB, nullable=True)  # Temperature, humidity, etc.
    affected_products = Column(JSONB, nullable=True)  # List of affected product IDs
    
    # Risk assessment
    public_health_risk = Column(Boolean, nullable=False, default=False)
    business_impact = Column(Text, nullable=True)
    estimated_loss = Column(Numeric(12, 2), nullable=True)
    
    # Alert status and lifecycle
    status = Column(String(50), nullable=False, default="active", index=True)
    # Status values: active, acknowledged, investigating, resolved, dismissed, escalated
    
    alert_state = Column(String(50), nullable=False, default="new")  # new, escalated, recurring
    
    # Response and resolution
    immediate_actions_taken = Column(JSONB, nullable=True)  # Actions taken immediately
    investigation_notes = Column(Text, nullable=True)
    resolution_action = Column(String(200), nullable=True)
    resolution_notes = Column(Text, nullable=True)
    corrective_actions = Column(JSONB, nullable=True)  # List of corrective actions
    preventive_measures = Column(JSONB, nullable=True)  # Preventive measures implemented
    
    # Timing and escalation
    first_occurred_at = Column(DateTime(timezone=True), nullable=False, index=True)
    last_occurred_at = Column(DateTime(timezone=True), nullable=False)
    acknowledged_at = Column(DateTime(timezone=True), nullable=True)
    resolved_at = Column(DateTime(timezone=True), nullable=True)
    escalation_deadline = Column(DateTime(timezone=True), nullable=True)
    
    # Occurrence tracking
    occurrence_count = Column(Integer, nullable=False, default=1)
    is_recurring = Column(Boolean, nullable=False, default=False)
    recurrence_pattern = Column(String(100), nullable=True)
    
    # Responsibility and assignment
    assigned_to = Column(UUID(as_uuid=True), nullable=True)
    assigned_role = Column(String(50), nullable=True)  # food_safety_manager, quality_assurance, etc.
    escalated_to = Column(UUID(as_uuid=True), nullable=True)
    escalation_level = Column(Integer, nullable=False, default=0)
    
    # Notification tracking
    notification_sent = Column(Boolean, nullable=False, default=False)
    notification_methods = Column(JSONB, nullable=True)  # [email, sms, whatsapp, dashboard]
    notification_recipients = Column(JSONB, nullable=True)  # List of recipients
    regulatory_notification_required = Column(Boolean, nullable=False, default=False)
    regulatory_notification_sent = Column(Boolean, nullable=False, default=False)
    
    # Documentation and audit trail
    documentation = Column(JSONB, nullable=True)  # Links to documentation, photos, etc.
    audit_trail = Column(JSONB, nullable=True)  # Changes and actions taken
    external_reference = Column(String(100), nullable=True)  # External system reference
    
    # Performance tracking
    detection_time = Column(DateTime(timezone=True), nullable=True)  # When issue was detected
    response_time_minutes = Column(Integer, nullable=True)  # Time to acknowledge
    resolution_time_minutes = Column(Integer, nullable=True)  # Time to resolve
    
    # Quality and feedback
    alert_accuracy = Column(Boolean, nullable=True)  # Was this a valid alert?
    false_positive = Column(Boolean, nullable=False, default=False)
    feedback_notes = Column(Text, 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)
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert model to dictionary for API responses"""
        return {
            'id': str(self.id),
            'tenant_id': str(self.tenant_id),
            'alert_code': self.alert_code,
            'alert_type': self.alert_type.value if self.alert_type else None,
            'severity': self.severity,
            'risk_level': self.risk_level,
            'source_entity_type': self.source_entity_type,
            'source_entity_id': str(self.source_entity_id),
            'ingredient_id': str(self.ingredient_id) if self.ingredient_id else None,
            'stock_id': str(self.stock_id) if self.stock_id else None,
            'title': self.title,
            'description': self.description,
            'detailed_message': self.detailed_message,
            'regulatory_requirement': self.regulatory_requirement,
            'compliance_standard': self.compliance_standard.value if self.compliance_standard else None,
            'regulatory_action_required': self.regulatory_action_required,
            'trigger_condition': self.trigger_condition,
            'threshold_value': float(self.threshold_value) if self.threshold_value else None,
            'actual_value': float(self.actual_value) if self.actual_value else None,
            'alert_data': self.alert_data,
            'environmental_factors': self.environmental_factors,
            'affected_products': self.affected_products,
            'public_health_risk': self.public_health_risk,
            'business_impact': self.business_impact,
            'estimated_loss': float(self.estimated_loss) if self.estimated_loss else None,
            'status': self.status,
            'alert_state': self.alert_state,
            'immediate_actions_taken': self.immediate_actions_taken,
            'investigation_notes': self.investigation_notes,
            'resolution_action': self.resolution_action,
            'resolution_notes': self.resolution_notes,
            'corrective_actions': self.corrective_actions,
            'preventive_measures': self.preventive_measures,
            'first_occurred_at': self.first_occurred_at.isoformat() if self.first_occurred_at else None,
            'last_occurred_at': self.last_occurred_at.isoformat() if self.last_occurred_at else None,
            'acknowledged_at': self.acknowledged_at.isoformat() if self.acknowledged_at else None,
            'resolved_at': self.resolved_at.isoformat() if self.resolved_at else None,
            'escalation_deadline': self.escalation_deadline.isoformat() if self.escalation_deadline else None,
            'occurrence_count': self.occurrence_count,
            'is_recurring': self.is_recurring,
            'recurrence_pattern': self.recurrence_pattern,
            'assigned_to': str(self.assigned_to) if self.assigned_to else None,
            'assigned_role': self.assigned_role,
            'escalated_to': str(self.escalated_to) if self.escalated_to else None,
            'escalation_level': self.escalation_level,
            'notification_sent': self.notification_sent,
            'notification_methods': self.notification_methods,
            'notification_recipients': self.notification_recipients,
            'regulatory_notification_required': self.regulatory_notification_required,
            'regulatory_notification_sent': self.regulatory_notification_sent,
            'documentation': self.documentation,
            'audit_trail': self.audit_trail,
            'external_reference': self.external_reference,
            'detection_time': self.detection_time.isoformat() if self.detection_time else None,
            'response_time_minutes': self.response_time_minutes,
            'resolution_time_minutes': self.resolution_time_minutes,
            'alert_accuracy': self.alert_accuracy,
            'false_positive': self.false_positive,
            'feedback_notes': self.feedback_notes,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None,
            'created_by': str(self.created_by) if self.created_by else None,
            'updated_by': str(self.updated_by) if self.updated_by else None,
        }