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

import time
from functools import wraps
from typing import Dict, Any

from flask import Blueprint, jsonify, request, Response
from loguru import logger

from ..api.research_functions import analyze_documents
from ..database.session_context import get_user_db_session
from ..utilities.db_utils import get_settings_manager

# Create a blueprint for the API
api_blueprint = Blueprint("api_v1", __name__, url_prefix="/api/v1")

# Rate limiting data store: {ip_address: [timestamp1, timestamp2, ...]}
rate_limit_data = {}


def api_access_control(f):
    """
    Decorator to enforce API access control:
    - Check if API is enabled
    - Enforce rate limiting
    """

    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Get username from session
        from flask import g, session

        username = (
            g.current_user
            if hasattr(g, "current_user")
            else session.get("username")
        )

        # Check if API is enabled
        api_enabled = True  # Default to enabled
        rate_limit = 60  # Default 60 requests per minute

        # Only try to get settings if there's an authenticated user
        if username:
            with get_user_db_session(username) as db_session:
                if db_session:
                    settings_manager = get_settings_manager(
                        db_session, username
                    )
                    api_enabled = settings_manager.get_setting(
                        "app.enable_api", True
                    )
                    rate_limit = settings_manager.get_setting(
                        "app.api_rate_limit", 60
                    )

        if not api_enabled:
            return jsonify({"error": "API access is disabled"}), 403

        # Implement rate limiting
        if rate_limit:
            client_ip = request.remote_addr
            current_time = time.time()

            # Initialize or clean up old requests for this IP
            if client_ip not in rate_limit_data:
                rate_limit_data[client_ip] = []

            # Remove timestamps older than 1 minute
            rate_limit_data[client_ip] = [
                ts
                for ts in rate_limit_data[client_ip]
                if current_time - ts < 60
            ]

            # Check if rate limit is exceeded
            if len(rate_limit_data[client_ip]) >= rate_limit:
                return (
                    jsonify(
                        {
                            "error": f"Rate limit exceeded. Maximum {rate_limit} requests per minute allowed."
                        }
                    ),
                    429,
                )

            # Add current timestamp to the list
            rate_limit_data[client_ip].append(current_time)

        return f(*args, **kwargs)

    return decorated_function


@api_blueprint.route("/", methods=["GET"])
@api_access_control
def api_documentation():
    """
    Provide documentation on the available API endpoints.
    """
    api_docs = {
        "api_version": "v1",
        "description": "REST API for Local Deep Research",
        "endpoints": [
            {
                "path": "/api/v1/quick_summary",
                "method": "POST",
                "description": "Generate a quick research summary",
                "parameters": {
                    "query": "Research query (required)",
                    "search_tool": "Search engine to use (optional)",
                    "iterations": "Number of search iterations (optional)",
                    "temperature": "LLM temperature (optional)",
                },
            },
            {
                "path": "/api/v1/generate_report",
                "method": "POST",
                "description": "Generate a comprehensive research report",
                "parameters": {
                    "query": "Research query (required)",
                    "output_file": "Path to save report (optional)",
                    "searches_per_section": "Searches per report section (optional)",
                    "model_name": "LLM model to use (optional)",
                    "temperature": "LLM temperature (optional)",
                },
            },
            {
                "path": "/api/v1/analyze_documents",
                "method": "POST",
                "description": "Search and analyze documents in a local collection",
                "parameters": {
                    "query": "Search query (required)",
                    "collection_name": "Local collection name (required)",
                    "max_results": "Maximum results to return (optional)",
                    "temperature": "LLM temperature (optional)",
                    "force_reindex": "Force collection reindexing (optional)",
                },
            },
        ],
    }

    return jsonify(api_docs)


@api_blueprint.route("/health", methods=["GET"])
def health_check():
    """Simple health check endpoint."""
    return jsonify(
        {"status": "ok", "message": "API is running", "timestamp": time.time()}
    )


