"""Email + password authentication strategy."""

from __future__ import annotations

from typing import Any, Generic

from aura_auth._core.exceptions import UserInactiveError
from aura_auth._core.protocols import BackendProtocol, UserProtocol
from aura_auth._core.schemas import UserCreate
from aura_auth._core.security import PasswordHelper, TokenHelper
from aura_auth._core.types import ID
from aura_auth.strategies.base import BaseStrategy


class PasswordStrategy(BaseStrategy[ID], Generic[ID]):
    """Authenticate users with bcrypt-hashed passwords."""

    def __init__(self, password_helper: PasswordHelper, token_helper: TokenHelper) -> None:
        self._password_helper = password_helper
        self._token_helper = token_helper

    async def authenticate(
        self,
        credentials: dict[str, Any],
        backend: BackendProtocol[ID],
    ) -> UserProtocol[ID] | None:
        """Authenticate with email + password. Returns user or None."""
        email = credentials.get("email")
        password = credentials.get("password")
        if not isinstance(email, str) or not isinstance(password, str):
            return None
        user = await backend.get_by_email(email)
        if user is None or user.hashed_password is None:
            return None
        if not self._password_helper.verify(password, user.hashed_password):
            return None
        if not user.is_active:
            raise UserInactiveError("User is inactive")
        return user

    async def register(self, data: UserCreate, backend: BackendProtocol[ID]) -> UserProtocol[ID]:
        """Create a new user with a hashed password."""
        hashed = self._password_helper.hash(data.password)
        user = await backend.create(
            {
                "email": str(data.email),
                "hashed_password": hashed,
            },
        )
        await self.on_after_register(user)
        return user
