"""
Extended tests for model consolidation - Comprehensive model architecture validation.

Tests cover:
- All model imports from consolidated location
- Model relationships and foreign keys
- Column definitions and types
- Model constraints and indexes
- Enum definitions
- Cross-model consistency
"""

from sqlalchemy import inspect


class TestModelImports:
    """Tests for model imports from consolidated location."""

    def test_base_model_importable(self):
        """Base model should be importable."""
        from local_deep_research.database.models import Base

        assert Base is not None

    def test_user_model_importable(self):
        """User model should be importable."""
        from local_deep_research.database.models import User

        assert User is not None

    def test_research_history_importable(self):
        """ResearchHistory model should be importable."""
        from local_deep_research.database.models import ResearchHistory

        assert ResearchHistory is not None

    def test_research_resource_importable(self):
        """ResearchResource model should be importable."""
        from local_deep_research.database.models import ResearchResource

        assert ResearchResource is not None

    def test_benchmark_models_importable(self):
        """Benchmark models should be importable."""
        from local_deep_research.database.models import (
            BenchmarkRun,
            BenchmarkResult,
            BenchmarkProgress,
        )

        assert BenchmarkRun is not None
        assert BenchmarkResult is not None
        assert BenchmarkProgress is not None

    def test_metrics_models_importable(self):
        """Metrics models should be importable."""
        from local_deep_research.database.models import TokenUsage

        assert TokenUsage is not None

    def test_news_models_importable(self):
        """News models should be importable."""
        from local_deep_research.database.models import NewsSubscription

        assert NewsSubscription is not None

    def test_library_models_importable(self):
        """Library models should be importable."""
        from local_deep_research.database.models import (
            Document,
            Collection,
            DocumentChunk,
        )

        assert Document is not None
        assert Collection is not None
        assert DocumentChunk is not None


class TestModelRelationships:
    """Tests for model relationships."""

    def test_benchmark_run_has_results_relationship(self):
        """BenchmarkRun should have results relationship."""
        from local_deep_research.database.models import BenchmarkRun

        assert hasattr(BenchmarkRun, "results")

    def test_benchmark_run_has_progress_relationship(self):
        """BenchmarkRun should have progress_updates relationship."""
        from local_deep_research.database.models import BenchmarkRun

        assert hasattr(BenchmarkRun, "progress_updates")

    def test_benchmark_result_has_run_relationship(self):
        """BenchmarkResult should have benchmark_run relationship."""
        from local_deep_research.database.models import BenchmarkResult

        assert hasattr(BenchmarkResult, "benchmark_run")

    def test_document_has_collections_relationship(self):
        """Document should have collections relationship."""
        from local_deep_research.database.models import Document

        assert hasattr(Document, "collections")

    def test_collection_has_documents_relationship(self):
        """Collection should have document_links relationship."""
        from local_deep_research.database.models import Collection

        assert hasattr(Collection, "document_links")


class TestColumnDefinitions:
    """Tests for model column definitions."""

    def test_research_history_has_query_column(self):
        """ResearchHistory should have query column."""
        from local_deep_research.database.models import ResearchHistory

        assert hasattr(ResearchHistory, "query")

    def test_research_history_has_status_column(self):
        """ResearchHistory should have status column."""
        from local_deep_research.database.models import ResearchHistory

        assert hasattr(ResearchHistory, "status")

    def test_research_history_has_research_meta_column(self):
        """ResearchHistory should have research_meta (renamed from metadata)."""
        from local_deep_research.database.models import ResearchHistory

        assert hasattr(ResearchHistory, "research_meta")

    def test_research_resource_has_title_column(self):
        """ResearchResource should have title column."""
        from local_deep_research.database.models import ResearchResource

        assert hasattr(ResearchResource, "title")

    def test_research_resource_has_url_column(self):
        """ResearchResource should have url column."""
        from local_deep_research.database.models import ResearchResource

        assert hasattr(ResearchResource, "url")

    def test_research_resource_has_resource_metadata_column(self):
        """ResearchResource should have resource_metadata (renamed from metadata)."""
        from local_deep_research.database.models import ResearchResource

        assert hasattr(ResearchResource, "resource_metadata")

    def test_document_has_required_columns(self):
        """Document should have all required columns."""
        from local_deep_research.database.models import Document

        required_columns = [
            "id",
            "document_hash",
            "file_size",
            "file_type",
            "status",
            "created_at",
        ]
        for col in required_columns:
            assert hasattr(Document, col), f"Document missing column: {col}"

    def test_collection_has_required_columns(self):
        """Collection should have all required columns."""
        from local_deep_research.database.models import Collection

        required_columns = ["id", "name", "is_default", "created_at"]
        for col in required_columns:
            assert hasattr(Collection, col), f"Collection missing column: {col}"


