"""
Unit tests for Information Space models.

Tests the core domain models: InformationSpace, SpaceDocument, SpaceConfig, SpaceMetadata.
"""

import pytest
from datetime import datetime
from markitect.spaces.models import (
    InformationSpace,
    SpaceDocument,
    SpaceConfig,
    SpaceMetadata,
    SpaceVariable,
    TransclusionReference,
    SpaceStatus,
)


class TestSpaceMetadata:
    """Tests for SpaceMetadata dataclass."""

    def test_default_metadata(self):
        """Test default metadata values."""
        metadata = SpaceMetadata()
        assert metadata.tags == []
        assert metadata.author is None
        assert metadata.custom == {}

    def test_metadata_with_values(self):
        """Test metadata with custom values."""
        metadata = SpaceMetadata(
            tags=["api", "docs"],
            author="test-user",
            custom={"version": "1.0"}
        )
        assert metadata.tags == ["api", "docs"]
        assert metadata.author == "test-user"
        assert metadata.custom["version"] == "1.0"

    def test_metadata_to_dict(self):
        """Test metadata serialization."""
        metadata = SpaceMetadata(tags=["test"], author="user")
        data = metadata.to_dict()
        assert data["tags"] == ["test"]
        assert data["author"] == "user"

    def test_metadata_from_dict(self):
        """Test metadata deserialization."""
        data = {"tags": ["api"], "author": "admin", "custom": {"key": "value"}}
        metadata = SpaceMetadata.from_dict(data)
        assert metadata.tags == ["api"]
        assert metadata.author == "admin"
        assert metadata.custom["key"] == "value"


class TestSpaceConfig:
    """Tests for SpaceConfig dataclass."""

    def test_default_config(self):
        """Test default configuration values."""
        config = SpaceConfig()
        assert config.default_variant == "hierarchical"
        assert config.enable_caching is True
        assert config.theme is None
        assert config.history_enabled is False
        assert config.history_backend == "git"

    def test_config_with_history_enabled(self):
        """Test config with git history enabled."""
        config = SpaceConfig(history_enabled=True, history_backend="git")
        assert config.history_enabled is True
        assert config.history_backend == "git"

    def test_config_to_dict(self):
        """Test config serialization."""
        config = SpaceConfig(theme="dark", enable_caching=False)
        data = config.to_dict()
        assert data["theme"] == "dark"
        assert data["enable_caching"] is False

    def test_config_from_dict(self):
        """Test config deserialization."""
        data = {"default_variant": "flat", "history_enabled": True}
        config = SpaceConfig.from_dict(data)
        assert config.default_variant == "flat"
        assert config.history_enabled is True


class TestSpaceDocument:
    """Tests for SpaceDocument dataclass."""

    def test_default_document(self):
        """Test default document values."""
        doc = SpaceDocument()
        assert doc.id is not None
        assert doc.space_path == ""
        assert doc.order_index == 0
        assert doc.metadata == {}

    def test_document_with_values(self):
        """Test document with custom values."""
        doc = SpaceDocument(
            space_id="space-1",
            document_id="doc-1",
            space_path="/intro.md",
            order_index=1,
            content_hash="abc123"
        )
        assert doc.space_id == "space-1"
        assert doc.space_path == "/intro.md"
        assert doc.content_hash == "abc123"

    def test_document_to_dict(self):
        """Test document serialization."""
        doc = SpaceDocument(space_path="/test.md")
        data = doc.to_dict()
        assert data["space_path"] == "/test.md"
        assert "id" in data
        assert "added_at" in data

    def test_document_from_dict(self):
        """Test document deserialization."""
        data = {
            "id": "doc-123",
            "space_id": "space-1",
            "space_path": "/api.md",
            "order_index": 5
        }
        doc = SpaceDocument.from_dict(data)
        assert doc.id == "doc-123"
        assert doc.space_path == "/api.md"
        assert doc.order_index == 5


