#!/usr/bin/env python3
"""
Integration tests for ChromaDB and Weaviate upload functionality.

Tests real upload capabilities for vector databases.
"""

import json
import pytest

# Import adaptors
from skill_seekers.cli.adaptors import get_adaptor


@pytest.fixture
def sample_chroma_package(tmp_path):
    """Create a sample ChromaDB package for testing."""
    package_data = {
        "collection_name": "test_collection",
        "documents": ["Test doc 1", "Test doc 2", "Test doc 3"],
        "metadatas": [
            {"source": "test", "category": "overview", "file": "SKILL.md"},
            {"source": "test", "category": "api", "file": "API.md"},
            {"source": "test", "category": "guide", "file": "GUIDE.md"},
        ],
        "ids": ["id1", "id2", "id3"],
    }

    package_path = tmp_path / "test-chroma.json"
    package_path.write_text(json.dumps(package_data))
    return package_path


@pytest.fixture
def sample_weaviate_package(tmp_path):
    """Create a sample Weaviate package for testing."""
    package_data = {
        "class_name": "TestSkill",
        "schema": {
            "class": "TestSkill",
            "description": "Test skill documentation",
            "vectorizer": "none",
            "properties": [
                {"name": "content", "dataType": ["text"]},
                {"name": "source", "dataType": ["string"]},
                {"name": "category", "dataType": ["string"]},
            ],
        },
        "objects": [
            {
                "id": "00000000-0000-0000-0000-000000000001",
                "properties": {
                    "content": "Test content 1",
                    "source": "test",
                    "category": "overview",
                },
            },
            {
                "id": "00000000-0000-0000-0000-000000000002",
                "properties": {"content": "Test content 2", "source": "test", "category": "api"},
            },
        ],
    }

    package_path = tmp_path / "test-weaviate.json"
    package_path.write_text(json.dumps(package_data))
    return package_path


class TestChromaUploadBasics:
    """Test ChromaDB upload basic functionality."""

    def test_chroma_adaptor_exists(self):
        """Test that ChromaDB adaptor can be loaded."""
        adaptor = get_adaptor("chroma")
        assert adaptor is not None
        assert adaptor.PLATFORM == "chroma"

    def test_chroma_upload_without_chromadb_installed(self, sample_chroma_package):
        """Test upload fails gracefully without chromadb installed."""
        adaptor = get_adaptor("chroma")

        # Temporarily remove chromadb if it exists
        import sys

        chromadb_backup = sys.modules.get("chromadb")
        if "chromadb" in sys.modules:
            del sys.modules["chromadb"]

        try:
            result = adaptor.upload(sample_chroma_package)

            assert result["success"] is False
            # ImportError → "not installed"; other import-time errors (e.g.
            # pydantic ConfigError on Python 3.14) → "failed to import"
            assert (
                "chromadb not installed. Run: pip install chromadb" in result["message"]
                or "chromadb failed to import" in result["message"]
            )
        finally:
            if chromadb_backup:
                sys.modules["chromadb"] = chromadb_backup

    def test_chroma_upload_api_signature(self, sample_chroma_package):
        """Test ChromaDB upload has correct API signature."""
        adaptor = get_adaptor("chroma")

        # Verify upload method exists and accepts kwargs
        assert hasattr(adaptor, "upload")
        assert callable(adaptor.upload)

        # Verify adaptor methods exist
        assert hasattr(adaptor, "_generate_openai_embeddings")


class TestWeaviateUploadBasics:
    """Test Weaviate upload basic functionality."""

    def test_weaviate_adaptor_exists(self):
        """Test that Weaviate adaptor can be loaded."""
        adaptor = get_adaptor("weaviate")
        assert adaptor is not None
        assert adaptor.PLATFORM == "weaviate"

    def test_weaviate_upload_without_weaviate_installed(self, sample_weaviate_package):
        """Test upload fails gracefully without weaviate-client installed."""
        adaptor = get_adaptor("weaviate")

        # Temporarily remove weaviate if it exists
        import sys

        weaviate_backup = sys.modules.get("weaviate")
        if "weaviate" in sys.modules:
            del sys.modules["weaviate"]

        try:
            result = adaptor.upload(sample_weaviate_package)

            assert result["success"] is False
            assert "weaviate-client not installed" in result["message"]
            assert "pip install weaviate-client" in result["message"]
        finally:
            if weaviate_backup:
                sys.modules["weaviate"] = weaviate_backup

    def test_weaviate_upload_api_signature(self, sample_weaviate_package):
        """Test Weaviate upload has correct API signature."""
        adaptor = get_adaptor("weaviate")

        # Verify upload method exists and accepts kwargs
        assert hasattr(adaptor, "upload")
        assert callable(adaptor.upload)

        # Verify adaptor methods exist
        assert hasattr(adaptor, "_generate_openai_embeddings")


