"""add agent MFA fields

Revision ID: 023_mfa_fields
Revises: 012_sync_remaining_fields
Create Date: 2026-06-21

Phase 2.1 task #17: pyotp TOTP 服务 + User MFA 字段
- 新增 mfa_secret 字段(存储 TOTP secret,绑定时生成,首次验证前不算启用)
- 新增 mfa_enabled 字段(是否启用 MFA,默认 False)
- 新增 mfa_bound_at 字段(首次绑定完成时间,可空)
- 新增 mfa_last_verified_at 字段(最近一次验证成功时间,可空)

为什么需要独立字段而非复用早期 otp_*:
  Phase 2.1 的 MFA 是面向全员(员工 + 坐席)的统一二次认证方案,
  与早期仅供 admin 强制 OTP 的 otp_secret / otp_enabled 是两套体系。
  字段独立便于后续维护 + 迁移路径清晰。

为什么不破坏现有坐席:
  - mfa_secret 默认为 NULL,允许已注册坐席不绑定
  - mfa_enabled 用 server_default=text('false')(字符串 false,不是 Python False),
    否则 Alembic 会写入整数 0 在 PG 里被解读为 truthy
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers
revision = '023_mfa_fields'
down_revision = '012_sync_remaining_fields'
branch_labels = None
depends_on = None


def upgrade() -> None:
    """添加 4 个 MFA 字段到 agents 表"""
    # --------------------------------------------------------------------------
    # mfa_secret: TOTP 共享密钥(base32,绑定时生成)
    # 可空,默认 None — 用户没绑定时就是空
    # --------------------------------------------------------------------------
    op.add_column(
        'agents',
        sa.Column(
            'mfa_secret',
            sa.String(32),
            nullable=True,
            comment='MFA TOTP 共享密钥(base32,绑定时生成)',
        )
    )

    # --------------------------------------------------------------------------
    # mfa_enabled: 是否启用 MFA
    # 非空,默认 False
    # server_default 必须用 text('false') 字符串形式(PG 把 false 解析为布尔 false)
    # 直接传 sa.text('False') 或 Python False 会被 SQLAlchemy 当成 truthy 写出 '1'
    # 详见 memory: feedback-adopted-default-bug.md
    # --------------------------------------------------------------------------
    op.add_column(
        'agents',
        sa.Column(
            'mfa_enabled',
            sa.Boolean(),
            nullable=False,
            server_default=sa.text('false'),
            comment='MFA 是否启用(False/True)',
        )
    )

    # --------------------------------------------------------------------------
    # mfa_bound_at: 首次绑定完成时间(可空)
    # --------------------------------------------------------------------------
    op.add_column(
        'agents',
        sa.Column(
            'mfa_bound_at',
            sa.DateTime(timezone=True),
            nullable=True,
            comment='MFA 首次绑定完成时间',
        )
    )

    # --------------------------------------------------------------------------
    # mfa_last_verified_at: 最近一次验证成功时间(可空,审计用)
    # --------------------------------------------------------------------------
    op.add_column(
        'agents',
        sa.Column(
            'mfa_last_verified_at',
            sa.DateTime(timezone=True),
            nullable=True,
            comment='MFA 最近一次验证成功时间',
        )
    )


def downgrade() -> None:
    """删除 4 个 MFA 字段(按添加的逆序)"""
    op.drop_column('agents', 'mfa_last_verified_at')
    op.drop_column('agents', 'mfa_bound_at')
    op.drop_column('agents', 'mfa_enabled')
    op.drop_column('agents', 'mfa_secret')