import pytest
from unittest.mock import MagicMock
from bson import ObjectId
from datetime import datetime
from app.repositories.user_repository import UserRepository
from app.models.entities import UserEntity


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


@pytest.fixture
def user_repository(mock_db):
    return UserRepository(db=mock_db)


def test_get_all_users(user_repository):
    mock_users = [
        {
            "_id": ObjectId(),
            "email": "a@example.com",
            "name": "A",
            "password": "pass1",
            "locale": "id-ID",
        },
        {
            "_id": ObjectId(),
            "email": "b@example.com",
            "name": "B",
            "password": "pass2",
            "locale": "id-ID",
        },
    ]
    user_repository.collection.find.return_value = mock_users

    result = user_repository.get_all_users()

    assert len(result) == 2
    assert all(isinstance(user, UserEntity) for user in result)
    assert result[0].email == "a@example.com"
    assert result[1].name == "B"


def test_get_user_by_email_found(user_repository):
    mock_user = {
        "_id": ObjectId(),
        "email": "john@example.com",
        "name": "John Doe",
        "password": "hashed",
        "birth_date": datetime(2000, 1, 1),
        "locale": "en-US",
        "phone": "08123456789",
    }
    user_repository.collection.find_one.return_value = mock_user

    result = user_repository.get_user_by_email("john@example.com")

    assert isinstance(result, UserEntity)
    assert result.email == "john@example.com"
    assert result.name == "John Doe"


def test_get_user_by_email_not_found(user_repository):
    user_repository.collection.find_one.return_value = None

    result = user_repository.get_user_by_email("notfound@example.com")

    assert result is None


def test_get_user_by_id_found(user_repository):
    user_id = ObjectId()
    mock_user = {
        "_id": user_id,
        "email": "jane@example.com",
        "name": "Jane",
        "password": "hashed",
        "birth_date": datetime(1990, 1, 1),
        "locale": "en-US",
        "phone": "089999999",
    }
    user_repository.collection.find_one.return_value = mock_user

    result = user_repository.get_user_by_id(str(user_id))

    assert isinstance(result, UserEntity)
    assert str(result.id) == str(user_id)
    assert result.name == "Jane"


def test_get_by_google_id_found(user_repository):
    mock_user = {
        "_id": ObjectId(),
        "google_id": "google-123",
        "email": "google@example.com",
        "name": "Google User",
        "locale": "en-US",
    }
    user_repository.collection.find_one.return_value = mock_user

    result = user_repository.get_by_google_id("google-123")

    assert isinstance(result, UserEntity)
    assert result.google_id == "google-123"
    assert result.email == "google@example.com"


def test_insert_user(user_repository):
    user_entity = UserEntity(
        name="Test",
        email="test@example.com",
        password="123",
        birth_date=datetime(2000, 1, 1),
        phone="081111111",
        locale="id-ID",
    )
    mock_insert_result = MagicMock(inserted_id=ObjectId())
    user_repository.collection.insert_one.return_value = mock_insert_result

    result = user_repository.insert_user(user_entity)

    user_repository.collection.insert_one.assert_called_once()
    assert isinstance(result, str)


def test_update_user(user_repository):
    user_id = str(ObjectId())
    mock_result = MagicMock(modified_count=1)
    user_repository.collection.update_one.return_value = mock_result

    result = user_repository.update_user(user_id, {"name": "Updated Name"})

    assert result is True


def test_update_user_field(user_repository):
    user_id = str(ObjectId())
    mock_result = MagicMock(modified_count=1)
    user_repository.collection.update_one.return_value = mock_result

    result = user_repository.update_user_field(user_id, "phone", "0822334455")

    assert result is True


def test_delete_user(user_repository):
    user_id = str(ObjectId())
    mock_result = MagicMock(deleted_count=1)
    user_repository.collection.delete_one.return_value = mock_result

    result = user_repository.delete_user(user_id)

    assert result is True