class TestEnumDefinitions:
    """Tests for enum definitions."""

    def test_document_status_enum_exists(self):
        """DocumentStatus enum should exist."""
        from local_deep_research.database.models.library import DocumentStatus

        assert DocumentStatus is not None

    def test_document_status_has_expected_values(self):
        """DocumentStatus should have expected values."""
        from local_deep_research.database.models.library import DocumentStatus

        assert DocumentStatus.PENDING.value == "pending"
        assert DocumentStatus.PROCESSING.value == "processing"
        assert DocumentStatus.COMPLETED.value == "completed"
        assert DocumentStatus.FAILED.value == "failed"

    def test_rag_index_status_enum_exists(self):
        """RAGIndexStatus enum should exist."""
        from local_deep_research.database.models.library import RAGIndexStatus

        assert RAGIndexStatus is not None

    def test_embedding_provider_enum_exists(self):
        """EmbeddingProvider enum should exist."""
        from local_deep_research.database.models.library import (
            EmbeddingProvider,
        )

        assert EmbeddingProvider is not None
        assert (
            EmbeddingProvider.SENTENCE_TRANSFORMERS.value
            == "sentence_transformers"
        )
        assert EmbeddingProvider.OLLAMA.value == "ollama"
        # Issue #3883 — OPENAI covers the cloud API and any
        # OpenAI-compatible endpoint (LM Studio, vLLM, llama.cpp).
        assert EmbeddingProvider.OPENAI.value == "openai"

    def test_embedding_provider_openai_constructible_from_string(self):
        """EmbeddingProvider("openai") should resolve to the OPENAI member.

        The library RAG service stores the provider as a string and
        later persists it via ``EmbeddingProvider(value)``; the
        round-trip is the column-write path that issue #3883's
        acceptance criteria #1 calls out.
        """
        from local_deep_research.database.models.library import (
            EmbeddingProvider,
        )

        assert EmbeddingProvider("openai") is EmbeddingProvider.OPENAI


class TestTableNames:
    """Tests for correct table names."""

    def test_document_table_name(self):
        """Document should have correct table name."""
        from local_deep_research.database.models import Document

        assert Document.__tablename__ == "documents"

    def test_collection_table_name(self):
        """Collection should have correct table name."""
        from local_deep_research.database.models import Collection

        assert Collection.__tablename__ == "collections"

    def test_document_chunk_table_name(self):
        """DocumentChunk should have correct table name."""
        from local_deep_research.database.models import DocumentChunk

        assert DocumentChunk.__tablename__ == "document_chunks"

    def test_rag_index_table_name(self):
        """RAGIndex should have correct table name."""
        from local_deep_research.database.models import RAGIndex

        assert RAGIndex.__tablename__ == "rag_indices"


class TestModelConstraints:
    """Tests for model constraints."""

    def test_document_has_unique_hash_constraint(self):
        """Document should have unique document_hash constraint."""
        from local_deep_research.database.models import Document

        mapper = inspect(Document)
        columns = {c.name: c for c in mapper.columns}
        assert columns["document_hash"].unique is True

    def test_collection_document_has_unique_constraint(self):
        """DocumentCollection should have unique document-collection pair."""
        from local_deep_research.database.models import DocumentCollection

        # Check table args for unique constraint
        table_args = DocumentCollection.__table_args__
        has_unique = any(
            hasattr(arg, "name") and "uix_document_collection" in str(arg.name)
            for arg in table_args
            if hasattr(arg, "name")
        )
        assert has_unique


class TestIndexDefinitions:
    """Tests for index definitions."""

    def test_document_has_source_type_index(self):
        """Document should have source_type index."""
        from local_deep_research.database.models import Document

        table_args = Document.__table_args__
        has_index = any(
            hasattr(arg, "name") and "idx_source_type" in str(arg.name)
            for arg in table_args
            if hasattr(arg, "name")
        )
        assert has_index

    def test_document_chunk_has_collection_index(self):
        """DocumentChunk should have collection index."""
        from local_deep_research.database.models import DocumentChunk

        table_args = DocumentChunk.__table_args__
        has_index = any(
            hasattr(arg, "name") and "idx_chunk_collection" in str(arg.name)
            for arg in table_args
            if hasattr(arg, "name")
        )
        assert has_index


class TestCrossModelConsistency:
    """Tests for cross-model consistency."""

    def test_document_references_source_type(self):
        """Document.source_type_id should reference source_types."""
        from local_deep_research.database.models import Document

        mapper = inspect(Document)
        columns = {c.name: c for c in mapper.columns}
        fk = list(columns["source_type_id"].foreign_keys)[0]
        assert "source_types" in str(fk.target_fullname)

    def test_document_collection_references_both(self):
        """DocumentCollection should reference both Document and Collection."""
        from local_deep_research.database.models import DocumentCollection

        mapper = inspect(DocumentCollection)
        columns = {c.name: c for c in mapper.columns}

        doc_fk = list(columns["document_id"].foreign_keys)[0]
        coll_fk = list(columns["collection_id"].foreign_keys)[0]

        assert "documents" in str(doc_fk.target_fullname)
        assert "collections" in str(coll_fk.target_fullname)


