"""Local auth provider — argon2id passwords, user management."""
from __future__ import annotations
from pathlib import Path
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
from .base import User
from . import db as user_db
from .db import _connect, _VALID_ROLES

_ph = PasswordHasher()


class LocalAuthProvider:
    def __init__(self, db_path: Path) -> None:
        self.db_path = db_path

    def register(self, *, username: str, email: str, password: str, role: str = "user") -> User:
        password_hash = _ph.hash(password)
        return user_db.create_user(
            self.db_path, username=username, email=email,
            password_hash=password_hash, role=role, auth_provider="local",
        )

    def authenticate(self, *, email: str, password: str) -> User | None:
        conn = _connect(self.db_path)
        try:
            row = conn.execute(
                "SELECT a.id, u.username, a.email, u.role, a.auth_provider, a.password_hash "
                "FROM auth a JOIN users u ON a.id = u.id "
                "WHERE a.email = ? AND a.active = 1 AND a.auth_provider = 'local'",
                (email,),
            ).fetchone()
        finally:
            conn.close()
        if not row:
            return None
        *user_fields, password_hash = row
        if not password_hash:
            return None
        try:
            _ph.verify(password_hash, password)
        except VerifyMismatchError:
            return None
        return User(*user_fields)

    def update_password(self, user_id: str, new_password: str) -> None:
        password_hash = _ph.hash(new_password)
        conn = _connect(self.db_path)
        try:
            conn.execute("UPDATE auth SET password_hash = ? WHERE id = ?", (password_hash, user_id))
            conn.commit()
        finally:
            conn.close()

    def set_role(self, user_id: str, role: str) -> None:
        if role not in _VALID_ROLES:
            raise ValueError(f"Invalid role: {role!r}. Must be one of: {', '.join(sorted(_VALID_ROLES))}")
        conn = _connect(self.db_path)
        try:
            conn.execute("UPDATE users SET role = ? WHERE id = ?", (role, user_id))
            conn.commit()
        finally:
            conn.close()

    def revoke_all_sessions(self, user_id: str) -> None:
        conn = _connect(self.db_path)
        try:
            conn.execute(
                "UPDATE refresh_tokens SET revoked = 1 WHERE user_id = ? AND revoked = 0",
                (user_id,),
            )
            conn.commit()
        finally:
            conn.close()
