"""Add sessions and session_messages tables.

This migration creates the two session persistence tables needed for
the Session service:

- ``sessions``: Persistent conversation threads tied to orchestrator actors.
- ``session_messages``: Ordered messages within a session conversation.

Revision ID: a7_001_session_persistence
Revises: c1_001_tool_registry
Create Date: 2026-02-14 12:00:00

"""

from collections.abc import Sequence

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision: str = "a7_001_session_persistence"
down_revision: str | Sequence[str] | None = "c1_001_tool_registry"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    """Create sessions and session_messages tables."""
    # --- sessions table ---
    op.create_table(
        "sessions",
        # PK: ULID (26-char string)
        sa.Column("session_id", sa.String(26), nullable=False),
        # Optional actor binding
        sa.Column("actor_name", sa.String(255), nullable=True),
        # Namespace for session ownership
        sa.Column(
            "namespace",
            sa.String(100),
            nullable=False,
            server_default="local",
        ),
        # Session-level automation override
        sa.Column("automation_level", sa.String(30), nullable=True),
        # JSON: list of linked plan ULIDs
        sa.Column("linked_plan_ids_json", sa.Text(), nullable=True),
        # JSON: token usage tracking
        sa.Column("token_usage_json", sa.Text(), nullable=True),
        # JSON: arbitrary session metadata
        sa.Column("metadata_json", sa.Text(), nullable=True),
        # Timestamps (ISO-8601 strings)
        sa.Column("created_at", sa.String(30), nullable=False),
        sa.Column("updated_at", sa.String(30), nullable=False),
        # Constraints
        sa.PrimaryKeyConstraint("session_id"),
    )

    op.create_index(
        "ix_sessions_created_at",
        "sessions",
        ["created_at"],
        unique=False,
    )
    op.create_index(
        "ix_sessions_actor_name",
        "sessions",
        ["actor_name"],
        unique=False,
    )

    # --- session_messages table ---
    op.create_table(
        "session_messages",
        # PK: ULID (26-char string)
        sa.Column("message_id", sa.String(26), nullable=False),
        # FK to sessions
        sa.Column(
            "session_id",
            sa.String(26),
            sa.ForeignKey(
                "sessions.session_id",
                ondelete="CASCADE",
                name="fk_session_messages_session",
            ),
            nullable=False,
        ),
        # Message role: user | assistant | system | tool
        sa.Column("role", sa.String(20), nullable=False),
        # Message content (full text)
        sa.Column("content", sa.Text(), nullable=False),
        # Ordering index within the session
        sa.Column("sequence", sa.Integer(), nullable=False),
        # Message creation timestamp (ISO-8601 string)
        sa.Column("timestamp", sa.String(30), nullable=False),
        # JSON: optional message metadata
        sa.Column("metadata_json", sa.Text(), nullable=True),
        # Tool call identifier (required when role is 'tool')
        sa.Column("tool_call_id", sa.String(255), nullable=True),
        # Constraints
        sa.PrimaryKeyConstraint("message_id"),
    )

    op.create_index(
        "ix_session_messages_session_id",
        "session_messages",
        ["session_id"],
        unique=False,
    )
    op.create_index(
        "ix_session_messages_sequence",
        "session_messages",
        ["session_id", "sequence"],
        unique=False,
    )


def downgrade() -> None:
    """Drop sessions and session_messages tables."""
    # Drop in reverse FK order: messages -> sessions
    op.drop_index("ix_session_messages_sequence", table_name="session_messages")
    op.drop_index("ix_session_messages_session_id", table_name="session_messages")
    op.drop_table("session_messages")

    op.drop_index("ix_sessions_actor_name", table_name="sessions")
    op.drop_index("ix_sessions_created_at", table_name="sessions")
    op.drop_table("sessions")