class TestModelRepr:
    """Tests for model __repr__ methods."""

    def test_document_repr_not_error(self):
        """Document __repr__ should not raise errors."""
        from local_deep_research.database.models import Document

        doc = Document()
        doc.id = "test-id"
        doc.title = "Test Document"
        doc.file_type = "pdf"
        doc.file_size = 1024

        # Should not raise
        repr_str = repr(doc)
        assert "Document" in repr_str

    def test_collection_repr_not_error(self):
        """Collection __repr__ should not raise errors."""
        from local_deep_research.database.models import Collection

        coll = Collection()
        coll.id = "test-id"
        coll.name = "Test Collection"
        coll.collection_type = "user_collection"

        repr_str = repr(coll)
        assert "Collection" in repr_str


class TestModelDefaults:
    """Tests for model default values."""

    def test_document_status_default(self):
        """Document status should default to COMPLETED."""
        from local_deep_research.database.models import Document

        mapper = inspect(Document)
        columns = {c.name: c for c in mapper.columns}
        default = columns["status"].default

        assert default is not None

    def test_collection_is_default_defaults_to_false(self):
        """Collection.is_default should default to False."""
        from local_deep_research.database.models import Collection

        mapper = inspect(Collection)
        columns = {c.name: c for c in mapper.columns}
        default = columns["is_default"].default

        assert default is not None
        assert default.arg is False


class TestNullableColumns:
    """Tests for nullable column settings."""

    def test_document_id_not_nullable(self):
        """Document.id should not be nullable."""
        from local_deep_research.database.models import Document

        mapper = inspect(Document)
        columns = {c.name: c for c in mapper.columns}
        assert columns["id"].nullable is False

    def test_document_hash_not_nullable(self):
        """Document.document_hash should not be nullable."""
        from local_deep_research.database.models import Document

        mapper = inspect(Document)
        columns = {c.name: c for c in mapper.columns}
        assert columns["document_hash"].nullable is False

    def test_document_original_url_nullable(self):
        """Document.original_url should be nullable (for uploads)."""
        from local_deep_research.database.models import Document

        mapper = inspect(Document)
        columns = {c.name: c for c in mapper.columns}
        assert columns["original_url"].nullable is True


class TestExtractionEnums:
    """Tests for extraction-related enums."""

    def test_extraction_method_enum(self):
        """ExtractionMethod enum should have expected values."""
        from local_deep_research.database.models.library import ExtractionMethod

        assert ExtractionMethod.PDF_EXTRACTION.value == "pdf_extraction"
        assert ExtractionMethod.NATIVE_API.value == "native_api"
        assert ExtractionMethod.UNKNOWN.value == "unknown"

    def test_extraction_source_enum(self):
        """ExtractionSource enum should have expected values."""
        from local_deep_research.database.models.library import ExtractionSource

        assert ExtractionSource.ARXIV_API.value == "arxiv_api"
        assert ExtractionSource.PUBMED_API.value == "pubmed_api"
        assert ExtractionSource.PDFPLUMBER.value == "pdfplumber"

    def test_extraction_quality_enum(self):
        """ExtractionQuality enum should have expected values."""
        from local_deep_research.database.models.library import (
            ExtractionQuality,
        )

        assert ExtractionQuality.HIGH.value == "high"
        assert ExtractionQuality.MEDIUM.value == "medium"
        assert ExtractionQuality.LOW.value == "low"


class TestRAGEnums:
    """Tests for RAG-related enums."""

    def test_distance_metric_enum(self):
        """DistanceMetric enum should have expected values."""
        from local_deep_research.database.models.library import DistanceMetric

        assert DistanceMetric.COSINE.value == "cosine"
        assert DistanceMetric.L2.value == "l2"
        assert DistanceMetric.DOT_PRODUCT.value == "dot_product"

    def test_index_type_enum(self):
        """IndexType enum should have expected values."""
        from local_deep_research.database.models.library import IndexType

        assert IndexType.FLAT.value == "flat"
        assert IndexType.HNSW.value == "hnsw"
        assert IndexType.IVF.value == "ivf"

    def test_splitter_type_enum(self):
        """SplitterType enum should have expected values."""
        from local_deep_research.database.models.library import SplitterType

        assert SplitterType.RECURSIVE.value == "recursive"
        assert SplitterType.SEMANTIC.value == "semantic"
        assert SplitterType.TOKEN.value == "token"
        assert SplitterType.SENTENCE.value == "sentence"


class TestPDFStorageMode:
    """Tests for PDF storage mode enum."""

    def test_pdf_storage_mode_enum(self):
        """PDFStorageMode enum should have expected values."""
        from local_deep_research.database.models.library import PDFStorageMode

        assert PDFStorageMode.NONE.value == "none"
        assert PDFStorageMode.FILESYSTEM.value == "filesystem"
        assert PDFStorageMode.DATABASE.value == "database"
