"""
API module for Local Deep Research.
Provides programmatic access to search and research capabilities.
"""

import logging
from typing import Any, Callable, Dict, Optional

from ..config.llm_config import get_llm
from ..config.search_config import get_search
from ..report_generator import IntegratedReportGenerator
from ..search_system import AdvancedSearchSystem
from ..utilities.search_utilities import remove_think_tags

logger = logging.getLogger(__name__)


def _init_search_system(
    model_name: str | None = None,
    temperature: float = 0.7,
    provider: str | None = None,
    openai_endpoint_url: str | None = None,
    progress_callback: Callable[[str, int, dict], None] | None = None,
    search_tool: Optional[str] = None,
    iterations: int = 1,
    questions_per_iteration: int = 1,
) -> AdvancedSearchSystem:
    """
    Initializes the advanced search system with specified parameters. This function sets up
    and returns an instance of the AdvancedSearchSystem using the provided configuration
    options such as model name, temperature for randomness in responses, provider service
    details, endpoint URL, and an optional search tool.

    Args:
        model_name: Name of the model to use (if None, uses database setting)
        temperature: LLM temperature for generation
        provider: Provider to use (if None, uses database setting)
        openai_endpoint_url: Custom endpoint URL to use (if None, uses database
            setting)
        progress_callback: Optional callback function to receive progress updates
        search_tool: Search engine to use (auto, wikipedia, arxiv, etc.). If None, uses default
        iterations: Number of research cycles to perform
        questions_per_iteration: Number of questions to generate per cycle

    Returns:
        AdvancedSearchSystem: An instance of the configured AdvancedSearchSystem.

    """
    # Get language model with custom temperature
    llm = get_llm(
        temperature=temperature,
        openai_endpoint_url=openai_endpoint_url,
        model_name=model_name,
        provider=provider,
    )

    # Set the search engine if specified
    search_engine = None
    if search_tool:
        search_engine = get_search(search_tool, llm_instance=llm)
        if search_engine is None:
            logger.warning(
                f"Could not create search engine '{search_tool}', using default."
            )

    # Create search system with custom parameters
    system = AdvancedSearchSystem(llm=llm, search=search_engine)

    # Override default settings with user-provided values
    system.max_iterations = iterations
    system.questions_per_iteration = questions_per_iteration

    # Set progress callback if provided
    if progress_callback:
        system.set_progress_callback(progress_callback)

    return system


def quick_summary(
    query: str,
    **kwargs: Any,
) -> Dict[str, Any]:
    """
    Generate a quick research summary for a given query.

    Args:
        query: The research query to analyze
        **kwargs: Configuration for the search system. Will be forwarded to
            `_init_search_system()`.

    Returns:
        Dictionary containing the research results with keys:
        - 'summary': The generated summary text
        - 'findings': List of detailed findings from each search
        - 'iterations': Number of iterations performed
        - 'questions': Questions generated during research
    """
    logger.info("Generating quick summary for query: %s", query)

    system = _init_search_system(**kwargs)

    # Perform the search and analysis
    results = system.analyze_topic(query)

    # Extract the summary from the current knowledge
    if results and "current_knowledge" in results:
        summary = results["current_knowledge"]
    else:
        summary = "Unable to generate summary for the query."

    # Prepare the return value
    return {
        "summary": summary,
        "findings": results.get("findings", []),
        "iterations": results.get("iterations", 0),
        "questions": results.get("questions", {}),
        "formatted_findings": results.get("formatted_findings", ""),
        "sources": results.get("all_links_of_system", []),
    }


