"""user.discord_only — mark accounts whose only credential is Discord

"Sign in with Discord" (notifications/discord_link.py) creates accounts for people
who never chose a password. ``hashed_password`` is NOT NULL, so those rows carry a
generated one nobody has ever seen; without a flag there is no way to tell such an
account apart from a password account that merely linked Discord later. That
distinction is load-bearing: unlinking Discord from a Discord-only account would
delete its only way in, and no reset-password router is mounted to recover it.

Conditional on purpose. Revision 0001 builds the schema with
``Base.metadata.create_all``, which reads the *current* models.py — so a database
created after this column was added to the ORM already has it, and an
unconditional ``add_column`` would fail there with a duplicate-column error. Only
a database stamped before this revision is missing it.

Revision ID: 0003_user_discord_only
Revises: 0002_climate_hypertables
Create Date: 2026-07-26
"""
import sqlalchemy as sa
from alembic import op

revision = "0003_user_discord_only"
down_revision = "0002_climate_hypertables"
branch_labels = None
depends_on = None


def _has_column() -> bool:
    cols = sa.inspect(op.get_bind()).get_columns("user")
    return any(c["name"] == "discord_only" for c in cols)


def upgrade() -> None:
    if _has_column():
        return
    # server_default (not just a Python-side default) so the backfill of existing
    # rows happens in the same statement: every account that predates Discord
    # login has a password, so False is correct for all of them.
    op.add_column(
        "user",
        sa.Column("discord_only", sa.Boolean(), nullable=False,
                  server_default=sa.false()),
    )


def downgrade() -> None:
    if not _has_column():
        return
    op.drop_column("user", "discord_only")
