"""add account_id to content tables and backfill from _team_account_mapping

Revision ID: 019
Revises: 018
Create Date: 2026-02-07

Uses the _team_account_mapping table from migration 018 for deterministic
FK backfill instead of non-deterministic LIMIT 1 subqueries.
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID


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

# Tables that have team_id and need account_id
CONTENT_TABLES = ['trees', 'step_library', 'tree_categories', 'tree_tags', 'step_categories']


def upgrade() -> None:
    conn = op.get_bind()

    for table in CONTENT_TABLES:
        # Add account_id column
        op.add_column(table, sa.Column('account_id', UUID(as_uuid=True), nullable=True))
        op.create_index(f'ix_{table}_account_id', table, ['account_id'])

        # Backfill from mapping table (deterministic)
        conn.execute(sa.text(f"""
            UPDATE {table} SET account_id = m.account_id
            FROM _team_account_mapping m
            WHERE {table}.team_id = m.team_id
        """))

        # Validate: no rows with team_id but missing account_id
        orphaned = conn.execute(sa.text(f"""
            SELECT COUNT(*) FROM {table}
            WHERE team_id IS NOT NULL AND account_id IS NULL
        """)).scalar()
        if orphaned > 0:
            raise RuntimeError(
                f"Migration 019 failed: {table} has {orphaned} rows with team_id but no account_id"
            )


def downgrade() -> None:
    for table in reversed(CONTENT_TABLES):
        op.drop_index(f'ix_{table}_account_id', table_name=table)
        op.drop_column(table, 'account_id')
