# ================================================================
# services/forecasting/app/models/validation_run.py
# ================================================================
"""
Validation run models for tracking forecast validation executions
"""

from sqlalchemy import Column, String, Integer, Float, DateTime, Text, JSON, Index
from sqlalchemy.dialects.postgresql import UUID
from datetime import datetime, timezone
import uuid

from shared.database.base import Base


class ValidationRun(Base):
    """Track forecast validation execution runs"""
    __tablename__ = "validation_runs"

    __table_args__ = (
        Index('ix_validation_runs_tenant_created', 'tenant_id', 'started_at'),
        Index('ix_validation_runs_status', 'status', 'started_at'),
        Index('ix_validation_runs_orchestration', 'orchestration_run_id'),
    )

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)

    # Link to orchestration run (if triggered by orchestrator)
    orchestration_run_id = Column(UUID(as_uuid=True), nullable=True)

    # Validation period
    validation_start_date = Column(DateTime(timezone=True), nullable=False)
    validation_end_date = Column(DateTime(timezone=True), nullable=False)

    # Execution metadata
    started_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
    completed_at = Column(DateTime(timezone=True), nullable=True)
    duration_seconds = Column(Float, nullable=True)

    # Status and results
    status = Column(String(50), default="pending")  # pending, running, completed, failed

    # Validation statistics
    total_forecasts_evaluated = Column(Integer, default=0)
    forecasts_with_actuals = Column(Integer, default=0)
    forecasts_without_actuals = Column(Integer, default=0)

    # Accuracy metrics summary (across all validated forecasts)
    overall_mae = Column(Float, nullable=True)
    overall_mape = Column(Float, nullable=True)
    overall_rmse = Column(Float, nullable=True)
    overall_r2_score = Column(Float, nullable=True)
    overall_accuracy_percentage = Column(Float, nullable=True)

    # Additional statistics
    total_predicted_demand = Column(Float, default=0.0)
    total_actual_demand = Column(Float, default=0.0)

    # Breakdown by product/location (JSON)
    metrics_by_product = Column(JSON, nullable=True)  # {product_id: {mae, mape, ...}}
    metrics_by_location = Column(JSON, nullable=True)  # {location: {mae, mape, ...}}

    # Performance metrics created count
    metrics_records_created = Column(Integer, default=0)

    # Error tracking
    error_message = Column(Text, nullable=True)
    error_details = Column(JSON, nullable=True)

    # Execution context
    triggered_by = Column(String(100), default="manual")  # manual, orchestrator, scheduled
    execution_mode = Column(String(50), default="batch")  # batch, single_day, real_time

    def __repr__(self):
        return (
            f"<ValidationRun(id={self.id}, tenant_id={self.tenant_id}, "
            f"status={self.status}, forecasts_evaluated={self.total_forecasts_evaluated})>"
        )

    def to_dict(self):
        """Convert to dictionary for API responses"""
        return {
            'id': str(self.id),
            'tenant_id': str(self.tenant_id),
            'orchestration_run_id': str(self.orchestration_run_id) if self.orchestration_run_id else None,
            'validation_start_date': self.validation_start_date.isoformat() if self.validation_start_date else None,
            'validation_end_date': self.validation_end_date.isoformat() if self.validation_end_date else None,
            'started_at': self.started_at.isoformat() if self.started_at else None,
            'completed_at': self.completed_at.isoformat() if self.completed_at else None,
            'duration_seconds': self.duration_seconds,
            'status': self.status,
            'total_forecasts_evaluated': self.total_forecasts_evaluated,
            'forecasts_with_actuals': self.forecasts_with_actuals,
            'forecasts_without_actuals': self.forecasts_without_actuals,
            'overall_mae': self.overall_mae,
            'overall_mape': self.overall_mape,
            'overall_rmse': self.overall_rmse,
            'overall_r2_score': self.overall_r2_score,
            'overall_accuracy_percentage': self.overall_accuracy_percentage,
            'total_predicted_demand': self.total_predicted_demand,
            'total_actual_demand': self.total_actual_demand,
            'metrics_by_product': self.metrics_by_product,
            'metrics_by_location': self.metrics_by_location,
            'metrics_records_created': self.metrics_records_created,
            'error_message': self.error_message,
            'error_details': self.error_details,
            'triggered_by': self.triggered_by,
            'execution_mode': self.execution_mode,
        }
