"""Add actions_v3 table for v3 plan lifecycle.

This migration creates the actions_v3 table that stores reusable action templates.
Actions are created via CLI and define strategy/execution actors and arguments.
The table uses ULID text primary keys (26-character Crockford base32).

This must run BEFORE the lifecycle_plans migration since lifecycle_plans
references actions_v3.action_id as a foreign key.

Revision ID: a5_001_actions_v3
Revises: c3d9b3d0cf3e
Create Date: 2026-02-09 00:00:00

"""

from collections.abc import Sequence

import sqlalchemy as sa
from alembic import op

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


def upgrade() -> None:
    """Create actions_v3 table for v3 plan lifecycle action templates."""
    op.create_table(
        "actions_v3",
        # Identity - ULID primary key (26 chars, Crockford base32)
        sa.Column("action_id", sa.String(26), nullable=False),
        # Naming - full namespaced name (e.g., "local/code-coverage", "myorg/deploy")
        sa.Column("name", sa.String(255), nullable=False),
        # Extracted namespace for filtering (e.g., "local", "myorg")
        sa.Column("namespace", sa.String(100), nullable=False),
        # Extracted short name after namespace (e.g., "code-coverage")
        sa.Column("short_name", sa.String(150), nullable=False),
        # Descriptions
        sa.Column("short_description", sa.Text(), nullable=True),
        sa.Column("long_description", sa.Text(), nullable=True),
        # Definition of done - explicit testable completion criteria
        sa.Column("definition_of_done", sa.Text(), nullable=False),
        # Actor references (namespaced names)
        sa.Column("strategy_actor", sa.String(255), nullable=False),
        sa.Column("execution_actor", sa.String(255), nullable=False),
        sa.Column("estimation_actor", sa.String(255), nullable=True),
        sa.Column("review_actor", sa.String(255), nullable=True),
        sa.Column("apply_actor", sa.String(255), nullable=True),
        # Inputs schema - JSON array of ActionArgument definitions
        sa.Column(
            "inputs_schema",
            sa.Text(),
            nullable=False,
            server_default="[]",
        ),
        # State management
        sa.Column(
            "state",
            sa.String(20),
            nullable=False,
            server_default="draft",
        ),
        # Behavior flags
        sa.Column(
            "reusable",
            sa.Boolean(),
            nullable=False,
            server_default=sa.text("1"),
        ),
        sa.Column(
            "read_only",
            sa.Boolean(),
            nullable=False,
            server_default=sa.text("0"),
        ),
        # Metadata
        sa.Column("created_by", sa.String(255), nullable=True),
        sa.Column("tags", sa.Text(), nullable=False, server_default="[]"),
        # Timestamps (ISO8601 strings for portability)
        sa.Column("created_at", sa.String(30), nullable=False),
        sa.Column("updated_at", sa.String(30), nullable=False),
        # Constraints
        sa.PrimaryKeyConstraint("action_id"),
        sa.UniqueConstraint("name", name="uq_actions_v3_name"),
        sa.CheckConstraint(
            "state IN ('available', 'draft', 'archived')",
            name="ck_actions_v3_state",
        ),
    )

    # Indices for common queries
    op.create_index(
        "ix_actions_v3_namespace",
        "actions_v3",
        ["namespace"],
        unique=False,
    )
    op.create_index(
        "ix_actions_v3_state",
        "actions_v3",
        ["state"],
        unique=False,
    )
    op.create_index(
        "ix_actions_v3_short_name",
        "actions_v3",
        ["short_name"],
        unique=False,
    )


def downgrade() -> None:
    """Drop actions_v3 table."""
    op.drop_index("ix_actions_v3_short_name", table_name="actions_v3")
    op.drop_index("ix_actions_v3_state", table_name="actions_v3")
    op.drop_index("ix_actions_v3_namespace", table_name="actions_v3")
    op.drop_table("actions_v3")
