"""audit_logs 表 — 高危操作/登录/MFA 审计日志

Revision ID: 027_audit_logs
Revises: 026_drop_agent_otp_legacy
Create Date: 2026-06-22 (v0.7.1)

v0.7.1 task #89 实施,配合 RBAC 5 角色的 audit_log 资源(给 auditor 角色只读用)

字段:
  - id: UUID 主键
  - employee_id: 操作人(企微 UserID / 'system')
  - action: 操作类型
  - resource: 目标资源类型
  - resource_id: 目标资源 ID
  - details: JSON 详细上下文
  - result: success / failure / partial
  - ip_address: 来源 IP
  - user_agent: 来源 UA
  - created_at: 时间

索引:
  - idx_audit_employee_id: 按操作人查
  - idx_audit_action: 按操作类型查
  - idx_audit_resource: 按资源类型+ID 查
  - idx_audit_created_at: 按时间范围查(默认倒序)
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers
revision = '027_audit_logs'
down_revision = '026_drop_agent_otp_legacy'
branch_labels = None
depends_on = None


def upgrade() -> None:
    """建 audit_logs 表 + 索引。"""
    bind = op.get_bind()
    inspector = sa.inspect(bind)

    if not inspector.has_table('audit_logs'):
        op.create_table(
            'audit_logs',
            sa.Column('id', sa.String(36), primary_key=True),
            sa.Column('employee_id', sa.String(100), nullable=False,
                      comment='操作人(employee_id / system)'),
            sa.Column('action', sa.String(50), nullable=False,
                      comment='操作类型'),
            sa.Column('resource', sa.String(50), nullable=False,
                      comment='目标资源类型'),
            sa.Column('resource_id', sa.String(100), nullable=True,
                      comment='目标资源 ID'),
            sa.Column('details', sa.JSON, nullable=True,
                      comment='详细上下文(JSON)'),
            sa.Column('result', sa.String(20), nullable=False, server_default='success',
                      comment='执行结果'),
            sa.Column('ip_address', sa.String(64), nullable=True,
                      comment='来源 IP'),
            sa.Column('user_agent', sa.Text, nullable=True,
                      comment='来源 User-Agent'),
            sa.Column('created_at', sa.DateTime(timezone=True), nullable=False,
                      comment='时间'),
        )

    # 4 个索引 (IF NOT EXISTS 兼容)
    op.execute("CREATE INDEX IF NOT EXISTS idx_audit_employee_id ON audit_logs (employee_id)")
    op.execute("CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_logs (action)")
    op.execute("CREATE INDEX IF NOT EXISTS idx_audit_resource ON audit_logs (resource, resource_id)")
    op.execute("CREATE INDEX IF NOT EXISTS idx_audit_created_at ON audit_logs (created_at)")


def downgrade() -> None:
    """删 audit_logs 表(顺序: 删索引 → 删表)。"""
    op.execute("DROP INDEX IF EXISTS idx_audit_created_at")
    op.execute("DROP INDEX IF EXISTS idx_audit_resource")
    op.execute("DROP INDEX IF EXISTS idx_audit_action")
    op.execute("DROP INDEX IF EXISTS idx_audit_employee_id")
    op.execute("DROP TABLE IF EXISTS audit_logs")
