import pytest
from unittest.mock import MagicMock
from bson import ObjectId
from datetime import datetime
from app.repositories import UserAnswerRepository
from app.models import UserAnswerEntity
from app.models.entities import AnswerItemEntity


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


@pytest.fixture
def repository(mock_db):
    return UserAnswerRepository(db=mock_db)


def generate_dummy_answer_entity() -> UserAnswerEntity:
    return UserAnswerEntity(
        session_id="session123",
        quiz_id=str(ObjectId()),
        user_id="user123",
        answered_at=datetime.utcnow(),
        answers=[
            AnswerItemEntity(
                question_index=0, answer="B", is_correct=True, time_spent=10
            )
        ],
        total_score=80,
        total_correct=4,
    )


def test_create(repository):
    dummy_entity = generate_dummy_answer_entity()
    insert_result = MagicMock(inserted_id=ObjectId())
    repository.collection.insert_one.return_value = insert_result

    result = repository.create(dummy_entity)

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


def test_get_by_id_found(repository):
    dummy_entity = generate_dummy_answer_entity()
    data = dummy_entity.model_dump(by_alias=True)
    data["_id"] = ObjectId()

    repository.collection.find_one.return_value = data

    result = repository.get_by_id(str(data["_id"]))

    assert isinstance(result, UserAnswerEntity)
    assert result.user_id == dummy_entity.user_id
    assert result.quiz_id == dummy_entity.quiz_id


def test_get_by_id_not_found(repository):
    repository.collection.find_one.return_value = None

    result = repository.get_by_id(str(ObjectId()))

    assert result is None


def test_get_by_user_and_quiz(repository):
    quiz_id = ObjectId()
    repository.collection.find.return_value = [
        {"_id": ObjectId(), "user_id": "u1", "quiz_id": quiz_id}
    ]

    result = repository.get_by_user_and_quiz("u1", str(quiz_id))

    repository.collection.find.assert_called_once_with(
        {"user_id": "u1", "quiz_id": quiz_id}
    )
    assert isinstance(result, list)


def test_get_by_user(repository):
    dummy_data = [generate_dummy_answer_entity().model_dump(by_alias=True)]
    repository.collection.find.return_value = dummy_data

    result = repository.get_by_user("user123")

    assert isinstance(result, list)
    assert all(isinstance(item, UserAnswerEntity) for item in result)


def test_get_by_session(repository):
    session_id = ObjectId()
    repository.collection.find.return_value = [{"session_id": str(session_id)}]

    result = repository.get_by_session(str(session_id))

    repository.collection.find.assert_called_once_with({"session_id": session_id})
    assert isinstance(result, list)
    assert result[0]["session_id"] == str(session_id)


def test_delete_by_id(repository):
    repository.collection.delete_one.return_value = MagicMock(deleted_count=1)

    result = repository.delete_by_id(str(ObjectId()))

    assert result is True
