#!/usr/bin/env python3
"""
Hybrid Search Example for Local Deep Research

This example demonstrates how to combine multiple search sources:
1. Multiple named retrievers for different document types
2. Combining custom retrievers with web search
3. Analyzing and comparing sources from different origins
"""

from typing import List
from langchain_core.retrievers import Document, BaseRetriever
from langchain_community.vectorstores import FAISS
from langchain_ollama import OllamaEmbeddings

from local_deep_research.api import quick_summary, detailed_research
from local_deep_research.api.settings_utils import create_settings_snapshot


class TechnicalDocsRetriever(BaseRetriever):
    """Mock retriever for technical documentation."""

    def get_relevant_documents(self, query: str) -> List[Document]:
        """Return mock technical documents."""
        # In a real scenario, this would search actual technical docs
        return [
            Document(
                page_content=f"Technical specification for {query}: Implementation requires careful consideration of system architecture, performance metrics, and scalability factors.",
                metadata={
                    "source": "tech_docs",
                    "type": "specification",
                    "title": f"Technical Spec: {query}",
                },
            ),
            Document(
                page_content=f"Best practices for {query}: Follow industry standards, implement proper error handling, and ensure comprehensive testing coverage.",
                metadata={
                    "source": "tech_docs",
                    "type": "best_practices",
                    "title": f"Best Practices: {query}",
                },
            ),
        ]

    async def aget_relevant_documents(self, query: str) -> List[Document]:
        """Async version."""
        return self.get_relevant_documents(query)


class BusinessDocsRetriever(BaseRetriever):
    """Mock retriever for business/strategy documents."""

    def get_relevant_documents(self, query: str) -> List[Document]:
        """Return mock business documents."""
        return [
            Document(
                page_content=f"Business implications of {query}: Consider market impact, ROI analysis, and strategic alignment with organizational goals.",
                metadata={
                    "source": "business_docs",
                    "type": "strategy",
                    "title": f"Business Strategy: {query}",
                },
            ),
            Document(
                page_content=f"Cost-benefit analysis for {query}: Initial investment requirements, expected returns, and risk assessment factors.",
                metadata={
                    "source": "business_docs",
                    "type": "analysis",
                    "title": f"Cost Analysis: {query}",
                },
            ),
        ]

    async def aget_relevant_documents(self, query: str) -> List[Document]:
        """Async version."""
        return self.get_relevant_documents(query)


def create_knowledge_base_retriever() -> BaseRetriever:
    """Create a FAISS-based retriever with sample knowledge base documents."""
    documents = [
        Document(
            page_content="Machine learning models require training data, validation strategies, and performance metrics for evaluation.",
            metadata={"source": "ml_knowledge_base", "topic": "ml_basics"},
        ),
        Document(
            page_content="Cloud computing provides scalable infrastructure, reducing capital expenditure and enabling flexible resource allocation.",
            metadata={
                "source": "cloud_knowledge_base",
                "topic": "cloud_benefits",
            },
        ),
        Document(
            page_content="Agile methodology emphasizes iterative development, customer collaboration, and responding to change.",
            metadata={"source": "project_knowledge_base", "topic": "agile"},
        ),
        Document(
            page_content="Data privacy regulations like GDPR require explicit consent, data minimization, and user rights management.",
            metadata={
                "source": "compliance_knowledge_base",
                "topic": "privacy",
            },
        ),
    ]

    # Create embeddings and vector store
    embeddings = OllamaEmbeddings(model="nomic-embed-text")
    vectorstore = FAISS.from_documents(documents, embeddings)
    return vectorstore.as_retriever(search_kwargs={"k": 2})


def demonstrate_multiple_retrievers():
    """Show how to use multiple named retrievers for different document types."""
    print("=" * 70)
    print("MULTIPLE NAMED RETRIEVERS")
    print("=" * 70)
    print("""
Using multiple specialized retrievers:
- Technical documentation retriever
- Business documentation retriever
- Knowledge base retriever
Each provides different perspectives on the same topic.
    """)

    # Create different retrievers
    tech_retriever = TechnicalDocsRetriever()
    business_retriever = BusinessDocsRetriever()
    kb_retriever = create_knowledge_base_retriever()

    # Configure settings. Registered retrievers are addressable by name;
    # with the default langgraph-agent strategy, every registered retriever
    # is also exposed to the research agent as a search tool.
    settings = create_settings_snapshot(
        {
            "search.tool": "knowledge_base",  # Primary retriever
        }
    )

    # Use multiple retrievers in research
    result = quick_summary(
        query="Implementing machine learning in production",
        settings_snapshot=settings,
        retrievers={
            "technical": tech_retriever,
            "business": business_retriever,
            "knowledge_base": kb_retriever,
        },
        search_tool="knowledge_base",  # Primary retriever (others stay available)
        iterations=2,
        questions_per_iteration=2,
        programmatic_mode=True,
    )

    print("\nResearch Summary (first 400 chars):")
    print(result["summary"][:400] + "...")

    # Analyze sources by type
    sources = result.get("sources", [])
    print(f"\nTotal sources found: {len(sources)}")

    # Group sources by retriever
    source_types = {}
    for source in sources:
        if isinstance(source, dict):
            source_type = source.get("metadata", {}).get("source", "unknown")
        else:
            source_type = "other"
        source_types[source_type] = source_types.get(source_type, 0) + 1

    print("\nSources by retriever:")
    for stype, count in source_types.items():
        print(f"  - {stype}: {count} sources")

    return result


