"""user.username(对外展示账号 ID)+ 默认昵称,并回填存量用户

Revision ID: b3f1a2c4d5e6
Revises: 45047b5a884c
Create Date: 2026-06-16 12:00:00.000000

加 user.username(11 位纯数字、首位非 1 与手机号天然区分、全局唯一)。存量用户:
生成唯一 username,昵称为空的补 9 位字母数字随机昵称。
迁移自包含(不 import app 业务代码,逻辑冻结为当时快照)。
"""
import secrets
import string
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'b3f1a2c4d5e6'
down_revision: Union[str, Sequence[str], None] = '45047b5a884c'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


_USERNAME_FIRST = "23456789"      # 首位避前导 0、避 1(手机号都以 1 开头)
_USERNAME_DIGITS = "0123456789"
_NICKNAME_ALPHABET = string.ascii_letters + string.digits


def _gen_username() -> str:
    return secrets.choice(_USERNAME_FIRST) + "".join(
        secrets.choice(_USERNAME_DIGITS) for _ in range(10)
    )


def _gen_nickname() -> str:
    return "".join(secrets.choice(_NICKNAME_ALPHABET) for _ in range(9))


def upgrade() -> None:
    # 1. 先加可空列(存量行此刻还没值)
    with op.batch_alter_table('user', schema=None) as batch_op:
        batch_op.add_column(sa.Column('username', sa.String(length=11), nullable=True))

    # 2. 回填存量:每人一个唯一 username;昵称为空的补随机昵称。
    #    表里 username 原本全空,本批用 used 防互撞即可(无既有非空值需规避)。
    #    "user" 是 PostgreSQL 保留字,必须加双引号(SQLite 也接受双引号标识符)。
    bind = op.get_bind()
    rows = bind.execute(sa.text('SELECT id, nickname FROM "user"')).fetchall()
    used = set()
    for row in rows:
        uid, nick = row[0], row[1]
        while True:
            uname = _gen_username()
            if uname not in used:
                used.add(uname)
                break
        if nick is None or not str(nick).strip():
            bind.execute(
                sa.text('UPDATE "user" SET username = :u, nickname = :n WHERE id = :i'),
                {"u": uname, "n": _gen_nickname(), "i": uid},
            )
        else:
            bind.execute(
                sa.text('UPDATE "user" SET username = :u WHERE id = :i'),
                {"u": uname, "i": uid},
            )

    # 3. 收紧:NOT NULL + 唯一索引(对齐模型 unique=True, index=True)
    with op.batch_alter_table('user', schema=None) as batch_op:
        batch_op.alter_column('username', existing_type=sa.String(length=11), nullable=False)
        batch_op.create_index('ix_user_username', ['username'], unique=True)


def downgrade() -> None:
    with op.batch_alter_table('user', schema=None) as batch_op:
        batch_op.drop_index('ix_user_username')
        batch_op.drop_column('username')
