import pytest
from unittest.mock import MagicMock
from werkzeug.security import check_password_hash
from bson import ObjectId
from app.services.user_service import UserService
from app.schemas import RegisterSchema
from app.exception import AlreadyExistException
from app.models.entities import UserEntity
import datetime


@pytest.fixture
def mock_user_repository():
    return MagicMock()


@pytest.fixture
def user_service(mock_user_repository):
    return UserService(user_repository=mock_user_repository)


def test_register_user_success(user_service, mock_user_repository):
    # Arrange
    register_data = RegisterSchema(
        name="John Doe",
        email="john@example.com",
        password="plainpassword",
        birth_date="01-01-2000",
        phone="08123456789",
    )

    mock_user_repository.get_user_by_email.return_value = None
    mock_user_repository.insert_user.return_value = "new_user_id"

    # Act
    result = user_service.register_user(register_data)

    # Assert
    assert result == "new_user_id"
    assert register_data.password != "plainpassword"  # Ensure password is hashed
    assert check_password_hash(register_data.password, "plainpassword")
    mock_user_repository.insert_user.assert_called_once()


def test_register_user_email_already_exists(user_service, mock_user_repository):
    # Arrange
    register_data = RegisterSchema(
        name="Jane Doe",
        email="jane@example.com",
        password="password123",
        birth_date="12-12-1990",
        phone="08987654321",
    )

    mock_user_repository.get_user_by_email.return_value = UserEntity(
        id=ObjectId(),
        name="Jane Doe",
        email="jane@example.com",
        password="hashedpassword",
        birth_date=datetime.datetime(1990, 12, 12, 0, 0),
        phone="08987654321",
    )

    # Act & Assert
    with pytest.raises(AlreadyExistException) as exc_info:
        user_service.register_user(register_data)

    assert str(exc_info.value) == "Email already exists"
    mock_user_repository.insert_user.assert_not_called()
