"""3.0.3
整理历史按源存储与源路径唯一

Revision ID: 7f5c1d2e3a4b
Revises: 8a4c7e1d2f90
Create Date: 2026-08-04
"""

from collections import defaultdict

from alembic import op
import sqlalchemy as sa


revision = "7f5c1d2e3a4b"
down_revision = "8a4c7e1d2f90"
branch_labels = None
depends_on = None

TABLE_NAME = "transferhistory"
INDEX_NAME = "ux_transferhistory_src_storage"
INDEX_COLUMNS = ["src", "src_storage"]

transferhistory = sa.table(
    TABLE_NAME,
    sa.column("id", sa.Integer()),
    sa.column("src", sa.String()),
    sa.column("src_storage", sa.String()),
    sa.column("status", sa.Boolean()),
)


def _table_exists(inspector: sa.Inspector) -> bool:
    """检查整理历史表是否存在。"""
    return TABLE_NAME in inspector.get_table_names()


def _has_unique_index(inspector: sa.Inspector) -> bool:
    """检查源路径与源存储的唯一索引是否已存在。"""
    return any(
        tuple(index.get("column_names") or []) == tuple(INDEX_COLUMNS)
        and bool(index.get("unique"))
        for index in inspector.get_indexes(TABLE_NAME)
    )


def _deduplicate_rows() -> None:
    """归一化旧存储值并按现有查重语义清理重复历史。"""
    bind = op.get_bind()
    bind.execute(
        transferhistory.update()
        .where(
            sa.or_(
                transferhistory.c.src_storage.is_(None),
                transferhistory.c.src_storage == "",
            )
        )
        .values(src_storage="local")
    )

    rows = bind.execute(
        sa.select(
            transferhistory.c.id,
            transferhistory.c.src,
            transferhistory.c.src_storage,
            transferhistory.c.status,
        ).where(transferhistory.c.src.is_not(None))
    ).mappings()
    grouped_rows = defaultdict(list)
    for row in rows:
        grouped_rows[(row["src"], row["src_storage"])].append(row)

    duplicate_ids = []
    for group in grouped_rows.values():
        # 旧运行时在同源混有成功和失败记录时优先返回成功记录；保留其中 ID 最新的一条，
        # 既延续这一保护语义，也让唯一索引能安全建立。
        retained = max(
            group,
            key=lambda row: (bool(row["status"]), row["id"]),
        )
        duplicate_ids.extend(
            row["id"]
            for row in group
            if row["id"] != retained["id"]
        )
    if duplicate_ids:
        bind.execute(
            transferhistory.delete().where(transferhistory.c.id.in_(duplicate_ids))
        )


def _make_src_storage_required(inspector: sa.Inspector) -> None:
    """将源存储设为非空，使唯一索引同样约束本地存储记录。"""
    column = next(
        (
            current
            for current in inspector.get_columns(TABLE_NAME)
            if current["name"] == "src_storage"
        ),
        None,
    )
    if not column or not column.get("nullable"):
        return
    with op.batch_alter_table(TABLE_NAME) as batch_op:
        batch_op.alter_column(
            "src_storage",
            existing_type=sa.String(),
            nullable=False,
            server_default="local",
        )


def upgrade() -> None:
    """归一化并唯一化整理历史的源路径记录。"""
    inspector = sa.inspect(op.get_bind())
    if not _table_exists(inspector):
        return

    _deduplicate_rows()
    _make_src_storage_required(sa.inspect(op.get_bind()))

    inspector = sa.inspect(op.get_bind())
    if not _has_unique_index(inspector):
        op.create_index(INDEX_NAME, TABLE_NAME, INDEX_COLUMNS, unique=True)


def downgrade() -> None:
    """移除整理历史源路径唯一约束。"""
    inspector = sa.inspect(op.get_bind())
    if not _table_exists(inspector):
        return

    if _has_unique_index(inspector):
        op.drop_index(INDEX_NAME, table_name=TABLE_NAME)
    with op.batch_alter_table(TABLE_NAME) as batch_op:
        batch_op.alter_column(
            "src_storage",
            existing_type=sa.String(),
            nullable=True,
            server_default=None,
        )
