# app/modules/tenancy/tests/unit/test_user_auth_service.py
"""Unit tests for UserAuthService."""

import uuid

import pytest

from app.modules.tenancy.exceptions import InvalidTokenException
from app.modules.tenancy.models import User
from app.modules.tenancy.models.email_verification_token import EmailVerificationToken
from app.modules.tenancy.models.user_password_reset_token import UserPasswordResetToken
from app.modules.tenancy.services.user_auth_service import UserAuthService


@pytest.mark.unit
@pytest.mark.database
class TestUserAuthServicePasswordReset:
    """Test UserAuthService password reset methods."""

    @pytest.fixture
    def service(self):
        return UserAuthService()

    @pytest.fixture
    def uas_user(self, db):
        """Create a test user."""
        from middleware.auth import AuthManager

        auth = AuthManager()
        uid = uuid.uuid4().hex[:8]
        user = User(
            email=f"uas_{uid}@test.com",
            username=f"uas_{uid}",
            hashed_password=auth.hash_password("oldpass123"),  # noqa: SEC001
            role="merchant_owner",
            is_active=True,
            is_email_verified=True,
        )
        db.add(user)
        db.commit()
        db.refresh(user)
        return user

    @pytest.fixture
    def uas_inactive_user(self, db):
        """Create an inactive test user."""
        from middleware.auth import AuthManager

        auth = AuthManager()
        uid = uuid.uuid4().hex[:8]
        user = User(
            email=f"uasi_{uid}@test.com",
            username=f"uasi_{uid}",
            hashed_password=auth.hash_password("inactive123"),  # noqa: SEC001
            role="merchant_owner",
            is_active=False,
            is_email_verified=True,
        )
        db.add(user)
        db.commit()
        db.refresh(user)
        return user

    def test_request_password_reset_success(self, service, db, uas_user):
        """Valid active user gets a reset token."""
        user, token = service.request_password_reset(db, uas_user.email)
        assert user is not None
        assert user.id == uas_user.id
        assert token is not None
        assert len(token) > 20

    def test_request_password_reset_nonexistent_email(self, service, db):
        """Non-existent email returns (None, None)."""
        user, token = service.request_password_reset(db, "nonexistent@test.com")
        assert user is None
        assert token is None

    def test_request_password_reset_inactive_user(self, service, db, uas_inactive_user):
        """Inactive user returns (None, None)."""
        user, token = service.request_password_reset(db, uas_inactive_user.email)
        assert user is None
        assert token is None

    def test_reset_password_success(self, service, db, uas_user):
        """Valid token resets password."""
        plaintext = UserPasswordResetToken.create_for_user(db, uas_user.id)
        db.commit()

        user = service.reset_password(db, plaintext, "newpass456")  # noqa: SEC001
        db.commit()

        assert user.id == uas_user.id
        # Verify the password was actually changed
        from middleware.auth import AuthManager
        auth = AuthManager()
        assert auth.verify_password("newpass456", user.hashed_password)  # noqa: SEC001

    def test_reset_password_invalid_token(self, service, db):
        """Invalid token raises InvalidTokenException."""
        with pytest.raises(InvalidTokenException):
            service.reset_password(db, "invalid-token", "newpass456")  # noqa: SEC001


@pytest.mark.unit
@pytest.mark.database
class TestUserAuthServiceEmailVerification:
    """Test UserAuthService email verification methods."""

    @pytest.fixture
    def service(self):
        return UserAuthService()

    @pytest.fixture
    def uas_unverified_user(self, db):
        """Create an unverified test user."""
        uid = uuid.uuid4().hex[:8]
        user = User(
            email=f"uasev_{uid}@test.com",
            username=f"uasev_{uid}",
            hashed_password="hashed_password",  # noqa: SEC001
            role="merchant_owner",
            is_active=True,
            is_email_verified=False,
        )
        db.add(user)
        db.commit()
        db.refresh(user)
        return user

    @pytest.fixture
    def uas_verified_user(self, db):
        """Create a verified test user."""
        uid = uuid.uuid4().hex[:8]
        user = User(
            email=f"uasv_{uid}@test.com",
            username=f"uasv_{uid}",
            hashed_password="hashed_password",  # noqa: SEC001
            role="merchant_owner",
            is_active=True,
            is_email_verified=True,
        )
        db.add(user)
        db.commit()
        db.refresh(user)
        return user

    def test_request_verification_resend_unverified(self, service, db, uas_unverified_user):
        """Unverified user gets a new verification token."""
        user, token = service.request_verification_resend(db, uas_unverified_user.email)
        assert user is not None
        assert user.id == uas_unverified_user.id
        assert token is not None

    def test_request_verification_resend_already_verified(self, service, db, uas_verified_user):
        """Already-verified user returns (None, None)."""
        user, token = service.request_verification_resend(db, uas_verified_user.email)
        assert user is None
        assert token is None

    def test_request_verification_resend_nonexistent(self, service, db):
        """Non-existent email returns (None, None)."""
        user, token = service.request_verification_resend(db, "nonexistent@test.com")
        assert user is None
        assert token is None
