from types import SimpleNamespace
from unittest.mock import MagicMock
from uuid import uuid4

from dsg_core.services.data.commandDryrunService import CommandDryrunService
from dsg_core.services.data.dependencies import RefsAndDepsSchema
from dsg_core.services.data.dataCommandProcessor import (
    DataCommandProcessor,
    DataCommandProcessorOutput,
)


def test_data_command_processor_forwards_skip_nested_commands() -> None:
    expected_output = DataCommandProcessorOutput(events=[], projection_events=[])

    class StubHandler:
        def __init__(self, session):
            self.process = MagicMock(return_value=expected_output)

    processor = DataCommandProcessor(handler=StubHandler, session=MagicMock())
    command = MagicMock()
    user_uid = uuid4()

    output = processor.process(
        command,
        user_uid=user_uid,
        skip_nested_commands=True,
    )

    assert output is expected_output
    processor.handler.process.assert_called_once_with(
        command,
        user_uid=user_uid,
        task_id=None,
        validate_only=False,
        skip_nested_commands=True,
    )


def test_dryrun_service_propagates_skip_nested_commands(monkeypatch) -> None:
    processor_calls: list[bool] = []

    class StubProcessor:
        def __init__(self, handler, session):
            self.handler = handler
            self.session = session

        def process(self, command, *, user_uid, skip_nested_commands=False, **kwargs):
            processor_calls.append(skip_nested_commands)
            return DataCommandProcessorOutput(events=[], projection_events=[])

    class StubDryrun:
        def __init__(self) -> None:
            self.graph = None

        def model_dump(self, mode="json"):
            return {
                "events": [],
                "skipEvents": None,
                "validationErrors": None,
                "graph": self.graph,
                "timestamp": None,
            }

    monkeypatch.setattr(
        "dsg_core.services.data.commandDryrunService.DataCommandProcessor",
        StubProcessor,
    )
    monkeypatch.setattr(
        "dsg_core.services.data.commandDryrunService.DependencyService.retrieve_item_references_and_dependencies_from_dryrun",
        lambda *args, **kwargs: RefsAndDepsSchema(references=[], dependencies=[]),
    )
    monkeypatch.setattr(
        "dsg_core.services.data.commandDryrunService.TaskDryrunService.task_dryrun_schema_from_command_output",
        lambda **kwargs: StubDryrun(),
    )
    monkeypatch.setattr(
        "dsg_core.services.data.commandDryrunService.TaskDryrunService.compile_command_dryrun_graph",
        lambda **kwargs: None,
    )

    session = MagicMock()
    response = CommandDryrunService.dryrun_commands(
        payload=[
            {
                "command_uid": uuid4(),
                "item_id": uuid4(),
                "item_type_id": uuid4(),
                "version": "1.0",
                "command_type": "create",
                "data": {},
                "skip_nested_commands": True,
            }
        ],
        user_uid=uuid4(),
        session=session,
    )

    assert processor_calls == [True]
    assert response.skip_nested_commands is True
    session.rollback.assert_called_once_with()
