"""Tests for ObjectMetadata and StoredObject classes."""

import time

from pydantic import BaseModel

from mosh.metadata import ObjectMetadata, StoredObject


class TestObjectMetadataCreation:
    """Tests for ObjectMetadata creation and defaults."""

    def test_create_with_defaults(self) -> None:
        """Test creating ObjectMetadata with defaults."""
        meta = ObjectMetadata()
        assert meta.id is not None
        assert len(meta.id) == 36  # UUID format
        assert meta.created_at is not None
        assert meta.updated_at is not None
        assert meta.tags == []
        assert meta.type_name == ""

    def test_create_with_custom_values(self) -> None:
        """Test creating ObjectMetadata with custom values."""
        meta = ObjectMetadata(
            id="custom-id",
            tags=["tag1", "tag2"],
            type_name="Person",
        )
        assert meta.id == "custom-id"
        assert meta.tags == ["tag1", "tag2"]
        assert meta.type_name == "Person"


class TestObjectMetadataTags:
    """Tests for ObjectMetadata tag operations."""

    def test_add_tag(self) -> None:
        """Test adding a tag."""
        meta = ObjectMetadata()
        meta.add_tag("important")
        assert "important" in meta.tags

    def test_add_duplicate_tag(self) -> None:
        """Test that duplicate tags are not added."""
        meta = ObjectMetadata(tags=["existing"])
        meta.add_tag("existing")
        assert meta.tags.count("existing") == 1

    def test_remove_tag(self) -> None:
        """Test removing a tag."""
        meta = ObjectMetadata(tags=["to-remove", "keep"])
        result = meta.remove_tag("to-remove")
        assert result is True
        assert "to-remove" not in meta.tags
        assert "keep" in meta.tags

    def test_remove_nonexistent_tag(self) -> None:
        """Test removing a tag that doesn't exist."""
        meta = ObjectMetadata(tags=["existing"])
        result = meta.remove_tag("nonexistent")
        assert result is False
        assert meta.tags == ["existing"]

    def test_has_tag(self) -> None:
        """Test checking for tag presence."""
        meta = ObjectMetadata(tags=["present"])
        assert meta.has_tag("present") is True
        assert meta.has_tag("absent") is False

    def test_has_any_tag(self) -> None:
        """Test checking for any matching tag."""
        meta = ObjectMetadata(tags=["a", "b"])
        assert meta.has_any_tag(["a", "c"]) is True
        assert meta.has_any_tag(["c", "d"]) is False

    def test_has_all_tags(self) -> None:
        """Test checking for all matching tags."""
        meta = ObjectMetadata(tags=["a", "b", "c"])
        assert meta.has_all_tags(["a", "b"]) is True
        assert meta.has_all_tags(["a", "d"]) is False


class TestObjectMetadataTimestamps:
    """Tests for ObjectMetadata timestamp handling."""

    def test_touch_updates_timestamp(self) -> None:
        """Test that touch() updates updated_at."""
        meta = ObjectMetadata()
        original_updated = meta.updated_at
        time.sleep(0.01)  # Small delay to ensure different timestamp
        meta.touch()
        assert meta.updated_at > original_updated


class TestStoredObject:
    """Tests for StoredObject wrapper."""

    def test_create_stored_object(self) -> None:
        """Test creating a StoredObject."""

        class Person(BaseModel):
            name: str
            age: int

        person = Person(name="Alice", age=30)
        meta = ObjectMetadata(id="test-123", type_name="Person")
        stored = StoredObject(metadata=meta, obj=person)

        assert stored.obj.name == "Alice"
        assert stored.obj.age == 30
        assert stored.metadata.id == "test-123"

    def test_convenience_properties(self) -> None:
        """Test StoredObject convenience properties."""

        class Item(BaseModel):
            value: str

        item = Item(value="test")
        meta = ObjectMetadata(
            id="item-1",
            tags=["important"],
            type_name="Item",
        )
        stored = StoredObject(metadata=meta, obj=item)

        assert stored.id == "item-1"
        assert stored.tags == ["important"]
        assert stored.type_name == "Item"
        assert stored.created_at is not None
        assert stored.updated_at is not None