def generate_report(
    query: str,
    output_file: Optional[str] = None,
    progress_callback: Optional[Callable] = None,
    searches_per_section: int = 2,
    **kwargs: Any,
) -> Dict[str, Any]:
    """
    Generate a comprehensive, structured research report for a given query.

    Args:
        query: The research query to analyze
        output_file: Optional path to save report markdown file
        progress_callback: Optional callback function to receive progress updates
        searches_per_section: The number of searches to perform for each
            section in the report.

    Returns:
        Dictionary containing the research report with keys:
        - 'content': The full report content in markdown format
        - 'metadata': Report metadata including generated timestamp and query
    """
    logger.info("Generating comprehensive research report for query: %s", query)

    system = _init_search_system(**kwargs)

    # Set progress callback if provided
    if progress_callback:
        system.set_progress_callback(progress_callback)

    # Perform the initial research
    initial_findings = system.analyze_topic(query)

    # Generate the structured report
    report_generator = IntegratedReportGenerator(
        search_system=system,
        llm=system.model,
        searches_per_section=searches_per_section,
    )
    report = report_generator.generate_report(initial_findings, query)

    # Save report to file if path is provided
    if output_file and report and "content" in report:
        with open(output_file, "w", encoding="utf-8") as f:
            f.write(report["content"])
        logger.info(f"Report saved to {output_file}")
        report["file_path"] = output_file
    return report


def analyze_documents(
    query: str,
    collection_name: str,
    max_results: int = 10,
    temperature: float = 0.7,
    force_reindex: bool = False,
    output_file: Optional[str] = None,
) -> Dict[str, Any]:
    """
    Search and analyze documents in a specific local collection.

    Args:
        query: The search query
        collection_name: Name of the local document collection to search
        max_results: Maximum number of results to return
        temperature: LLM temperature for summary generation
        force_reindex: Whether to force reindexing the collection
        output_file: Optional path to save analysis results to a file

    Returns:
        Dictionary containing:
        - 'summary': Summary of the findings
        - 'documents': List of matching documents with content and metadata
    """
    logger.info(
        f"Analyzing documents in collection '{collection_name}' for query: {query}"
    )

    # Get language model with custom temperature
    llm = get_llm(temperature=temperature)

    # Get search engine for the specified collection
    search = get_search(collection_name, llm_instance=llm)

    if not search:
        return {
            "summary": f"Error: Collection '{collection_name}' not found or not properly configured.",
            "documents": [],
        }

    # Set max results
    search.max_results = max_results

    # Force reindex if requested
    if force_reindex and hasattr(search, "embedding_manager"):
        for folder_path in search.folder_paths:
            search.embedding_manager.index_folder(folder_path, force_reindex=True)

    # Perform the search
    results = search.run(query)

    if not results:
        return {
            "summary": f"No documents found in collection '{collection_name}' for query: '{query}'",
            "documents": [],
        }

    # Get LLM to generate a summary of the results

    docs_text = "\n\n".join(
        [
            f"Document {i + 1}:" f" {doc.get('content', doc.get('snippet', ''))[:1000]}"
            for i, doc in enumerate(results[:5])
        ]
    )  # Limit to first 5 docs and 1000 chars each

    summary_prompt = f"""Analyze these document excerpts related to the query: "{query}"

    {docs_text}

    Provide a concise summary of the key information found in these documents related to the query.
    """

    summary_response = llm.invoke(summary_prompt)
    if hasattr(summary_response, "content"):
        summary = remove_think_tags(summary_response.content)
    else:
        summary = str(summary_response)

    # Create result dictionary
    analysis_result = {
        "summary": summary,
        "documents": results,
        "collection": collection_name,
        "document_count": len(results),
    }

    # Save to file if requested
    if output_file:
        with open(output_file, "w", encoding="utf-8") as f:
            f.write(f"# Document Analysis: {query}\n\n")
            f.write(f"## Summary\n\n{summary}\n\n")
            f.write(f"## Documents Found: {len(results)}\n\n")

            for i, doc in enumerate(results):
                f.write(f"### Document {i + 1}:" f" {doc.get('title', 'Untitled')}\n\n")
                f.write(f"**Source:** {doc.get('link', 'Unknown')}\n\n")
                f.write(
                    f"**Content:**\n\n{doc.get('content', doc.get('snippet', 'No content available'))[:1000]}...\n\n"
                )
                f.write("---\n\n")

        analysis_result["file_path"] = output_file
        logger.info(f"Analysis saved to {output_file}")

    return analysis_result
