"""Authentication service — credential validation and password management."""
from __future__ import annotations

from sqlalchemy.orm import Session

from app.auth import hash_password, verify_password
from app.domain.errors import BusinessRuleViolation, PermissionViolation
from app.models.user import User

_DUMMY_HASH = "$2b$12$LJ3m4ys3Lg3dMO/NpNmOaeVwFpWJMxlB2FLmEAo9fZr.S8H1vC4Wy"


def authenticate_user(db: Session, *, username: str, password: str) -> User:
    """Validate credentials and return the User.

    Raises BusinessRuleViolation for invalid credentials.
    Raises PermissionViolation for disabled account.
    Uses constant-time comparison to prevent timing attacks.
    """
    user = db.query(User).filter(User.username == username).first()
    hashed = user.hashed_password if user else _DUMMY_HASH
    password_valid = verify_password(password, hashed)

    if user is None or not password_valid:
        raise BusinessRuleViolation("Incorrect username or password")
    if not user.is_active:
        raise PermissionViolation("Account is disabled. Contact an administrator.")
    return user


def change_password(
    db: Session,
    user: User,
    *,
    current_password: str,
    new_password: str,
) -> None:
    """Change a user's password. Does NOT commit.

    Raises BusinessRuleViolation if current password is wrong.
    """
    if not verify_password(current_password, user.hashed_password):
        raise BusinessRuleViolation("Current password is incorrect")
    if verify_password(new_password, user.hashed_password):
        raise BusinessRuleViolation(
            "New password must be different from the current password"
        )
    user.hashed_password = hash_password(new_password)
    user.must_change_password = False
