"""Tests for bridge base classes."""

import pytest

from freecad_mcp.bridge.base import (
    DocumentInfo,
    ExecutionResult,
    FreecadBridge,
    ObjectInfo,
)


class TestExecutionResult:
    """Tests for ExecutionResult dataclass."""

    def test_successful_result(self):
        """Successful execution result should have correct attributes."""
        result = ExecutionResult(
            success=True,
            result={"value": 42},
            stdout="output",
            stderr="",
            execution_time_ms=10.5,
        )

        assert result.success is True
        assert result.result == {"value": 42}
        assert result.stdout == "output"
        assert result.stderr == ""
        assert result.execution_time_ms == 10.5
        assert result.error_type is None
        assert result.error_traceback is None

    def test_failed_result(self):
        """Failed execution result should include error details."""
        result = ExecutionResult(
            success=False,
            result=None,
            stdout="",
            stderr="error occurred",
            execution_time_ms=5.0,
            error_type="ValueError",
            error_traceback="Traceback...",
        )

        assert result.success is False
        assert result.result is None
        assert result.error_type == "ValueError"
        assert result.error_traceback == "Traceback..."


class TestDocumentInfo:
    """Tests for DocumentInfo dataclass."""

    def test_document_with_all_fields(self):
        """DocumentInfo should store all fields correctly."""
        doc = DocumentInfo(
            name="TestDoc",
            path="/path/to/doc.FCStd",
            objects=["Box", "Cylinder"],
            is_modified=True,
            label="Test Document",
        )

        assert doc.name == "TestDoc"
        assert doc.path == "/path/to/doc.FCStd"
        assert doc.objects == ["Box", "Cylinder"]
        assert doc.is_modified is True
        assert doc.label == "Test Document"

    def test_document_with_defaults(self):
        """DocumentInfo should use sensible defaults."""
        doc = DocumentInfo(name="Doc", path=None)

        assert doc.name == "Doc"
        assert doc.path is None
        assert doc.objects == []
        assert doc.is_modified is False
        assert doc.label == "Doc"  # Label defaults to name


class TestObjectInfo:
    """Tests for ObjectInfo dataclass."""

    def test_object_with_shape(self):
        """ObjectInfo should store shape information correctly."""
        obj = ObjectInfo(
            name="Box",
            label="My Box",
            type_id="Part::Box",
            properties={"Length": 10.0},
            shape_info={"type": "Solid", "volume": 1000.0},
            children=["Child1"],
        )

        assert obj.name == "Box"
        assert obj.label == "My Box"
        assert obj.type_id == "Part::Box"
        assert obj.properties == {"Length": 10.0}
        assert obj.shape_info == {"type": "Solid", "volume": 1000.0}
        assert obj.children == ["Child1"]

    def test_object_with_defaults(self):
        """ObjectInfo should use sensible defaults."""
        obj = ObjectInfo(name="Obj", label="Obj", type_id="Part::Feature")

        assert obj.properties == {}
        assert obj.shape_info is None
        assert obj.children == []


class TestFreecadBridgeInterface:
    """Tests for FreecadBridge abstract interface."""

    def test_cannot_instantiate_abstract_class(self):
        """FreecadBridge should not be instantiable directly."""
        with pytest.raises(TypeError):
            FreecadBridge()  # type: ignore[abstract]

    def test_subclass_must_implement_methods(self):
        """Subclass must implement all abstract methods."""

        class IncompleteBridge(FreecadBridge):
            pass

        with pytest.raises(TypeError):
            IncompleteBridge()  # type: ignore[abstract]
