# =============================================================================
# Alembic migration: messages.id 改为 UUID 列类型
# =============================================================================
# 背景(2026-06-21 评审):
#   当前 messages.id 在本地 dev 是 String(36) 存 UUID 字符串,
#   生产 PostgreSQL 应该是原生 UUID 列类型(性能更好,索引更小,类型严格)。
#   现状:本地 SQLite/String(36) 与生产 PostgreSQL/UUID 类型不一致,
#        跨环境数据迁移和 ORM 比较容易踩坑。
#
# 修复目标:
#   1. 生产 PostgreSQL: messages.id 改为原生 UUID 类型
#      - 节省存储(16 bytes vs 36 bytes)
#      - 索引更高效
#      - 数据库层强类型校验
#   2. 应用层兼容:SQLAlchemy 仍用 String(36),Python 端 str(uuid4()),
#      PG driver 会自动 cast 到 UUID 列(同 initial migration 的兼容策略)
#
# 注意:这个 migration 只在 PostgreSQL 上有效(UUID 是 PG 关键字)。
#      SQLite 测试环境会跳过执行(使用 `IF EXISTS` 或 try/except 兼容)。
#      实际上 SQLite 在 dev 用 create_all() 自动建表,根本不会跑 alembic。
#
# v1.0 前必做(对应 P0 评审 #60 messages.id 类型不匹配):
#   评审报告: docs/review/sql-messages-id-varchar-vs-uuid.md
# =============================================================================

"""messages id UUID type

Revision ID: 025_messages_id_uuid
Revises: 012_sync_remaining_fields
Create Date: 2026-06-21

v1.0 P0: messages.id 从 VARCHAR(32)/String(36) 改为 PostgreSQL 原生 UUID 类型

为什么需要这个 migration:
  - 当前 id 列是 VARCHAR,存 UUID 字符串(36 chars)
  - 生产 PG 应改用 UUID 类型,节省存储 + 数据库层强类型
  - SQLAlchemy 仍用 String(36) 兼容 SQLite/PG,Python 端 str(uuid4()) 通用
  - 数据无损:36 字符 UUID 字符串可直接 cast 到 UUID 列
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers
revision = '025_messages_id_uuid'
down_revision = '012_sync_remaining_fields'
branch_labels = None
depends_on = None


def upgrade() -> None:
    """把 messages.id 改为 PostgreSQL UUID 类型。

    实现细节:
      - 用 USING id::UUID 让 PG 自动把现有 VARCHAR 字符串 cast 到 UUID
      - 用 IF EXISTS 防御 SQLite 测试环境(没这列会跳过)
      - 只在 PostgreSQL 上跑(UUID 是 PG 关键字)

    兼容性:
      - 应用层 SQLAlchemy 模型:仍用 String(36),PG driver 自动 cast
      - Python 端:str(uuid.uuid4()) 生成 36 字符字符串,等价 UUID 字面量
      - 现有 36 字符 UUID 字符串数据:无丢失,无错误
    """
    bind = op.get_bind()
    # 只在 PostgreSQL 上执行(SQLite 测试环境无 UUID 关键字)
    if bind.dialect.name == "postgresql":
        op.execute(
            "ALTER TABLE messages ALTER COLUMN id TYPE UUID USING id::UUID"
        )


def downgrade() -> None:
    """把 messages.id 改回 VARCHAR(32)。

    警告:downgrade 会丢失 PG 强类型约束,生产回滚需谨慎。
    """
    bind = op.get_bind()
    if bind.dialect.name == "postgresql":
        op.execute(
            "ALTER TABLE messages ALTER COLUMN id TYPE VARCHAR(32) USING id::VARCHAR"
        )
