"""Edge Functions: function_library, project_functions, project_function_versions,
project_webhook_endpoints, worker_runtime_versions, workspace_runtime_config.

Revision ID: 036
Revises: 035
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

revision = "036"
down_revision = "035"
branch_labels = None
depends_on = None


def upgrade() -> None:
    # ------------------------------------------------------------------
    # function_library — platform pre-built function registry
    # ------------------------------------------------------------------
    op.create_table(
        "function_library",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column("name", sa.String(120), nullable=False),
        sa.Column("slug", sa.String(64), nullable=False),
        sa.Column("description", sa.Text, nullable=True),
        sa.Column("runtime", sa.String(20), nullable=False, server_default="js"),
        sa.Column("trigger_type", sa.String(20), nullable=False, server_default="http"),
        sa.Column("required_integrations", postgresql.JSONB, nullable=True),
        sa.Column("required_secrets", postgresql.JSONB, nullable=True),
        sa.Column("tags", postgresql.JSONB, nullable=True),
        sa.Column("code_bundle_ref", sa.String(512), nullable=False),  # R2 key
        sa.Column("version", sa.String(20), nullable=False, server_default="1.0.0"),
        sa.Column("is_official", sa.Boolean, nullable=False, server_default="true"),
        sa.Column("is_active", sa.Boolean, nullable=False, server_default="true"),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.UniqueConstraint("slug", name="uq_function_library_slug"),
    )
    op.create_index("ix_function_library_slug", "function_library", ["slug"])
    op.create_index("ix_function_library_trigger_type", "function_library", ["trigger_type"])
    op.create_index("ix_function_library_is_active", "function_library", ["is_active"])

    # ------------------------------------------------------------------
    # project_functions — deployed function metadata per project
    # ------------------------------------------------------------------
    op.create_table(
        "project_functions",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column(
            "project_id",
            postgresql.UUID(as_uuid=True),
            sa.ForeignKey("projects.id", ondelete="CASCADE"),
            nullable=False,
        ),
        sa.Column("slug", sa.String(64), nullable=False),
        sa.Column("name", sa.String(120), nullable=False),
        sa.Column("description", sa.Text, nullable=True),
        sa.Column("runtime", sa.String(20), nullable=False, server_default="js"),
        # http | event | schedule | webhook
        sa.Column("trigger_type", sa.String(20), nullable=False, server_default="http"),
        # e.g. {"path":"/api/fn/slug"} | {"event_type":"auth.signed_up"} | {"cron":"0 * * * *"}
        sa.Column("trigger_config", postgresql.JSONB, nullable=True),
        sa.Column(
            "active_version_id",
            postgresql.UUID(as_uuid=True),
            nullable=True,
        ),
        # pending | deploying | active | error | disabled
        sa.Column("status", sa.String(20), nullable=False, server_default="pending"),
        # Non-null if deployed from library
        sa.Column(
            "library_fn_id",
            postgresql.UUID(as_uuid=True),
            sa.ForeignKey("function_library.id", ondelete="SET NULL"),
            nullable=True,
        ),
        sa.Column("secret_refs", postgresql.JSONB, nullable=True),
        sa.Column("created_by", sa.String(20), nullable=False, server_default="user"),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
        sa.UniqueConstraint("project_id", "slug", name="uq_project_function_project_slug"),
    )
    op.create_index("ix_project_functions_project_id", "project_functions", ["project_id"])
    op.create_index("ix_project_functions_status", "project_functions", ["project_id", "status"])

    # ------------------------------------------------------------------
    # project_function_versions — version history per function
    # ------------------------------------------------------------------
    op.create_table(
        "project_function_versions",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column(
            "function_id",
            postgresql.UUID(as_uuid=True),
            sa.ForeignKey("project_functions.id", ondelete="CASCADE"),
            nullable=False,
        ),
        sa.Column("version_number", sa.Integer, nullable=False),
        sa.Column("code_bundle_ref", sa.String(512), nullable=True),  # R2 key (custom code)
        sa.Column(
            "library_fn_id",
            postgresql.UUID(as_uuid=True),
            sa.ForeignKey("function_library.id", ondelete="SET NULL"),
            nullable=True,
        ),
        sa.Column("library_fn_version", sa.String(20), nullable=True),
        # pending | deploying | deployed | rolled_back | failed
        sa.Column("status", sa.String(20), nullable=False, server_default="pending"),
        sa.Column("deployed_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("rollback_from_version", sa.Integer, nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.UniqueConstraint(
            "function_id", "version_number", name="uq_project_fn_version_fn_version"
        ),
    )
    op.create_index(
        "ix_project_function_versions_function_id",
        "project_function_versions",
        ["function_id"],
    )

    # Add self-ref FK on project_functions.active_version_id after versions table exists
    op.create_foreign_key(
        "fk_project_functions_active_version",
        "project_functions",
        "project_function_versions",
        ["active_version_id"],
        ["id"],
        ondelete="SET NULL",
    )

    # ------------------------------------------------------------------
    # project_webhook_endpoints — webhook URL → project+provider mapping
    # ------------------------------------------------------------------
    op.create_table(
        "project_webhook_endpoints",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column(
            "project_id",
            postgresql.UUID(as_uuid=True),
            sa.ForeignKey("projects.id", ondelete="CASCADE"),
            nullable=False,
        ),
        sa.Column("wh_token", sa.String(64), nullable=False),
        sa.Column("provider", sa.String(40), nullable=False),
        sa.Column("events_json", postgresql.JSONB, nullable=True),
        sa.Column("signing_secret_enc", sa.Text, nullable=True),  # Fernet-encrypted
        sa.Column("auto_registered", sa.Boolean, nullable=False, server_default="false"),
        sa.Column("registered_at", sa.DateTime(timezone=True), nullable=True),
        # Which function handles this webhook
        sa.Column("function_slug", sa.String(64), nullable=True),
        sa.Column("is_active", sa.Boolean, nullable=False, server_default="true"),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.UniqueConstraint("wh_token", name="uq_project_webhook_endpoint_token"),
    )
    op.create_index(
        "ix_project_webhook_endpoints_project_id",
        "project_webhook_endpoints",
        ["project_id"],
    )
    op.create_index(
        "ix_project_webhook_endpoints_wh_token",
        "project_webhook_endpoints",
        ["wh_token"],
        unique=True,
    )

    # ------------------------------------------------------------------
    # worker_runtime_versions — platform runtime release registry
    # ------------------------------------------------------------------
    op.create_table(
        "worker_runtime_versions",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column("version", sa.String(20), nullable=False),  # semver, e.g. "1.0.0"
        sa.Column("bundle_ref", sa.String(512), nullable=False),  # R2 key
        # draft | canary | stable | deprecated
        sa.Column("status", sa.String(20), nullable=False, server_default="draft"),
        sa.Column("release_notes", sa.Text, nullable=True),
        sa.Column("released_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("deprecated_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.UniqueConstraint("version", name="uq_worker_runtime_version"),
    )
    op.create_index("ix_worker_runtime_versions_status", "worker_runtime_versions", ["status"])

    # ------------------------------------------------------------------
    # workspace_runtime_config — per-workspace runtime version pinning
    # ------------------------------------------------------------------
    op.create_table(
        "workspace_runtime_config",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column(
            "workspace_id",
            postgresql.UUID(as_uuid=True),
            sa.ForeignKey("workspaces.id", ondelete="CASCADE"),
            nullable=False,
            unique=True,
        ),
        # null = auto-update to latest stable
        sa.Column("runtime_version", sa.String(20), nullable=True),
        sa.Column("auto_update", sa.Boolean, nullable=False, server_default="true"),
        sa.Column("last_updated_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
    )
    op.create_index(
        "ix_workspace_runtime_config_workspace_id",
        "workspace_runtime_config",
        ["workspace_id"],
        unique=True,
    )


def downgrade() -> None:
    op.drop_table("workspace_runtime_config")
    op.drop_table("worker_runtime_versions")
    op.drop_table("project_webhook_endpoints")
    op.drop_constraint(
        "fk_project_functions_active_version", "project_functions", type_="foreignkey"
    )
    op.drop_table("project_function_versions")
    op.drop_table("project_functions")
    op.drop_table("function_library")
