import pytest
from unittest.mock import MagicMock
from app.services.subject_service import SubjectService
from app.schemas.requests import SubjectCreateRequest, SubjectUpdateRequest
from app.models.entities import SubjectEntity
from app.schemas.response import GetSubjectResponse


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


@pytest.fixture
def subject_service(mock_subject_repository):
    return SubjectService(repository=mock_subject_repository)


def test_create_subject(subject_service, mock_subject_repository):
    request = SubjectCreateRequest(
        name="Fisika", short_name="FIS", description="Pelajaran fisika"
    )
    mock_subject_repository.create.return_value = "subject123"

    result = subject_service.create_subject(request)

    mock_subject_repository.create.assert_called_once()
    assert result == "subject123"


def test_get_all_subjects(subject_service, mock_subject_repository):
    mock_subject_repository.get_all.return_value = [
        SubjectEntity(
            id="1",
            name="Biologi",
            short_name="BIO",
            description="Ilmu tentang makhluk hidup",
        )
    ]

    results = subject_service.get_all_subjects()

    assert len(results) == 1
    assert isinstance(results[0], GetSubjectResponse)
    assert results[0].name == "Biologi"
    assert results[0].alias == "BIO"
    assert results[0].description == "Ilmu tentang makhluk hidup"


def test_get_subject_by_id_found(subject_service, mock_subject_repository):
    mock_subject_repository.get_by_id.return_value = SubjectEntity(
        id="2", name="Matematika", short_name="MTK", description="Ilmu hitung"
    )

    result = subject_service.get_subject_by_id("2")

    assert result is not None
    assert result.name == "Matematika"
    assert result.alias == "MTK"


def test_get_subject_by_id_not_found(subject_service, mock_subject_repository):
    mock_subject_repository.get_by_id.return_value = None

    result = subject_service.get_subject_by_id("999")

    assert result is None


def test_update_subject(subject_service, mock_subject_repository):
    request = SubjectUpdateRequest(name="Sejarah")
    mock_subject_repository.update.return_value = True

    result = subject_service.update_subject("3", request)

    mock_subject_repository.update.assert_called_once_with("3", {"name": "Sejarah"})
    assert result is True


def test_delete_subject(subject_service, mock_subject_repository):
    mock_subject_repository.delete.return_value = True

    result = subject_service.delete_subject("4")

    mock_subject_repository.delete.assert_called_once_with("4")
    assert result is True