@api_blueprint.route("/quick_summary_test", methods=["POST"])
@api_access_control
def api_quick_summary_test():
    """Test endpoint using programmatic access with minimal parameters for fast testing."""
    data = request.json
    if not data or "query" not in data:
        return jsonify({"error": "Query parameter is required"}), 400

    query = data.get("query")

    try:
        # Import here to avoid circular imports
        from ..api.research_functions import quick_summary

        logger.info(f"Processing quick_summary_test request: query='{query}'")

        # Use minimal parameters for faster testing
        result = quick_summary(
            query=query,
            search_tool="wikipedia",  # Use fast Wikipedia search for testing
            iterations=1,  # Single iteration for speed
            temperature=0.7,
        )

        return jsonify(result)
    except Exception as e:
        logger.exception(f"Error in quick_summary_test API: {e!s}")
        return (
            jsonify(
                {
                    "error": "An internal error has occurred. Please try again later."
                }
            ),
            500,
        )


def _serialize_results(results: Dict[str, Any]) -> Response:
    """
    Converts the results dictionary into a JSON string.

    Args:
        results: The results dictionary.

    Returns:
        The JSON string.

    """
    # The main thing that needs to be handled here is the `Document` instances.
    converted_results = results.copy()
    for finding in converted_results.get("findings", []):
        for i, document in enumerate(finding.get("documents", [])):
            finding["documents"][i] = {
                "metadata": document.metadata,
                "content": document.page_content,
            }

    return jsonify(converted_results)


@api_blueprint.route("/quick_summary", methods=["POST"])
@api_access_control
def api_quick_summary():
    """
    Generate a quick research summary via REST API.

    POST /api/v1/quick_summary
    {
        "query": "Advances in fusion energy research",
        "search_tool": "auto",  # Optional: search engine to use
        "iterations": 2,        # Optional: number of search iterations
        "temperature": 0.7      # Optional: LLM temperature
    }
    """
    logger.debug("API quick_summary endpoint called")
    data = request.json
    logger.debug(f"Request data: {data}")

    if not data or "query" not in data:
        logger.debug("Missing query parameter")
        return jsonify({"error": "Query parameter is required"}), 400

    # Extract query and optional parameters
    query = data.get("query")
    params = {k: v for k, v in data.items() if k != "query"}
    logger.debug(f"Query: {query}, params: {params}")

    # Get username from session or g object
    from flask import g, session

    username = (
        g.current_user
        if hasattr(g, "current_user")
        else session.get("username")
    )
    if username:
        params["username"] = username

    try:
        # Import here to avoid circular imports
        from ..api.research_functions import quick_summary
        from ..database.session_context import get_user_db_session
        from ..utilities.db_utils import get_settings_manager

        logger.info(
            f"Processing quick_summary request: query='{query}' for user='{username}'"
        )

        # Set reasonable defaults for API use
        params.setdefault("temperature", 0.7)
        params.setdefault("search_tool", "auto")
        params.setdefault("iterations", 1)

        # Get settings snapshot for the user
        if username:
            try:
                logger.debug(f"Getting settings snapshot for user: {username}")
                with get_user_db_session(username) as db_session:
                    if db_session:
                        try:
                            settings_manager = get_settings_manager(
                                db_session, username
                            )
                            all_settings = settings_manager.get_all_settings()
                            # Extract just the values for the settings snapshot
                            settings_snapshot = {}
                            for key, setting in all_settings.items():
                                if (
                                    isinstance(setting, dict)
                                    and "value" in setting
                                ):
                                    settings_snapshot[key] = setting["value"]
                                else:
                                    settings_snapshot[key] = setting
                            params["settings_snapshot"] = settings_snapshot
                            logger.debug(
                                f"Got settings snapshot with {len(settings_snapshot)} settings"
                            )
                        except AttributeError as ae:
                            logger.exception(
                                f"SettingsManager attribute error: {ae}. "
                                f"Type: {type(settings_manager) if 'settings_manager' in locals() else 'Unknown'}"
                            )
                            raise
                    else:
                        logger.warning(
                            f"No database session for user: {username}"
                        )
            except Exception as e:
                logger.warning(
                    f"Failed to get settings snapshot: {e}", exc_info=True
                )
                # Continue with empty snapshot rather than failing
                params["settings_snapshot"] = {}
        else:
            logger.debug("No username in session, skipping settings snapshot")
            params["settings_snapshot"] = {}

        # Call the actual research function
        result = quick_summary(query, **params)

        return _serialize_results(result)
    except TimeoutError:
        logger.exception("Request timed out")
        return (
            jsonify(
                {
                    "error": "Request timed out. Please try with a simpler query or fewer iterations."
                }
            ),
            504,
        )
    except Exception:
        logger.exception("Error in quick_summary API")
        return (
            jsonify(
                {
                    "error": "An internal error has occurred. Please try again later."
                }
            ),
            500,
        )


