from datetime import UTC, datetime

from sqlalchemy import JSON, ForeignKey, Index, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

from zbt.infrastructure.mysql.types import UTCDateTime


def utc_now() -> datetime:
    return datetime.now(UTC)


class AgentBase(DeclarativeBase):
    pass


class AgentThreadRecord(AgentBase):
    __tablename__ = "agent_threads"
    __table_args__ = (
        Index("ix_agent_threads_owner_updated", "owner_type", "owner_id", "updated_at"),
    )

    id: Mapped[str] = mapped_column(String(26), primary_key=True)
    owner_type: Mapped[str] = mapped_column(String(16), nullable=False)
    owner_id: Mapped[str] = mapped_column(String(26), nullable=False)
    persona: Mapped[str] = mapped_column(String(32), nullable=False)
    title: Mapped[str] = mapped_column(String(128), nullable=False, default="")
    status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
    created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
    updated_at: Mapped[datetime] = mapped_column(
        UTCDateTime(), nullable=False, default=utc_now, onupdate=utc_now
    )


class AgentMessageRecord(AgentBase):
    __tablename__ = "agent_messages"
    __table_args__ = (Index("ix_agent_messages_thread_created", "thread_id", "created_at"),)

    id: Mapped[str] = mapped_column(String(26), primary_key=True)
    thread_id: Mapped[str] = mapped_column(
        String(26), ForeignKey("agent_threads.id"), nullable=False
    )
    role: Mapped[str] = mapped_column(String(16), nullable=False)
    content: Mapped[str] = mapped_column(Text, nullable=False)
    metadata_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
    created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)


class AgentRunRecord(AgentBase):
    __tablename__ = "agent_runs"
    __table_args__ = (
        Index("ix_agent_runs_thread_created", "thread_id", "created_at"),
        Index("ix_agent_runs_trace", "trace_id"),
    )

    id: Mapped[str] = mapped_column(String(26), primary_key=True)
    request_id: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
    thread_id: Mapped[str] = mapped_column(
        String(26), ForeignKey("agent_threads.id"), nullable=False
    )
    trace_id: Mapped[str | None] = mapped_column(String(64))
    persona: Mapped[str] = mapped_column(String(32), nullable=False)
    status: Mapped[str] = mapped_column(String(32), nullable=False)
    input_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
    output_json: Mapped[dict[str, object] | None] = mapped_column(JSON)
    error_code: Mapped[str | None] = mapped_column(String(64))
    created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
    completed_at: Mapped[datetime | None] = mapped_column(UTCDateTime())


class CustomerMemoryRecord(AgentBase):
    __tablename__ = "customer_memories"
    __table_args__ = (
        Index(
            "ix_customer_memories_owner_status",
            "owner_id",
            "status",
            "updated_at",
        ),
    )

    id: Mapped[str] = mapped_column(String(26), primary_key=True)
    owner_id: Mapped[str] = mapped_column(String(26), nullable=False)
    category: Mapped[str] = mapped_column(String(32), nullable=False)
    content: Mapped[str] = mapped_column(String(500), nullable=False)
    status: Mapped[str] = mapped_column(String(32), nullable=False)
    created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
    updated_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
