"""
Load documents from bytes content.

This module provides functions to load documents from in-memory bytes,
which is useful for handling file uploads via HTTP.
"""

import tempfile
from pathlib import Path
from typing import Optional

from langchain_core.documents import Document
from loguru import logger

from local_deep_research.security.filename_sanitizer import sanitize_filename

from .loader_registry import (
    get_loader_class_for_extension,
    is_extension_supported,
)


def load_from_bytes(
    content: bytes,
    extension: str,
    filename: str = "upload",
    source_url: Optional[str] = None,
) -> list[Document]:
    """
    Load documents from bytes content.

    This function writes the bytes to a temporary file, uses the appropriate
    LangChain loader, then cleans up the temp file.

    Args:
        content: File content as bytes
        extension: File extension (with or without leading dot)
        filename: Original filename for metadata
        source_url: Optional source URL for metadata

    Returns:
        List of Document objects with extracted content

    Raises:
        ValueError: If the extension is not supported
    """
    # Defense in depth: re-sanitize filename even though callers
    # should have sanitized already
    try:
        filename = sanitize_filename(filename)
    except Exception:
        filename = "upload"

    # Normalize extension
    ext = (
        extension.lower()
        if extension.startswith(".")
        else f".{extension.lower()}"
    )

    # Check if extension is supported
    if not is_extension_supported(ext):
        raise ValueError(f"Unsupported file extension: {ext}")

    # Get the loader class for this extension
    loader_info = get_loader_class_for_extension(ext)
    if loader_info is None:
        raise ValueError(f"No loader found for extension: {ext}")

    loader_class, loader_kwargs = loader_info

    # Create temp file with the content
    tmp_path = None
    try:
        with tempfile.NamedTemporaryFile(
            suffix=ext, delete=False, prefix="ldr_upload_"
        ) as tmp:
            tmp.write(content)
            tmp_path = tmp.name

        # Create loader and load documents
        loader = loader_class(tmp_path, **loader_kwargs)
        documents = loader.load()

        # Add metadata to all documents
        for doc in documents:
            doc.metadata["original_filename"] = filename
            if source_url:
                doc.metadata["source_url"] = source_url

        logger.info(
            f"Loaded {len(documents)} document(s) from {filename} ({ext})"
        )
        return documents  # type: ignore[no-any-return]

    except Exception:
        logger.exception(f"Error loading {filename} ({ext})")
        raise

    finally:
        # Clean up temp file
        if tmp_path:
            try:
                Path(tmp_path).unlink(missing_ok=True)
            except Exception:
                logger.warning(f"Failed to clean up temp file: {tmp_path}")


def extract_text_from_bytes(
    content: bytes,
    extension: str,
    filename: str = "upload",
) -> Optional[str]:
    """
    Extract text from bytes content.

    This is a convenience function that loads documents and joins their content.

    Args:
        content: File content as bytes
        extension: File extension (with or without leading dot)
        filename: Original filename for logging

    Returns:
        Extracted text as string, or None if extraction failed
    """
    try:
        documents = load_from_bytes(content, extension, filename)
        if documents:
            return "\n\n".join(
                doc.page_content for doc in documents if doc.page_content
            )
        return None
    except ValueError:
        logger.warning("Unsupported format")
        return None
    except Exception:
        logger.exception(f"Error extracting text from {filename}")
        return None