class TestInformationSpace:
    """Tests for InformationSpace dataclass."""

    def test_space_requires_name(self):
        """Test that space name is required."""
        with pytest.raises(ValueError, match="Space name is required"):
            InformationSpace(name="")

    def test_space_default_values(self):
        """Test default space values."""
        space = InformationSpace(name="test-space")
        assert space.name == "test-space"
        assert space.id is not None
        assert space.status == SpaceStatus.DRAFT
        assert space.description is None
        assert space.parent_space_id is None

    def test_space_with_config(self):
        """Test space with custom config."""
        config = SpaceConfig(theme="minimal", history_enabled=True)
        space = InformationSpace(
            name="docs",
            description="Documentation space",
            config=config
        )
        assert space.config.theme == "minimal"
        assert space.config.history_enabled is True

    def test_space_activation(self):
        """Test space lifecycle transitions."""
        space = InformationSpace(name="test")
        assert space.status == SpaceStatus.DRAFT

        space.activate()
        assert space.status == SpaceStatus.ACTIVE

        space.archive()
        assert space.status == SpaceStatus.ARCHIVED

    def test_space_touch_updates_timestamp(self):
        """Test that touch() updates the timestamp."""
        space = InformationSpace(name="test")
        original_updated = space.updated_at

        import time
        time.sleep(0.01)  # Small delay to ensure timestamp changes

        space.touch()
        assert space.updated_at >= original_updated

    def test_space_to_dict(self):
        """Test space serialization."""
        space = InformationSpace(
            name="api-docs",
            description="API Documentation"
        )
        data = space.to_dict()

        assert data["name"] == "api-docs"
        assert data["description"] == "API Documentation"
        assert data["status"] == "draft"
        assert "id" in data
        assert "created_at" in data

    def test_space_from_dict(self):
        """Test space deserialization."""
        data = {
            "id": "space-123",
            "name": "my-space",
            "description": "Test space",
            "status": "active",
            "config": {"history_enabled": True},
            "metadata": {"tags": ["test"]}
        }
        space = InformationSpace.from_dict(data)

        assert space.id == "space-123"
        assert space.name == "my-space"
        assert space.status == SpaceStatus.ACTIVE
        assert space.config.history_enabled is True
        assert space.metadata.tags == ["test"]

    def test_space_roundtrip_serialization(self):
        """Test that to_dict and from_dict are inverse operations."""
        original = InformationSpace(
            name="roundtrip-test",
            description="Testing serialization",
            config=SpaceConfig(theme="dark", history_enabled=True),
            metadata=SpaceMetadata(tags=["test", "roundtrip"])
        )
        original.activate()

        data = original.to_dict()
        restored = InformationSpace.from_dict(data)

        assert restored.name == original.name
        assert restored.description == original.description
        assert restored.status == original.status
        assert restored.config.theme == original.config.theme
        assert restored.metadata.tags == original.metadata.tags


class TestSpaceVariable:
    """Tests for SpaceVariable dataclass."""

    def test_variable_creation(self):
        """Test variable creation."""
        var = SpaceVariable(
            space_id="space-1",
            name="version",
            value="1.0.0"
        )
        assert var.name == "version"
        assert var.value == "1.0.0"
        assert var.scope == "space"

    def test_variable_to_dict(self):
        """Test variable serialization."""
        var = SpaceVariable(
            space_id="space-1",
            name="config",
            value={"key": "value"},
            scope="document"
        )
        data = var.to_dict()
        assert data["name"] == "config"
        assert data["scope"] == "document"


class TestTransclusionReference:
    """Tests for TransclusionReference dataclass."""

    def test_reference_creation(self):
        """Test transclusion reference creation."""
        ref = TransclusionReference(
            source_doc_id="doc-1",
            target_doc_id="doc-2",
            space_id="space-1"
        )
        assert ref.source_doc_id == "doc-1"
        assert ref.target_doc_id == "doc-2"
        assert ref.created_at is not None

    def test_reference_to_dict(self):
        """Test reference serialization."""
        ref = TransclusionReference(
            source_doc_id="a",
            target_doc_id="b",
            space_id="s"
        )
        data = ref.to_dict()
        assert "created_at" in data
        assert data["source_doc_id"] == "a"


class TestSpaceStatus:
    """Tests for SpaceStatus enum."""

    def test_status_values(self):
        """Test status enum values."""
        assert SpaceStatus.DRAFT.value == "draft"
        assert SpaceStatus.ACTIVE.value == "active"
        assert SpaceStatus.ARCHIVED.value == "archived"
        assert SpaceStatus.DELETED.value == "deleted"
