"""AI Analysis models for expert system functionality.

This module contains SQLAlchemy models for:
- AI algorithm configuration (per tenant/device)
- Anomaly detection results
- Anomaly detection execution audit trail
- Optimization recommendations
- Recommendation execution audit trail
"""

from sqlalchemy import (
    Boolean,
    CheckConstraint,
    Column,
    DateTime,
    ForeignKey,
    Index,
    Integer,
    Numeric,
    Text,
    UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.sql import text

from iot_db.models.base import Base


class AIAnalysisConfig(Base):
    """Configuration for AI algorithms per tenant or device.

    Hierarchy:
    - device_id = NULL -> tenant-wide config
    - device_id = specific value -> device-specific override

    Merge strategy: device > tenant > defaults (in code)
    """

    __tablename__ = "ai_analysis_config"

    # Primary key
    id = Column(
        UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")
    )

    # Scope
    tenant = Column(UUID(as_uuid=True), nullable=False, index=True)
    device_id = Column(
        Integer,
        ForeignKey("dim_device.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # Algorithm
    algorithm_type = Column(Text, nullable=False)
    config_params = Column(JSONB, nullable=False, server_default="{}")

    # Control
    enabled = Column(Boolean, nullable=False, server_default="true")
    priority = Column(Integer, nullable=False, server_default="0")
    schedule_cron = Column(Text, nullable=True)

    # Metadata
    created_at = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )
    updated_at = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )
    created_by = Column(Text, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant",
            "device_id",
            "algorithm_type",
            name="uq_ai_config_tenant_device_algo",
        ),
        Index(
            "idx_ai_config_enabled", "enabled", postgresql_where=text("enabled = TRUE")
        ),
        Index(
            "idx_ai_config_tenant_enabled",
            "tenant",
            "enabled",
            postgresql_where=text("enabled = TRUE"),
        ),
        Index("idx_ai_config_algorithm", "algorithm_type"),
        CheckConstraint(
            "algorithm_type IN ('anomaly_zscore', 'anomaly_iqr', "
            "'leak_detection', 'isolation_forest', 'correlation_analysis', "
            "'lstm_autoencoder', 'prophet_forecast')",
            name="chk_ai_config_algorithm_type",
        ),
    )


