# tests/unit/services/test_auth_service.py
"""Unit tests for AuthService - login and password hashing."""

import pytest

from app.modules.core.services.auth_service import AuthService
from app.modules.tenancy.exceptions import (
    InvalidCredentialsException,
    UserNotActiveException,
)
from app.modules.tenancy.schemas.auth import UserLogin


@pytest.mark.unit
@pytest.mark.auth
class TestAuthService:
    """Test suite for AuthService."""

    def setup_method(self):
        """Setup method."""
        self.service = AuthService()

    def test_login_user_success(self, db, test_user):
        """Test successful user login."""
        user_credentials = UserLogin(
            email_or_username=test_user.username, password="testpass123"  # noqa: SEC001
        )

        result = self.service.login_user(db, user_credentials)

        assert "token_data" in result
        assert "user" in result
        assert result["user"].id == test_user.id
        assert result["user"].username == test_user.username
        assert "access_token" in result["token_data"]
        assert "token_type" in result["token_data"]
        assert "expires_in" in result["token_data"]

    def test_login_user_with_email(self, db, test_user):
        """Test login with email instead of username."""
        user_credentials = UserLogin(
            email_or_username=test_user.email, password="testpass123"  # noqa: SEC001
        )

        result = self.service.login_user(db, user_credentials)

        assert result["user"].id == test_user.id
        assert "access_token" in result["token_data"]

    def test_login_user_wrong_username(self, db):
        """Test login fails with wrong username."""
        user_credentials = UserLogin(
            email_or_username="nonexistentuser", password="testpass123"  # noqa: SEC001
        )

        with pytest.raises(InvalidCredentialsException) as exc_info:
            self.service.login_user(db, user_credentials)

        exception = exc_info.value
        assert exception.error_code == "INVALID_CREDENTIALS"
        assert exception.status_code == 401
        assert "Incorrect username or password" in exception.message

    def test_login_user_wrong_password(self, db, test_user):
        """Test login fails with wrong password."""
        user_credentials = UserLogin(
            email_or_username=test_user.username, password="wrongpassword"  # noqa: SEC001
        )

        with pytest.raises(InvalidCredentialsException) as exc_info:
            self.service.login_user(db, user_credentials)

        exception = exc_info.value
        assert exception.error_code == "INVALID_CREDENTIALS"
        assert exception.status_code == 401
        assert "Incorrect username or password" in exception.message

    def test_login_user_inactive_user(self, db, test_user):
        """Test login fails for inactive user."""
        from app.modules.tenancy.models import User

        # Re-query user and deactivate
        user = db.query(User).filter(User.id == test_user.id).first()
        user.is_active = False
        db.commit()

        user_credentials = UserLogin(
            email_or_username=test_user.username, password="testpass123"  # noqa: SEC001
        )

        with pytest.raises(UserNotActiveException) as exc_info:
            self.service.login_user(db, user_credentials)

        exception = exc_info.value
        assert exception.error_code == "USER_NOT_ACTIVE"
        assert exception.status_code == 403
        assert "User account is not active" in exception.message

        # Reactivate for cleanup
        user.is_active = True
        db.commit()

    def test_hash_password(self):
        """Test password hashing."""
        password = "testpassword123"  # noqa: SEC001
        hashed = self.service.hash_password(password)

        assert hashed != password
        assert len(hashed) > len(password)
        assert hashed.startswith("$")  # bcrypt hash format

    def test_hash_password_different_results(self):
        """Test that hashing same password produces different hashes (salt)."""
        password = "testpassword123"  # noqa: SEC001
        hash1 = self.service.hash_password(password)
        hash2 = self.service.hash_password(password)

        assert hash1 != hash2  # Should be different due to salt

    def test_get_store_by_code_not_found(self, db):
        """Test getting store by non-existent code returns None."""
        store = self.service.get_store_by_code(db, "NONEXISTENT")

        assert store is None
