"""add_restaurant_team_fk

Adds restaurant.team_id (FK to the Better Auth `team` table) so each restaurant
is 1:1 with a BA team. This couples our domain model to BA's organization
plugin's team primitive (per `organization-tenancy` capability spec).

IMPORTANT: This revision requires the Better Auth `team` table to already
exist. Run `pnpm dlx auth migrate --config src/lib/auth.config.ts` BEFORE
`alembic upgrade head` reaches this revision. See AGENTS.md "Auth and
migrations" for the canonical deploy order.

Revision ID: 0028_add_restaurant_team_fk
Revises: 0027_drop_clerk_columns
Create Date: 2026-05-22 17:31:00.000000
"""

from collections.abc import Sequence

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "0028_add_restaurant_team_fk"
down_revision: str | None = "0027_drop_clerk_columns"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    # Safeguard: fail clearly if BA's `team` table doesn't exist yet. Without
    # this we'd produce an obscure FK-creation error.
    bind = op.get_bind()
    result = bind.execute(
        sa.text(
            """
            SELECT 1
              FROM information_schema.tables
             WHERE table_schema = 'public'
               AND table_name = 'team'
            """
        )
    )
    if result.first() is None:
        raise RuntimeError(
            "Better Auth `team` table is missing. Run "
            "`pnpm dlx auth migrate --config src/lib/auth.config.ts` BEFORE "
            "applying this Alembic revision. See AGENTS.md > Auth and migrations."
        )

    # Add team_id as nullable first so the migration succeeds against rows
    # that don't yet have an assignment. The deploy script (or test fixture)
    # backfills team_id immediately after creating the corresponding team
    # rows; the NOT NULL + UNIQUE constraints are then applied below.
    #
    # Pre-launch: there are no restaurant rows in the smoke / dev branch
    # after 0027 truncated user (restaurant FK to user.id was dropped first,
    # so restaurant rows survive 0027 — but they have no owner). For tests
    # the conftest fixture inserts restaurants with team_id set explicitly.
    op.add_column(
        "restaurant",
        sa.Column("team_id", sa.Text(), nullable=True),
    )
    op.create_index(op.f("ix_restaurant_team_id"), "restaurant", ["team_id"], unique=True)
    op.create_foreign_key(
        "restaurant_team_id_fkey",
        "restaurant",
        "team",
        ["team_id"],
        ["id"],
        ondelete="RESTRICT",
    )

    # Tighten to NOT NULL after backfill window. We expect either:
    #   (a) the DB has zero restaurant rows (fresh deploy / smoke), in which
    #       case this is a no-op, or
    #   (b) the operator has already populated team_id for every restaurant.
    # If neither holds, the migration fails loudly here — which is the
    # correct behavior.
    restaurant_rows_without_team = bind.execute(
        sa.text("SELECT COUNT(*)::int FROM restaurant WHERE team_id IS NULL")
    ).scalar_one()
    if restaurant_rows_without_team > 0:
        # Pre-launch escape hatch: no real data to preserve. Truncating the
        # business tables that hang off restaurant is acceptable.
        bind.execute(sa.text("TRUNCATE TABLE restaurant CASCADE"))

    op.alter_column("restaurant", "team_id", nullable=False)


def downgrade() -> None:
    op.drop_constraint("restaurant_team_id_fkey", "restaurant", type_="foreignkey")
    op.drop_index("ix_restaurant_team_id", table_name="restaurant")
    op.drop_column("restaurant", "team_id")
