import pytest
from unittest.mock import MagicMock
from bson import ObjectId
from datetime import datetime
from app.repositories import SessionRepository
from app.models.entities import SessionEntity


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


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


def generate_session_entity() -> SessionEntity:
    return SessionEntity(
        session_code="ABC123",
        quiz_id="quiz1",
        host_id="user1",
        created_at=datetime.now(),
        started_at=None,
        ended_at=None,
        is_active=True,
        participan_limit=5,
        participants=["user1"],
        current_question_index=0,
    )


def test_insert_session(repository):
    session = generate_session_entity()
    insert_result = MagicMock(inserted_id=ObjectId())
    repository.collection.insert_one.return_value = insert_result

    result = repository.insert(session)

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


def test_find_by_session_id_found(repository):
    session = generate_session_entity()
    doc = session.model_dump(by_alias=True)
    repository.collection.find_one.return_value = doc

    result = repository.find_by_session_id(session_id=doc["_id"])

    assert isinstance(result, SessionEntity)
    assert result.session_code == "ABC123"


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

    result = repository.find_by_session_id("nonexistent_id")

    assert result is None


def test_find_by_session_code_found(repository):
    session = generate_session_entity()
    doc = session.model_dump(by_alias=True)
    repository.collection.find_one.return_value = doc

    result = repository.find_by_session_code("ABC123")

    assert isinstance(result, SessionEntity)
    assert result.quiz_id == "quiz1"


def test_update_session(repository):
    repository.collection.update_one.return_value = MagicMock(modified_count=1)

    update_data = {"is_active": False}
    result = repository.update("session123", update_data)

    repository.collection.update_one.assert_called_once_with(
        {"_id": "session123"}, {"$set": update_data}
    )
    assert result is True


def test_add_participant(repository):
    repository.collection.update_one.return_value = MagicMock(modified_count=1)

    result = repository.add_participant("session123", "user999")

    repository.collection.update_one.assert_called_once_with(
        {"_id": "session123"}, {"$addToSet": {"participants": "user999"}}
    )
    assert result is True


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

    result = repository.delete("session123")

    repository.collection.delete_one.assert_called_once_with({"_id": "session123"})
    assert result is True


def test_list_active_sessions(repository):
    doc = generate_session_entity().model_dump(by_alias=True)
    repository.collection.find.return_value = [doc]

    result = repository.list_active_sessions()

    repository.collection.find.assert_called_once_with({"is_active": True})
    assert len(result) == 1
    assert isinstance(result[0], SessionEntity)
    assert result[0].is_active is True
