"""
Unit tests for artifact repository.

Tests SQLiteArtifactRepository implementation.
"""

import pytest
import tempfile
from pathlib import Path

from markitect.prompts.models import Artifact, ArtifactType, ArtifactMetadata
from markitect.prompts.repositories.sqlite import SQLiteArtifactRepository
from markitect.prompts.repositories.interfaces import (
    ArtifactNotFoundError,
    DuplicateArtifactError,
)


@pytest.fixture
def temp_db():
    """Create temporary database for testing."""
    with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
        db_path = f.name
    yield db_path
    # Cleanup
    Path(db_path).unlink(missing_ok=True)


@pytest.fixture
def repository(temp_db):
    """Create repository instance with temp database."""
    return SQLiteArtifactRepository(temp_db)


@pytest.fixture
def sample_artifact():
    """Create sample artifact for testing."""
    return Artifact.create(
        space_id="test-space",
        name="test-artifact",
        content="# Test Content\n\nThis is test content.",
        artifact_type=ArtifactType.CONTENT,
    )


class TestSQLiteArtifactRepository:
    """Tests for SQLiteArtifactRepository."""

    def test_create_artifact(self, repository, sample_artifact):
        """Test creating an artifact."""
        created = repository.create(sample_artifact)

        assert created.id == sample_artifact.id
        assert created.space_id == sample_artifact.space_id
        assert created.name == sample_artifact.name
        assert created.content_digest == sample_artifact.content_digest

    def test_create_duplicate_artifact_raises_error(self, repository, sample_artifact):
        """Test creating duplicate artifact raises error."""
        repository.create(sample_artifact)

        # Try to create another artifact with same space_id and name
        duplicate = Artifact.create(
            space_id="test-space",
            name="test-artifact",
            content="Different content",
        )

        with pytest.raises(DuplicateArtifactError, match="already exists"):
            repository.create(duplicate)

    def test_get_by_id(self, repository, sample_artifact):
        """Test retrieving artifact by ID."""
        repository.create(sample_artifact)

        retrieved = repository.get_by_id(sample_artifact.id)

        assert retrieved is not None
        assert retrieved.id == sample_artifact.id
        assert retrieved.name == sample_artifact.name
        assert retrieved.content_digest == sample_artifact.content_digest

    def test_get_by_id_not_found(self, repository):
        """Test get_by_id returns None for non-existent ID."""
        result = repository.get_by_id("non-existent-id")
        assert result is None

    def test_get_by_name(self, repository, sample_artifact):
        """Test retrieving artifact by space and name."""
        repository.create(sample_artifact)

        retrieved = repository.get_by_name("test-space", "test-artifact")

        assert retrieved is not None
        assert retrieved.id == sample_artifact.id
        assert retrieved.space_id == "test-space"
        assert retrieved.name == "test-artifact"

    def test_get_by_name_not_found(self, repository):
        """Test get_by_name returns None when not found."""
        result = repository.get_by_name("test-space", "non-existent")
        assert result is None

    def test_get_by_digest(self, repository):
        """Test finding artifacts by content digest."""
        content = "Shared content"
        artifact1 = Artifact.create(
            space_id="space-1",
            name="artifact-1",
            content=content,
        )
        artifact2 = Artifact.create(
            space_id="space-2",
            name="artifact-2",
            content=content,  # Same content, same digest
        )

        repository.create(artifact1)
        repository.create(artifact2)

        results = repository.get_by_digest(artifact1.content_digest)

        assert len(results) == 2
        names = {a.name for a in results}
        assert names == {"artifact-1", "artifact-2"}

    def test_list_by_space(self, repository):
        """Test listing artifacts in a space."""
        artifacts = [
            Artifact.create(
                space_id="space-1",
                name=f"artifact-{i}",
                content=f"Content {i}",
            )
            for i in range(3)
        ]

        for artifact in artifacts:
            repository.create(artifact)

        # Add artifact in different space
        other = Artifact.create(
            space_id="space-2",
            name="other",
            content="Other content",
        )
        repository.create(other)

        results = repository.list_by_space("space-1")

        assert len(results) == 3
        assert all(a.space_id == "space-1" for a in results)
        # Should be ordered by name
        assert [a.name for a in results] == ["artifact-0", "artifact-1", "artifact-2"]

    def test_list_by_space_with_type_filter(self, repository):
        """Test listing artifacts filtered by type."""
        artifacts = [
            Artifact.create(
                space_id="space-1",
                name="content-1",
                content="Content",
                artifact_type=ArtifactType.CONTENT,
            ),
            Artifact.create(
                space_id="space-1",
                name="template-1",
                content="Template",
                artifact_type=ArtifactType.TEMPLATE,
            ),
            Artifact.create(
                space_id="space-1",
                name="content-2",
                content="Content 2",
                artifact_type=ArtifactType.CONTENT,
            ),
        ]

        for artifact in artifacts:
            repository.create(artifact)

        results = repository.list_by_space("space-1", ArtifactType.CONTENT)

        assert len(results) == 2
        assert all(a.artifact_type == ArtifactType.CONTENT for a in results)

    def test_update_artifact(self, repository, sample_artifact):
        """Test updating artifact."""
        repository.create(sample_artifact)

        # Update content
        sample_artifact.update_content("New content")
        updated = repository.update(sample_artifact)

        # Retrieve and verify
        retrieved = repository.get_by_id(sample_artifact.id)
        assert retrieved.content_digest == updated.content_digest
        assert retrieved.updated_at >= updated.updated_at

    def test_update_nonexistent_artifact_raises_error(self, repository):
        """Test updating non-existent artifact raises error."""
        artifact = Artifact.create(
            space_id="test-space",
            name="test",
            content="content",
        )

        with pytest.raises(ArtifactNotFoundError, match="not found"):
            repository.update(artifact)

    def test_delete_artifact(self, repository, sample_artifact):
        """Test deleting artifact."""
        repository.create(sample_artifact)

        result = repository.delete(sample_artifact.id)
        assert result is True

        # Verify deleted
        retrieved = repository.get_by_id(sample_artifact.id)
        assert retrieved is None

    def test_delete_nonexistent_artifact(self, repository):
        """Test deleting non-existent artifact returns False."""
        result = repository.delete("non-existent-id")
        assert result is False

    def test_exists(self, repository, sample_artifact):
        """Test checking if artifact exists."""
        assert not repository.exists("test-space", "test-artifact")

        repository.create(sample_artifact)

        assert repository.exists("test-space", "test-artifact")
        assert not repository.exists("test-space", "other-artifact")
        assert not repository.exists("other-space", "test-artifact")

    def test_artifact_metadata_persistence(self, repository):
        """Test metadata is persisted correctly."""
        metadata = ArtifactMetadata(
            description="Test description",
            tags=["tag1", "tag2"],
            author="test-author",
            version="1.0.0",
            custom={"key": "value"},
        )

        artifact = Artifact.create(
            space_id="test-space",
            name="test",
            content="content",
            metadata=metadata,
        )

        repository.create(artifact)
        retrieved = repository.get_by_id(artifact.id)

        assert retrieved.metadata.description == "Test description"
        assert retrieved.metadata.tags == ["tag1", "tag2"]
        assert retrieved.metadata.author == "test-author"
        assert retrieved.metadata.version == "1.0.0"
        assert retrieved.metadata.custom == {"key": "value"}

    def test_content_round_trip(self, repository):
        """Test that artifact content survives store and retrieve."""
        original_content = "# Test Content\n\nThis is the full content."
        artifact = Artifact.create(
            space_id="test-space",
            name="content-test",
            content=original_content,
        )

        repository.create(artifact)
        retrieved = repository.get_by_id(artifact.id)

        assert retrieved.content == original_content

    def test_content_persisted_after_update(self, repository):
        """Test that updated content is persisted."""
        artifact = Artifact.create(
            space_id="test-space",
            name="update-test",
            content="Original content",
        )
        repository.create(artifact)

        artifact.update_content("Updated content")
        repository.update(artifact)

        retrieved = repository.get_by_id(artifact.id)
        assert retrieved.content == "Updated content"
