"""
db_models.py
-------------
SQLAlchemy ORM models. These mirror database/schema.sql field-for-field so
the same logical schema works whether you run against MySQL (production,
via DATABASE_URL) or SQLite (local dev default).
"""

import uuid
from datetime import datetime, timezone

from sqlalchemy import (
    Column, BigInteger, String, Boolean, DateTime, Date, Text, JSON,
    ForeignKey, Enum, SmallInteger, Numeric, UniqueConstraint,
)
from sqlalchemy.orm import relationship

from .database import Base


def _utcnow():
    return datetime.now(timezone.utc)


class User(Base):
    __tablename__ = "users"

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    participant_code = Column(String(32), unique=True, nullable=False,
                               default=lambda: f"P-{uuid.uuid4().hex[:10].upper()}")
    email = Column(String(255), unique=True, nullable=False, index=True)
    password_hash = Column(String(255), nullable=False)
    display_name = Column(String(100), nullable=True)
    date_of_birth = Column(Date, nullable=True)
    is_email_verified = Column(Boolean, default=False, nullable=False)
    email_verify_token = Column(String(255), nullable=True)
    email_verify_sent_at = Column(DateTime, nullable=True)
    consent_given_at = Column(DateTime, nullable=True)
    is_active = Column(Boolean, default=True, nullable=False)
    created_at = Column(DateTime, default=_utcnow, nullable=False)
    updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow, nullable=False)

    sessions = relationship("ChatSession", back_populates="user", cascade="all, delete-orphan")


class ChatSession(Base):
    __tablename__ = "chat_sessions"

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    session_uuid = Column(String(36), unique=True, nullable=False, default=lambda: str(uuid.uuid4()))
    user_id = Column(BigInteger, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
    stage = Column(String(32), default="intro_consent", nullable=False)
    consent_given = Column(Boolean, default=False, nullable=False)
    safety_paused = Column(Boolean, default=False, nullable=False)
    started_at = Column(DateTime, default=_utcnow, nullable=False)
    completed_at = Column(DateTime, nullable=True)

    user = relationship("User", back_populates="sessions")
    messages = relationship("Message", back_populates="session", cascade="all, delete-orphan")
    questionnaire_responses = relationship(
        "QuestionnaireResponse", back_populates="session", cascade="all, delete-orphan"
    )
    prediction = relationship(
        "AIPrediction", back_populates="session", uselist=False, cascade="all, delete-orphan"
    )
    report = relationship("Report", back_populates="session", uselist=False, cascade="all, delete-orphan")


class Message(Base):
    __tablename__ = "messages"

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    session_id = Column(BigInteger, ForeignKey("chat_sessions.id", ondelete="CASCADE"), nullable=False)
    speaker = Column(Enum("bot", "user", name="speaker_enum"), nullable=False)
    content = Column(Text, nullable=False)
    nlp_features = Column(JSON, nullable=True)
    created_at = Column(DateTime, default=_utcnow, nullable=False)

    session = relationship("ChatSession", back_populates="messages")


class QuestionnaireResponse(Base):
    __tablename__ = "questionnaire_responses"
    __table_args__ = (
        UniqueConstraint("session_id", "instrument", "item_index", name="uq_session_instrument_item"),
    )

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    session_id = Column(BigInteger, ForeignKey("chat_sessions.id", ondelete="CASCADE"), nullable=False)
    instrument = Column(Enum("PHQ9", "GAD7", "PSS10", name="instrument_enum"), nullable=False)
    item_index = Column(SmallInteger, nullable=False)
    response_value = Column(SmallInteger, nullable=False)
    raw_user_text = Column(Text, nullable=True)
    created_at = Column(DateTime, default=_utcnow, nullable=False)

    session = relationship("ChatSession", back_populates="questionnaire_responses")


class AIPrediction(Base):
    __tablename__ = "ai_predictions"

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    session_id = Column(BigInteger, ForeignKey("chat_sessions.id", ondelete="CASCADE"),
                         nullable=False, unique=True)
    depression_score = Column(Numeric(5, 1), nullable=False)
    depression_risk_level = Column(Enum("Low", "Moderate", "High", name="risk_enum_dep"), nullable=False)
    anxiety_score = Column(Numeric(5, 1), nullable=False)
    anxiety_risk_level = Column(Enum("Low", "Moderate", "High", name="risk_enum_anx"), nullable=False)
    stress_score = Column(Numeric(5, 1), nullable=False)
    stress_risk_level = Column(Enum("Low", "Moderate", "High", name="risk_enum_stress"), nullable=False)
    overall_wellness_score = Column(Numeric(5, 1), nullable=False)
    confidence_score = Column(Numeric(4, 3), nullable=False)
    ml_predicted_risk = Column(Enum("Low", "Moderate", "High", name="risk_enum_ml"), nullable=True)
    explanation_json = Column(JSON, nullable=False)
    created_at = Column(DateTime, default=_utcnow, nullable=False)

    session = relationship("ChatSession", back_populates="prediction")


class Report(Base):
    __tablename__ = "reports"

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    session_id = Column(BigInteger, ForeignKey("chat_sessions.id", ondelete="CASCADE"),
                         nullable=False, unique=True)
    report_html = Column(Text, nullable=False)
    generated_at = Column(DateTime, default=_utcnow, nullable=False)

    session = relationship("ChatSession", back_populates="report")


class Feedback(Base):
    __tablename__ = "feedback"

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    user_id = Column(BigInteger, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    session_id = Column(BigInteger, ForeignKey("chat_sessions.id", ondelete="SET NULL"), nullable=True)
    rating = Column(SmallInteger, nullable=True)
    comment = Column(Text, nullable=True)
    created_at = Column(DateTime, default=_utcnow, nullable=False)
