# app/modules/tenancy/tests/unit/test_user_account_service.py
"""
Unit tests for UserAccountService.

Tests self-service account operations: get, update, change password.
"""

import uuid

import pytest

from app.modules.tenancy.exceptions import (
    InvalidCredentialsException,
    UserAlreadyExistsException,
    UserNotFoundException,
)
from app.modules.tenancy.models import User
from app.modules.tenancy.services.user_account_service import UserAccountService
from middleware.auth import AuthManager


@pytest.fixture
def auth_mgr():
    return AuthManager()


@pytest.fixture
def account_service():
    return UserAccountService()


@pytest.fixture
def acct_user(db, auth_mgr):
    """Create a user for account service tests."""
    uid = uuid.uuid4().hex[:8]
    user = User(
        email=f"acct_{uid}@test.com",
        username=f"acct_{uid}",
        hashed_password=auth_mgr.hash_password("oldpass123"),
        first_name="Test",
        last_name="User",
        role="super_admin",
        is_active=True,
        is_email_verified=True,
        preferred_language="en",
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return user


@pytest.mark.unit
@pytest.mark.tenancy
class TestUserAccountService:
    """Tests for UserAccountService."""

    def test_get_account_returns_user(self, db, account_service, acct_user):
        result = account_service.get_account(db, acct_user.id)
        assert result.id == acct_user.id
        assert result.email == acct_user.email

    def test_get_account_not_found_raises(self, db, account_service):
        with pytest.raises(UserNotFoundException):
            account_service.get_account(db, 999999)

    def test_update_account_first_last_name(self, db, account_service, acct_user):
        result = account_service.update_account(
            db, acct_user.id, {"first_name": "New", "last_name": "Name"}
        )
        assert result.first_name == "New"
        assert result.last_name == "Name"

    def test_update_account_email_uniqueness_conflict(
        self, db, account_service, acct_user, auth_mgr
    ):
        uid2 = uuid.uuid4().hex[:8]
        other = User(
            email=f"other_{uid2}@test.com",
            username=f"other_{uid2}",
            hashed_password=auth_mgr.hash_password("pass1234"),
            role="store_member",
            is_active=True,
        )
        db.add(other)
        db.commit()

        with pytest.raises(UserAlreadyExistsException):
            account_service.update_account(
                db, acct_user.id, {"email": other.email}
            )

    def test_update_account_preferred_language(self, db, account_service, acct_user):
        result = account_service.update_account(
            db, acct_user.id, {"preferred_language": "fr"}
        )
        assert result.preferred_language == "fr"

    def test_change_password_success(self, db, account_service, acct_user, auth_mgr):
        account_service.change_password(
            db,
            acct_user.id,
            {
                "current_password": "oldpass123",
                "new_password": "newpass456",
                "confirm_password": "newpass456",
            },
        )
        db.refresh(acct_user)
        assert auth_mgr.verify_password("newpass456", acct_user.hashed_password)

    def test_change_password_wrong_current(self, db, account_service, acct_user):
        with pytest.raises(InvalidCredentialsException):
            account_service.change_password(
                db,
                acct_user.id,
                {
                    "current_password": "wrongpass",
                    "new_password": "newpass456",
                    "confirm_password": "newpass456",
                },
            )

    def test_change_password_mismatch_confirm(self, db, account_service, acct_user):
        with pytest.raises(InvalidCredentialsException):
            account_service.change_password(
                db,
                acct_user.id,
                {
                    "current_password": "oldpass123",
                    "new_password": "newpass456",
                    "confirm_password": "different789",
                },
            )

    def test_change_password_same_as_current(self, db, account_service, acct_user):
        with pytest.raises(InvalidCredentialsException):
            account_service.change_password(
                db,
                acct_user.id,
                {
                    "current_password": "oldpass123",
                    "new_password": "oldpass123",
                    "confirm_password": "oldpass123",
                },
            )