@api_blueprint.route("/generate_report", methods=["POST"])
@api_access_control
def api_generate_report():
    """
    Generate a comprehensive research report via REST API.

    POST /api/v1/generate_report
    {
        "query": "Impact of climate change on agriculture",
        "output_file": "/path/to/save/report.md",  # Optional
        "searches_per_section": 2,                 # Optional
        "model_name": "gpt-4",                     # Optional
        "temperature": 0.5                         # Optional
    }
    """
    data = request.json
    if not data or "query" not in data:
        return jsonify({"error": "Query parameter is required"}), 400

    query = data.get("query")
    params = {k: v for k, v in data.items() if k != "query"}

    try:
        # Import here to avoid circular imports
        from ..api.research_functions import generate_report

        # Set reasonable defaults for API use
        params.setdefault("searches_per_section", 1)
        params.setdefault("temperature", 0.7)

        logger.info(
            f"Processing generate_report request: query='{query}', params={params}"
        )

        result = generate_report(query, **params)

        # Don't return the full content for large reports
        if (
            result
            and "content" in result
            and isinstance(result["content"], str)
            and len(result["content"]) > 10000
        ):
            # Include a summary of the report content
            content_preview = (
                result["content"][:2000] + "... [Content truncated]"
            )
            result["content"] = content_preview
            result["content_truncated"] = True

        return jsonify(result)
    except TimeoutError:
        logger.exception("Request timed out")
        return (
            jsonify(
                {"error": "Request timed out. Please try with a simpler query."}
            ),
            504,
        )
    except Exception as e:
        logger.exception(f"Error in generate_report API: {e!s}")
        return (
            jsonify(
                {
                    "error": "An internal error has occurred. Please try again later."
                }
            ),
            500,
        )


@api_blueprint.route("/analyze_documents", methods=["POST"])
@api_access_control
def api_analyze_documents():
    """
    Search and analyze documents in a local collection via REST API.

    POST /api/v1/analyze_documents
    {
        "query": "neural networks in medicine",
        "collection_name": "research_papers",      # Required: local collection name
        "max_results": 20,                         # Optional: max results to return
        "temperature": 0.7,                        # Optional: LLM temperature
        "force_reindex": false                     # Optional: force reindexing
    }
    """
    data = request.json
    if not data or "query" not in data or "collection_name" not in data:
        return (
            jsonify(
                {
                    "error": "Both query and collection_name parameters are required"
                }
            ),
            400,
        )

    query = data.get("query")
    collection_name = data.get("collection_name")
    params = {
        k: v for k, v in data.items() if k not in ["query", "collection_name"]
    }

    try:
        result = analyze_documents(query, collection_name, **params)
        return jsonify(result)
    except Exception as e:
        logger.exception(f"Error in analyze_documents API: {e!s}")
        return (
            jsonify(
                {
                    "error": "An internal error has occurred. Please try again later."
                }
            ),
            500,
        )
