# #region Test.SessionEventLogger [C:2] [TYPE Module] [SEMANTICS test,dataset,event,logger,session,audit]
# @BRIEF Tests for event_logger.py — session event logging and persistence.
# @RELATION BINDS_TO -> [SessionEventLoggerModule]
# @TEST_EDGE: log_event -> Persists event payload correctly
# @TEST_EDGE: log_event_validation -> Empty fields raise ValueError
# @TEST_EDGE: log_event_with_details -> Event details stored
# @TEST_EDGE: log_for_session -> Convenience wrapper from session object

from pathlib import Path
import sys

sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))

from unittest.mock import MagicMock, patch
import pytest


class TestSessionEventPayload:
    """SessionEventPayload — dataclass contract."""

    def test_payload_creation(self):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="user-1",
            event_type="session_started",
            event_summary="Session created",
            current_phase="RECOVERY",
            readiness_state="IMPORTING",
            event_details={"key": "val"},
        )
        assert payload.session_id == "sess-1"
        assert payload.event_type == "session_started"
        assert payload.event_details == {"key": "val"}


class TestSessionEventLoggerLogEvent:
    """SessionEventLogger.log_event — persist event."""

    @pytest.fixture
    def db(self):
        return MagicMock()

    @pytest.fixture
    def logger(self, db):
        from src.services.dataset_review.event_logger import SessionEventLogger
        return SessionEventLogger(db)

    def test_log_event_success(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        # Mock SessionEvent
        mock_event = MagicMock()
        mock_event.session_event_id = "evt-1"
        mock_event.event_type = "session_started"
        db.add.return_value = None
        db.refresh.return_value = None

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="user-1",
            event_type="session_started",
            event_summary="Session created",
            current_phase="RECOVERY",
            readiness_state="IMPORTING",
            event_details={"source": "superset"},
        )

        result = logger.log_event(payload)
        db.add.assert_called_once()
        db.commit.assert_called_once()
        db.refresh.assert_called_once()

    def test_log_event_minimal(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="user-1",
            event_type="update",
            event_summary="Updated",
        )
        result = logger.log_event(payload)
        db.add.assert_called_once()
        db.commit.assert_called_once()

    def test_empty_session_id_raises(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="",
            actor_user_id="user-1",
            event_type="test",
            event_summary="test",
        )
        with pytest.raises(ValueError, match="session_id"):
            logger.log_event(payload)
        db.add.assert_not_called()

    def test_empty_actor_user_id_raises(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="",
            event_type="test",
            event_summary="test",
        )
        with pytest.raises(ValueError, match="actor_user_id"):
            logger.log_event(payload)
        db.add.assert_not_called()

    def test_empty_event_type_raises(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="user-1",
            event_type="",
            event_summary="test",
        )
        with pytest.raises(ValueError, match="event_type"):
            logger.log_event(payload)
        db.add.assert_not_called()

    def test_empty_event_summary_raises(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="user-1",
            event_type="test",
            event_summary="",
        )
        with pytest.raises(ValueError, match="event_summary"):
            logger.log_event(payload)
        db.add.assert_not_called()

    def test_event_with_complex_details(self, logger, db):
        from src.services.dataset_review.event_logger import SessionEventPayload

        payload = SessionEventPayload(
            session_id="sess-1",
            actor_user_id="user-1",
            event_type="mapping_approved",
            event_summary="Mappings approved by assistant",
            event_details={
                "mapping_ids": ["m-1", "m-2"],
                "count": 2,
                "nested": {"key": "value"},
            },
        )
        result = logger.log_event(payload)
        db.add.assert_called_once()
        # Verify the event_details dict
        added = db.add.call_args[0][0]
        assert added.event_details["mapping_ids"] == ["m-1", "m-2"]


class TestSessionEventLoggerLogForSession:
    """SessionEventLogger.log_for_session — convenience wrapper."""

    def test_log_for_session(self):
        from src.services.dataset_review.event_logger import SessionEventLogger, SessionEventPayload
        from src.models.dataset_review import DatasetReviewSession, SessionPhase, ReadinessState

        db = MagicMock()

        session = MagicMock(spec=DatasetReviewSession)
        session.session_id = "sess-1"
        session.current_phase = MagicMock(value="review")
        session.readiness_state = MagicMock(value="review_ready")

        logger = SessionEventLogger(db)

        with patch.object(logger, "log_event") as mock_log:
            mock_log.return_value = MagicMock(session_event_id="evt-1")

            result = logger.log_for_session(
                session,
                actor_user_id="user-1",
                event_type="preview_generated",
                event_summary="Preview ready",
                event_details={"preview_id": "pv-1"},
            )
            mock_log.assert_called_once()
            payload = mock_log.call_args[0][0]
            assert payload.session_id == "sess-1"
            assert payload.event_type == "preview_generated"
            assert payload.current_phase == "review"
            assert payload.readiness_state == "review_ready"

    def test_log_for_session_no_details(self):
        from src.services.dataset_review.event_logger import SessionEventLogger
        from src.models.dataset_review import DatasetReviewSession

        db = MagicMock()
        session = MagicMock(spec=DatasetReviewSession)
        session.session_id = "sess-1"
        session.current_phase = None
        session.readiness_state = None

        logger = SessionEventLogger(db)

        with patch.object(logger, "log_event") as mock_log:
            mock_log.return_value = MagicMock(session_event_id="evt-1")

            logger.log_for_session(
                session,
                actor_user_id="user-1",
                event_type="test",
                event_summary="test",
            )
            payload = mock_log.call_args[0][0]
            assert payload.current_phase is None
            assert payload.readiness_state is None
# #endregion Test.SessionEventLogger
