"""Auto-provisioning: a first-ever BW username gets a ZERO-capability
users row (04-architecture: "a new BW username gets a users row with no
party link and zero capabilities until an owner attaches it").

COLUMN-SCOPED on re-login (kit §5c): only the BW-derived mirror (email)
is refreshed. is_super_admin, person_party_id, and preferences are app-
owned and are NEVER touched by a login — so a grant made between two
logins survives the second one.
"""

import logging
from collections.abc import Mapping

from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

from app.models import User

log = logging.getLogger("with.auth")


def provision_user(db_session: Session, claims: Mapping) -> User:
    """Upsert the users row for a VERIFIED identity (id_token claims from
    bw_auth.verify_id_token — never an unverified source) and return it.
    Commits."""
    username = (claims.get("username") or claims.get("sub") or "").strip()
    if not username:
        raise ValueError("verified claims carry no username")
    email = (claims.get("email") or "").strip()

    user = db_session.scalar(select(User).where(User.idauth_username == username))
    if user is None:
        # Zero capabilities by construction: no party link, not super admin.
        user = User(idauth_username=username, email=email)
        db_session.add(user)
        try:
            db_session.commit()
            log.info("auto-provisioned zero-capability users row for %r", username)
            return user
        except IntegrityError:
            # Concurrent first login for the same username — take the winner's row.
            db_session.rollback()
            user = db_session.scalar(select(User).where(User.idauth_username == username))
            if user is None:  # pragma: no cover — unique race with no row can't happen
                raise

    if email and user.email != email:
        user.email = email  # the ONLY column a re-login may touch
        db_session.commit()
    return user
