"""Assistant identity + chat + onboarding models.

Three CARRIED v1 tables (near-verbatim port from
``data/v1-snapshot/v1_schema_pragma.txt``):

- ``chat_sessions``  — v1 columns + ``garden_id`` (D1) + two new columns from
  the approved plan (``status``, ``resolution``, ``resolution_note_id``) so a
  session can be resolved into a note or discarded.
- ``chat_messages``  — v1 columns exactly. ``photo_paths`` and ``tool_calls``
  were json-ish TEXT in v1 and STAY Text (don't improve a mature schema
  during a port).
- ``tool_suggestions`` — v1 columns exactly, no additions. The
  ``suggest_new_tool`` feature is NOT ported to v2, but the table is migrated
  so history survives.

Three NEW tables (from the approved plan):

- ``assistants``           — per-garden assistant identity/persona.
- ``assistant_templates``  — global (not garden-scoped) persona templates
  used to match/seed a garden's assistant.
- ``onboarding_sessions``  — links a garden's onboarding interview to the
  chat session that conducted it.

Notes:
- v1 ``chat_sessions.activity_log_id`` had NO FK in the pragma; carried as a
  plain BigInteger (the activity_log table lives in another module).
- ``resolution_note_id`` references ``notes.id`` (defined in another model
  module); string FK resolves at metadata level.
- v1 indexes are carried via ``__table_args__`` (names generated by the
  metadata naming convention).
"""
from __future__ import annotations

from datetime import datetime

import sqlalchemy as sa
from sqlalchemy import (
    BigInteger,
    CheckConstraint,
    DateTime,
    ForeignKey,
    Index,
    Integer,
    Text,
)
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column

from app.models.base import Base, created_at_column, garden_fk, pk_column


class ChatSession(Base):
    """CARRIED v1 ``chat_sessions`` + garden_id + resolution lifecycle."""

    __tablename__ = "chat_sessions"
    __table_args__ = (
        CheckConstraint(
            "status IN ('open', 'resolved', 'discarded')", name="status"
        ),
        Index(None, "created_at"),  # v1: idx_chat_sessions_created
    )

    id: Mapped[int] = pk_column()
    created_at: Mapped[datetime] = created_at_column()
    ended_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    title: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    summary: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    # v1 had no FK on this column (activity_log lives in another module).
    activity_log_id: Mapped[int | None] = mapped_column(
        BigInteger, nullable=True
    )

    # --- v2 additions (deviation D1 + approved plan) ---
    garden_id: Mapped[int] = garden_fk()
    status: Mapped[str] = mapped_column(
        Text, nullable=False, server_default=sa.text("'open'")
    )
    resolution: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
    # use_alter breaks the chat_sessions <-> notes FK cycle
    # (notes.source_conversation_id points back here): this constraint is
    # added via a post-create ALTER so table creation order can resolve.
    resolution_note_id: Mapped[int | None] = mapped_column(
        BigInteger,
        ForeignKey("notes.id", use_alter=True, name="fk_chat_sessions_resolution_note"),
        nullable=True,
    )


class ChatMessage(Base):
    """CARRIED v1 ``chat_messages`` — columns exactly as in the pragma."""

    __tablename__ = "chat_messages"
    __table_args__ = (
        Index(None, "session_id", "id"),  # v1: idx_chat_messages_session
    )

    id: Mapped[int] = pk_column()
    session_id: Mapped[int] = mapped_column(
        BigInteger,
        ForeignKey("chat_sessions.id", ondelete="CASCADE"),
        nullable=False,
    )
    created_at: Mapped[datetime] = created_at_column()
    role: Mapped[str] = mapped_column(Text, nullable=False)
    text: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    # json-ish TEXT in v1 — carried verbatim as Text, NOT JSONB.
    photo_paths: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    # json-ish TEXT in v1 — carried verbatim as Text, NOT JSONB.
    tool_calls: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    tokens_used: Mapped[int | None] = mapped_column(
        Integer, nullable=True, server_default=sa.text("0")
    )


class ToolSuggestion(Base):
    """CARRIED v1 ``tool_suggestions`` — no additions (history only).

    The v1 ``suggest_new_tool`` feature is not ported; rows are migrated so
    past suggestions remain queryable.
    """

    __tablename__ = "tool_suggestions"
    __table_args__ = (
        Index(None, "status", "created_at"),  # v1: idx_tool_suggestions_status
    )

    id: Mapped[int] = pk_column()
    created_at: Mapped[datetime] = created_at_column()
    session_id: Mapped[int | None] = mapped_column(
        BigInteger,
        ForeignKey("chat_sessions.id", ondelete="SET NULL"),
        nullable=True,
    )
    name: Mapped[str] = mapped_column(Text, nullable=False)
    signature: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    why_useful: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    example_question: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    status: Mapped[str] = mapped_column(
        Text, nullable=False, server_default=sa.text("'pending'")
    )


class Assistant(Base):
    """NEW — per-garden assistant identity/persona."""

    __tablename__ = "assistants"
    __table_args__ = (
        CheckConstraint("role IN ('primary', 'interviewer')", name="role"),
    )

    id: Mapped[int] = pk_column()
    garden_id: Mapped[int] = garden_fk()
    name: Mapped[str] = mapped_column(Text, nullable=False)
    role: Mapped[str] = mapped_column(
        Text, nullable=False, server_default=sa.text("'primary'")
    )
    persona_prompt: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    avatar_path: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    voice_examples: Mapped[list | None] = mapped_column(
        JSONB, nullable=True, server_default=sa.text("'[]'::jsonb")
    )
    notification_style: Mapped[dict | None] = mapped_column(
        JSONB, nullable=True, server_default=sa.text("'{}'::jsonb")
    )
    model_prefs: Mapped[dict | None] = mapped_column(
        JSONB, nullable=True, server_default=sa.text("'{}'::jsonb")
    )
    is_active: Mapped[bool | None] = mapped_column(
        sa.Boolean, nullable=True, server_default=sa.text("true")
    )
    created_at: Mapped[datetime] = created_at_column()


class AssistantTemplate(Base):
    """NEW — global persona templates (intentionally NOT garden-scoped)."""

    __tablename__ = "assistant_templates"

    id: Mapped[int] = pk_column()
    name: Mapped[str] = mapped_column(Text, nullable=False)
    persona_prompt: Mapped[str] = mapped_column(Text, nullable=False)
    voice_examples: Mapped[list | None] = mapped_column(
        JSONB, nullable=True, server_default=sa.text("'[]'::jsonb")
    )
    matching_profile: Mapped[dict | None] = mapped_column(
        JSONB, nullable=True, server_default=sa.text("'{}'::jsonb")
    )
    created_at: Mapped[datetime] = created_at_column()


class OnboardingSession(Base):
    """NEW — a garden's onboarding interview, hooked to its chat session."""

    __tablename__ = "onboarding_sessions"

    id: Mapped[int] = pk_column()
    garden_id: Mapped[int] = garden_fk()
    chat_session_id: Mapped[int | None] = mapped_column(
        BigInteger, ForeignKey("chat_sessions.id"), nullable=True
    )
    stage: Mapped[str | None] = mapped_column(
        Text, nullable=True, server_default=sa.text("''")
    )
    bootstrap: Mapped[dict | None] = mapped_column(
        JSONB, nullable=True, server_default=sa.text("'{}'::jsonb")
    )
    completed_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    created_at: Mapped[datetime] = created_at_column()