class AnomalyDetection(Base):
    """Detected anomalies in measurement data."""

    __tablename__ = "anomaly_detection"

    # Primary key
    id = Column(
        UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")
    )

    # Context
    tenant = Column(UUID(as_uuid=True), nullable=False, index=True)
    device_id = Column(
        Integer,
        ForeignKey("dim_device.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    # Anomaly
    anomaly_type = Column(Text, nullable=False)
    detected_at = Column(
        DateTime(timezone=True),
        nullable=False,
        server_default=text("NOW()"),
        index=True,
    )
    period_start = Column(DateTime(timezone=True), nullable=False)
    period_end = Column(DateTime(timezone=True), nullable=False)

    # Values
    expected_value = Column(Numeric(15, 4), nullable=True)
    actual_value = Column(Numeric(15, 4), nullable=False)
    deviation = Column(Numeric(15, 4), nullable=True)
    deviation_percentage = Column(Numeric(8, 2), nullable=True)

    # Detection
    algorithm_used = Column(Text, nullable=False)
    confidence_score = Column(Numeric(5, 4), nullable=True)
    severity = Column(Text, nullable=False, server_default="medium")
    details = Column(JSONB, nullable=False, server_default="{}")

    # Processing
    processed = Column(Boolean, nullable=False, server_default="false")
    processed_at = Column(DateTime(timezone=True), nullable=True)

    # Links
    alert_id = Column(UUID(as_uuid=True), nullable=True)
    command_id = Column(UUID(as_uuid=True), nullable=True)
    rule_id = Column(UUID(as_uuid=True), nullable=True)

    # Audit
    created_at = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )

    __table_args__ = (
        Index("idx_anomaly_tenant_detected", "tenant", "detected_at"),
        Index("idx_anomaly_device_detected", "device_id", "detected_at"),
        Index("idx_anomaly_type", "anomaly_type"),
        Index("idx_anomaly_severity", "severity"),
        Index(
            "idx_anomaly_unprocessed",
            "processed",
            "severity",
            "detected_at",
            postgresql_where=text("processed = FALSE"),
        ),
        CheckConstraint(
            "anomaly_type IN ('spike', 'drop', 'leak', 'unusual_pattern', "
            "'flatline', 'outlier')",
            name="chk_anomaly_type",
        ),
        CheckConstraint(
            "severity IN ('low', 'medium', 'high', 'critical')",
            name="chk_anomaly_severity",
        ),
        CheckConstraint(
            "confidence_score >= 0.0 AND confidence_score <= 1.0",
            name="chk_anomaly_confidence",
        ),
    )


class AnomalyExecution(Base):
    """Audit log for anomaly detector executions."""

    __tablename__ = "anomaly_execution"

    # Primary key
    id = Column(
        UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")
    )

    # Context
    tenant = Column(UUID(as_uuid=True), nullable=False, index=True)
    device_id = Column(
        Integer,
        ForeignKey("dim_device.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # Execution
    algorithm_type = Column(Text, nullable=False)
    execution_start = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )
    execution_end = Column(DateTime(timezone=True), nullable=True)
    duration_seconds = Column(Numeric(10, 3), nullable=True)

    # Period
    period_start = Column(DateTime(timezone=True), nullable=False)
    period_end = Column(DateTime(timezone=True), nullable=False)

    # Results
    status = Column(Text, nullable=False, server_default="success")
    anomalies_detected = Column(Integer, nullable=False, server_default="0")
    records_analyzed = Column(Integer, nullable=False, server_default="0")
    config_snapshot = Column(JSONB, nullable=False, server_default="{}")

    # Error
    error_message = Column(Text, nullable=True)

    # Metadata
    triggered_by = Column(Text, nullable=True)
    airflow_run_id = Column(Text, nullable=True)
    airflow_task_id = Column(Text, nullable=True)
    created_at = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )

    __table_args__ = (
        Index("idx_anomaly_exec_tenant_start", "tenant", "execution_start"),
        Index("idx_anomaly_exec_status", "status"),
        Index("idx_anomaly_exec_algorithm", "algorithm_type", "execution_start"),
        CheckConstraint(
            "status IN ('success', 'partial', 'failed', 'skipped')",
            name="chk_anomaly_exec_status",
        ),
    )


class Recommendation(Base):
    """Optimization recommendations generated by the AI system."""

    __tablename__ = "recommendation"

    # Primary key
    id = Column(
        UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")
    )

    # Context
    tenant = Column(UUID(as_uuid=True), nullable=False, index=True)
    device_id = Column(
        Integer,
        ForeignKey("dim_device.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # Recommendation
    recommendation_type = Column(Text, nullable=False)
    generated_at = Column(
        DateTime(timezone=True),
        nullable=False,
        server_default=text("NOW()"),
        index=True,
    )
    title = Column(Text, nullable=False)
    description = Column(Text, nullable=False)

    # Savings
    estimated_savings_pct = Column(Numeric(5, 2), nullable=True)
    estimated_savings_value = Column(Numeric(10, 2), nullable=True)
    estimated_savings_currency = Column(Text, nullable=True, server_default="PLN")

    # Priority
    priority = Column(Text, nullable=False, server_default="medium")
    confidence_score = Column(Numeric(5, 4), nullable=True)

    # Analysis
    analysis_period_start = Column(DateTime(timezone=True), nullable=False)
    analysis_period_end = Column(DateTime(timezone=True), nullable=False)
    data_points_analyzed = Column(Integer, nullable=True)
    details = Column(JSONB, nullable=False, server_default="{}")

    # Status
    status = Column(Text, nullable=False, server_default="pending")
    reviewed_at = Column(DateTime(timezone=True), nullable=True)
    reviewed_by = Column(Text, nullable=True)
    rule_id = Column(UUID(as_uuid=True), nullable=True)
    expires_at = Column(DateTime(timezone=True), nullable=True)

    # Audit
    created_at = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )

    __table_args__ = (
        Index("idx_rec_tenant_generated", "tenant", "generated_at"),
        Index("idx_rec_device_generated", "device_id", "generated_at"),
        Index("idx_rec_type", "recommendation_type"),
        Index("idx_rec_status_priority", "status", "priority", "generated_at"),
        Index(
            "idx_rec_pending",
            "status",
            "generated_at",
            postgresql_where=text("status = 'pending'"),
        ),
        CheckConstraint(
            "recommendation_type IN ('optimize_heating_curve', "
            "'reduce_night_consumption', 'balance_phases', 'adjust_schedule', "
            "'replace_device', 'improve_power_factor', 'shift_load')",
            name="chk_rec_type",
        ),
        CheckConstraint(
            "priority IN ('low', 'medium', 'high')", name="chk_rec_priority"
        ),
        CheckConstraint(
            "status IN ('pending', 'accepted', 'rejected', 'applied', 'expired')",
            name="chk_rec_status",
        ),
    )


class RecommendationExecution(Base):
    """Audit log for recommendation generator executions."""

    __tablename__ = "recommendation_execution"

    # Primary key
    id = Column(
        UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")
    )

    # Context
    tenant = Column(UUID(as_uuid=True), nullable=False, index=True)

    # Execution
    execution_start = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )
    execution_end = Column(DateTime(timezone=True), nullable=True)
    duration_seconds = Column(Numeric(10, 3), nullable=True)

    # Period
    analysis_period_start = Column(DateTime(timezone=True), nullable=False)
    analysis_period_end = Column(DateTime(timezone=True), nullable=False)

    # Results
    status = Column(Text, nullable=False, server_default="success")
    recommendations_generated = Column(Integer, nullable=False, server_default="0")
    devices_analyzed = Column(Integer, nullable=False, server_default="0")

    # Error
    error_message = Column(Text, nullable=True)

    # Metadata
    triggered_by = Column(Text, nullable=True)
    airflow_run_id = Column(Text, nullable=True)
    airflow_task_id = Column(Text, nullable=True)
    created_at = Column(
        DateTime(timezone=True), nullable=False, server_default=text("NOW()")
    )

    __table_args__ = (
        Index("idx_rec_exec_tenant_start", "tenant", "execution_start"),
        Index("idx_rec_exec_status", "status"),
        CheckConstraint(
            "status IN ('success', 'partial', 'failed', 'skipped')",
            name="chk_rec_exec_status",
        ),
    )