def demonstrate_retriever_plus_web():
    """Show how to combine custom retrievers with web search."""
    print("\n" + "=" * 70)
    print("RETRIEVER + WEB SEARCH COMBINATION")
    print("=" * 70)
    print("""
Combining internal knowledge with web search:
- Internal: Custom retriever with proprietary knowledge
- External: Wikipedia for general context
This provides both specific and general information.
    """)

    # Create internal knowledge retriever
    internal_retriever = create_knowledge_base_retriever()

    # Configure settings to use both retriever and web
    settings = create_settings_snapshot(
        {
            "search.tool": "wikipedia",  # Also use Wikipedia
        }
    )

    # Research combining internal and external sources
    result = detailed_research(
        query="Best practices for cloud migration",
        settings_snapshot=settings,
        retrievers={
            "internal_kb": internal_retriever,
        },
        search_tool="wikipedia",  # Also search Wikipedia
        search_strategy="source-based",
        iterations=2,
        questions_per_iteration=3,
        programmatic_mode=True,
    )

    print(f"\nResearch ID: {result['research_id']}")
    print(f"Summary length: {len(result['summary'])} characters")

    # Analyze source distribution
    sources = result.get("sources", [])
    internal_sources = 0
    external_sources = 0

    for source in sources:
        if isinstance(source, dict) and "knowledge_base" in str(source):
            internal_sources += 1
        else:
            external_sources += 1

    print("\nSource distribution:")
    print(f"  - Internal knowledge base: {internal_sources} sources")
    print(f"  - External (Wikipedia): {external_sources} sources")

    # Show how different sources complement each other
    print("\nComplementary insights from hybrid search:")
    print(
        "  - Internal sources provide: Specific procedures, proprietary knowledge"
    )
    print(
        "  - External sources provide: Industry context, general best practices"
    )

    return result


def demonstrate_source_analysis():
    """Show how to analyze and compare sources from different origins."""
    print("\n" + "=" * 70)
    print("SOURCE ANALYSIS AND COMPARISON")
    print("=" * 70)
    print("""
Analyzing source quality and relevance:
- Track source origins
- Compare information consistency
- Identify unique insights from each source type
    """)

    # Create multiple retrievers
    tech_retriever = TechnicalDocsRetriever()
    business_retriever = BusinessDocsRetriever()

    settings = create_settings_snapshot(
        {
            "search.tool": "wikipedia",
        }
    )

    # Run research with detailed source tracking
    result = quick_summary(
        query="Artificial intelligence implementation strategies",
        settings_snapshot=settings,
        retrievers={
            "technical": tech_retriever,
            "business": business_retriever,
        },
        search_tool="wikipedia",  # Also use web search
        iterations=2,
        questions_per_iteration=2,
        programmatic_mode=True,
    )

    # Detailed source analysis
    print("\nSource Analysis:")
    sources = result.get("sources", [])

    # Categorize sources
    source_categories = {"technical": [], "business": [], "web": []}

    for source in sources:
        if isinstance(source, dict):
            source_type = source.get("metadata", {}).get("source", "")
            if "tech" in source_type:
                source_categories["technical"].append(source)
            elif "business" in source_type:
                source_categories["business"].append(source)
            else:
                source_categories["web"].append(source)
        else:
            source_categories["web"].append(source)

    # Report on each category
    for category, category_sources in source_categories.items():
        print(f"\n{category.upper()} Sources ({len(category_sources)}):")
        if category_sources:
            for i, source in enumerate(category_sources[:2], 1):  # Show first 2
                if isinstance(source, dict):
                    title = source.get("metadata", {}).get("title", "Untitled")
                    print(f"  {i}. {title}")
                else:
                    print(f"  {i}. {str(source)[:60]}...")

    # Show findings breakdown
    findings = result.get("findings", [])
    print(f"\nTotal findings: {len(findings)}")
    print("Findings provide integrated insights from all source types")

    return result


def main():
    """Run all hybrid search demonstrations."""
    print("=" * 70)
    print("LOCAL DEEP RESEARCH - HYBRID SEARCH DEMONSTRATION")
    print("=" * 70)
    print("""
This example shows how to combine multiple search sources:
- Custom retrievers for proprietary knowledge
- Web search engines for public information
- Source analysis across origins
    """)

    # Run demonstrations
    demonstrate_multiple_retrievers()
    demonstrate_retriever_plus_web()
    demonstrate_source_analysis()

    print("\n" + "=" * 70)
    print("KEY TAKEAWAYS")
    print("=" * 70)
    print("""
1. Multiple Retrievers: Use specialized retrievers for different document types
2. Hybrid Search: Combine internal knowledge with web search for comprehensive results
3. Source Analysis: Track and analyze sources to understand information origin

Best Practices:
- Name your retrievers descriptively for easy tracking
- Balance internal and external sources based on your needs
- Use source analysis to verify information consistency
    """)

    print("\n✓ Hybrid search demonstration complete!")


if __name__ == "__main__":
    main()