class TestEmbeddingMethodInheritance:
    """Test that shared embedding methods are properly inherited from base."""

    def test_chroma_inherits_openai_embeddings(self):
        """Test chroma adaptor gets _generate_openai_embeddings from base."""
        adaptor = get_adaptor("chroma")
        assert hasattr(adaptor, "_generate_openai_embeddings")
        # Verify it's the base class method, not a local override
        from skill_seekers.cli.adaptors.base import SkillAdaptor

        assert (
            adaptor._generate_openai_embeddings.__func__ is SkillAdaptor._generate_openai_embeddings
        )

    def test_weaviate_inherits_both_embedding_methods(self):
        """Test weaviate adaptor gets both embedding methods from base."""
        adaptor = get_adaptor("weaviate")
        assert hasattr(adaptor, "_generate_openai_embeddings")
        assert hasattr(adaptor, "_generate_st_embeddings")
        from skill_seekers.cli.adaptors.base import SkillAdaptor

        assert (
            adaptor._generate_openai_embeddings.__func__ is SkillAdaptor._generate_openai_embeddings
        )
        assert adaptor._generate_st_embeddings.__func__ is SkillAdaptor._generate_st_embeddings

    def test_pinecone_inherits_both_embedding_methods(self):
        """Test pinecone adaptor gets both embedding methods from base."""
        adaptor = get_adaptor("pinecone")
        assert hasattr(adaptor, "_generate_openai_embeddings")
        assert hasattr(adaptor, "_generate_st_embeddings")
        from skill_seekers.cli.adaptors.base import SkillAdaptor

        assert (
            adaptor._generate_openai_embeddings.__func__ is SkillAdaptor._generate_openai_embeddings
        )
        assert adaptor._generate_st_embeddings.__func__ is SkillAdaptor._generate_st_embeddings


class TestPackageStructure:
    """Test that packages are correctly structured for upload."""

    def test_chroma_package_structure(self, sample_chroma_package):
        """Test ChromaDB package has required fields."""
        with open(sample_chroma_package) as f:
            data = json.load(f)

        assert "collection_name" in data
        assert "documents" in data
        assert "metadatas" in data
        assert "ids" in data
        assert len(data["documents"]) == len(data["metadatas"]) == len(data["ids"])

    def test_weaviate_package_structure(self, sample_weaviate_package):
        """Test Weaviate package has required fields."""
        with open(sample_weaviate_package) as f:
            data = json.load(f)

        assert "class_name" in data
        assert "schema" in data
        assert "objects" in data
        assert len(data["objects"]) == 2

        # Verify schema structure
        assert "class" in data["schema"]
        assert "properties" in data["schema"]

        # Verify object structure
        for obj in data["objects"]:
            assert "id" in obj
            assert "properties" in obj


class TestUploadCommandIntegration:
    """Test upload command integration."""

    def test_upload_skill_api_signature(self):
        """Test upload_skill_api has correct signature."""
        from skill_seekers.cli.upload_skill import upload_skill_api

        # Verify function exists
        assert callable(upload_skill_api)

        # Verify it accepts kwargs for vector DBs
        import inspect

        sig = inspect.signature(upload_skill_api)
        params = list(sig.parameters.keys())
        assert "package_path" in params
        assert "target" in params
        assert "api_key" in params
        assert "kwargs" in params  # For platform-specific options

    def test_upload_command_supports_chroma(self):
        """Test upload command recognizes chroma as target."""

        # This should not raise ValueError
        adaptor = get_adaptor("chroma")
        assert adaptor is not None

    def test_upload_command_supports_weaviate(self):
        """Test upload command recognizes weaviate as target."""

        # This should not raise ValueError
        adaptor = get_adaptor("weaviate")
        assert adaptor is not None


class TestErrorHandling:
    """Test error handling in upload functionality."""

    def test_chroma_handles_missing_file(self, tmp_path):
        """Test ChromaDB upload handles missing files gracefully."""
        adaptor = get_adaptor("chroma")

        missing_file = tmp_path / "nonexistent.json"

        # Should raise FileNotFoundError or return error dict
        try:
            result = adaptor.upload(missing_file)
            # If it returns a dict, it should indicate failure
            assert result["success"] is False
        except FileNotFoundError:
            # This is also acceptable
            pass

    def test_weaviate_handles_missing_file(self, tmp_path):
        """Test Weaviate upload handles missing files gracefully."""
        adaptor = get_adaptor("weaviate")

        missing_file = tmp_path / "nonexistent.json"

        # Should raise FileNotFoundError or return error dict
        try:
            result = adaptor.upload(missing_file)
            # If it returns a dict, it should indicate failure
            assert result["success"] is False
        except FileNotFoundError:
            # This is also acceptable
            pass

    def test_chroma_handles_invalid_json(self, tmp_path):
        """Test ChromaDB upload handles invalid JSON gracefully."""
        adaptor = get_adaptor("chroma")

        invalid_file = tmp_path / "invalid.json"
        invalid_file.write_text("not valid json{")

        # Should raise JSONDecodeError or return error dict
        try:
            result = adaptor.upload(invalid_file)
            # If it returns a dict, it should indicate failure
            assert result["success"] is False
        except json.JSONDecodeError:
            # This is also acceptable
            pass

    def test_weaviate_handles_invalid_json(self, tmp_path):
        """Test Weaviate upload handles invalid JSON gracefully."""
        adaptor = get_adaptor("weaviate")

        invalid_file = tmp_path / "invalid.json"
        invalid_file.write_text("not valid json{")

        # Should raise JSONDecodeError or return error dict
        try:
            result = adaptor.upload(invalid_file)
            # If it returns a dict, it should indicate failure
            assert result["success"] is False
        except json.JSONDecodeError:
            # This is also acceptable
            pass
