"""add server-issued expense application preview decisions

Revision ID: 20260714_0004
Revises: 20260714_0003
Create Date: 2026-07-14 15:30:00
"""

from collections.abc import Sequence

import sqlalchemy as sa

from alembic import op

revision: str = "20260714_0004"
down_revision: str | None = "20260714_0003"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    op.create_table(
        "ai_application_preview_decisions",
        sa.Column("id", sa.String(length=36), nullable=False),
        sa.Column("tenant_id", sa.String(length=64), nullable=False),
        sa.Column("actor_id", sa.String(length=120), nullable=False),
        sa.Column("auth_session_id", sa.String(length=120), nullable=False),
        sa.Column("conversation_id", sa.String(length=120), nullable=False),
        sa.Column("decision_type", sa.String(length=80), nullable=False),
        sa.Column("decision_source", sa.String(length=20), nullable=False),
        sa.Column("field_keys_json", sa.JSON(), nullable=False),
        sa.Column("field_fingerprints_json", sa.JSON(), nullable=False),
        sa.Column("snapshot_fingerprint", sa.String(length=80), nullable=False),
        sa.Column("fingerprint_key_version", sa.String(length=40), nullable=False),
        sa.Column("source_version_json", sa.JSON(), nullable=False),
        sa.Column("status", sa.String(length=20), nullable=False),
        sa.Column("issue_request_id", sa.String(length=120), nullable=False),
        sa.Column("consumed_action", sa.String(length=30), nullable=True),
        sa.Column("consumed_request_id", sa.String(length=120), nullable=True),
        sa.Column("consumed_claim_id", sa.String(length=36), nullable=True),
        sa.Column("consumed_business_event_id", sa.String(length=36), nullable=True),
        sa.Column("consumed_final_fingerprint", sa.String(length=80), nullable=True),
        sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("consumed_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column(
            "created_at",
            sa.DateTime(timezone=True),
            server_default=sa.func.now(),
            nullable=False,
        ),
        sa.CheckConstraint(
            "status IN ('issued', 'consumed', 'expired', 'revoked')",
            name="ck_ai_application_preview_decisions_status",
        ),
        sa.CheckConstraint(
            "decision_source IN ('heuristic', 'rule', 'hybrid', 'server_draft')",
            name="ck_ai_application_preview_decisions_source",
        ),
        sa.CheckConstraint(
            "consumed_action IS NULL OR consumed_action IN ('save_draft', 'submit')",
            name="ck_ai_application_preview_decisions_consumed_action",
        ),
        sa.CheckConstraint(
            "status != 'consumed' OR ("
            "consumed_action IS NOT NULL AND consumed_request_id IS NOT NULL AND "
            "consumed_claim_id IS NOT NULL AND consumed_business_event_id IS NOT NULL AND "
            "consumed_final_fingerprint IS NOT NULL AND consumed_at IS NOT NULL)",
            name="ck_ai_application_preview_decisions_consumed_fields",
        ),
        sa.CheckConstraint(
            "expires_at > created_at",
            name="ck_ai_application_preview_decisions_expiry",
        ),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint(
            "tenant_id",
            "id",
            name="uq_ai_application_preview_decisions_tenant_id",
        ),
        sa.UniqueConstraint(
            "tenant_id",
            "actor_id",
            "auth_session_id",
            "issue_request_id",
            name="uq_ai_application_preview_decisions_issue_request",
        ),
    )
    op.create_index(
        "ix_ai_application_preview_decisions_actor_status_expiry",
        "ai_application_preview_decisions",
        ["tenant_id", "actor_id", "status", "expires_at"],
    )
    op.create_index(
        "ix_ai_application_preview_decisions_conversation",
        "ai_application_preview_decisions",
        ["tenant_id", "conversation_id", "created_at"],
    )

    op.add_column(
        "ai_decisions",
        sa.Column("preview_decision_id", sa.String(length=36), nullable=True),
    )
    op.create_foreign_key(
        "fk_ai_decisions_tenant_preview_decision",
        "ai_decisions",
        "ai_application_preview_decisions",
        ["tenant_id", "preview_decision_id"],
        ["tenant_id", "id"],
        ondelete="RESTRICT",
    )
    op.create_unique_constraint(
        "uq_ai_decisions_tenant_preview_decision",
        "ai_decisions",
        ["tenant_id", "preview_decision_id"],
    )


def downgrade() -> None:
    op.drop_constraint(
        "uq_ai_decisions_tenant_preview_decision",
        "ai_decisions",
        type_="unique",
    )
    op.drop_constraint(
        "fk_ai_decisions_tenant_preview_decision",
        "ai_decisions",
        type_="foreignkey",
    )
    op.drop_column("ai_decisions", "preview_decision_id")

    op.drop_index(
        "ix_ai_application_preview_decisions_conversation",
        table_name="ai_application_preview_decisions",
    )
    op.drop_index(
        "ix_ai_application_preview_decisions_actor_status_expiry",
        table_name="ai_application_preview_decisions",
    )
    op.drop_table("ai_application_preview_decisions")
