from datetime import datetime, timezone
from typing import TYPE_CHECKING

from sqlalchemy import JSON, DateTime, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from uuid6 import uuid7

from vdash.core import BaseModel

if TYPE_CHECKING:
    from vdash.modules.user_db.models import UserDB


class SqlConversation(BaseModel):
    __tablename__ = "sql_conversations"

    uuid: Mapped[str] = mapped_column(
        String(36),
        unique=True,
        nullable=False,
        default=lambda: str(uuid7()),
        index=True,
    )

    user_db_id: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        index=True,
    )

    title: Mapped[str | None] = mapped_column(
        String(500),
        nullable=True,
        doc="Auto-generated title from first question",
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        nullable=False,
    )

    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        onupdate=lambda: datetime.now(timezone.utc),
        nullable=False,
    )

    # Relationships (logical link, no FK constraint)
    user_db: Mapped["UserDB"] = relationship(
        primaryjoin="SqlConversation.user_db_id == foreign(UserDB.id)",
        lazy="joined",
    )

    messages: Mapped[list["SqlMessage"]] = relationship(
        primaryjoin="SqlConversation.id == foreign(SqlMessage.conversation_id)",
        order_by="SqlMessage.created_at",
        back_populates="conversation",
    )


class SqlMessage(BaseModel):
    __tablename__ = "sql_messages"

    uuid: Mapped[str] = mapped_column(
        String(36),
        unique=True,
        nullable=False,
        default=lambda: str(uuid7()),
        index=True,
    )

    conversation_id: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        index=True,
    )

    role: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        doc="user | assistant",
    )

    content: Mapped[dict] = mapped_column(
        JSON,
        nullable=False,
        doc="TextContent | SqlContent",
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        nullable=False,
    )

    # Relationship (logical link, no FK constraint)
    conversation: Mapped["SqlConversation"] = relationship(
        primaryjoin="foreign(SqlMessage.conversation_id) == SqlConversation.id",
        back_populates="messages",
    )

    sql_query: Mapped["SqlQuery | None"] = relationship(
        primaryjoin="SqlMessage.id == foreign(SqlQuery.message_id)",
        back_populates="message",
        uselist=False,
    )


class SqlQuery(BaseModel):
    __tablename__ = "sql_queries"

    uuid: Mapped[str] = mapped_column(
        String(36),
        unique=True,
        nullable=False,
        default=lambda: str(uuid7()),
        index=True,
    )

    message_id: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        index=True,
    )

    user_db_id: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        index=True,
    )

    name: Mapped[str | None] = mapped_column(
        String(500),
        nullable=True,
        doc="Auto-generated name from user input",
    )

    sql: Mapped[str] = mapped_column(Text, nullable=False)

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        nullable=False,
    )

    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        onupdate=lambda: datetime.now(timezone.utc),
        nullable=False,
    )

    # Relationship (logical link, no FK constraint)
    user_db: Mapped["UserDB"] = relationship(
        primaryjoin="SqlQuery.user_db_id == foreign(UserDB.id)",
        lazy="joined",
    )

    message: Mapped["SqlMessage"] = relationship(
        primaryjoin="foreign(SqlQuery.message_id) == SqlMessage.id",
        back_populates="sql_query",
    )
