"""
Edge-case tests for loader_registry module.

Focuses on:
- get_loader_for_path returning None when constructor raises
- Special loader kwargs (TSV tab delimiter, TXT autodetect, notebook outputs, Evernote)
- Optional loader flag gating (HAS_ODT/EPUB/RTF/RST/ORG/IMAGE_LOADER)
- Path handling (string conversion, uppercase extension)
"""

from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest


# ---------------------------------------------------------------------------
# get_loader_for_path -- constructor raises returns None
# ---------------------------------------------------------------------------


class TestGetLoaderForPathConstructorException:
    """When the loader class constructor raises, get_loader_for_path returns None."""

    def test_runtime_error_in_constructor_returns_none(self):
        """A RuntimeError during loader instantiation yields None."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
            get_loader_for_path,
        )

        class _BoomLoader:
            def __init__(self, *args, **kwargs):
                raise RuntimeError("boom")

        with patch.dict(
            LOADER_REGISTRY,
            {".txt": {"loader_class": _BoomLoader, "loader_kwargs": {}}},
        ):
            result = get_loader_for_path("/fake/path/file.txt")
            assert result is None

    def test_type_error_in_constructor_returns_none(self):
        """A TypeError during loader instantiation yields None."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
            get_loader_for_path,
        )

        class _BadSigLoader:
            def __init__(self):
                pass

        with patch.dict(
            LOADER_REGISTRY,
            {".csv": {"loader_class": _BadSigLoader, "loader_kwargs": {}}},
        ):
            result = get_loader_for_path("/fake/data.csv")
            assert result is None

    def test_value_error_in_constructor_returns_none(self):
        """A ValueError during loader instantiation yields None."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
            get_loader_for_path,
        )

        class _ValErrLoader:
            def __init__(self, *args, **kwargs):
                raise ValueError("invalid arg")

        with patch.dict(
            LOADER_REGISTRY,
            {".md": {"loader_class": _ValErrLoader, "loader_kwargs": {}}},
        ):
            result = get_loader_for_path("/fake/readme.md")
            assert result is None


# ---------------------------------------------------------------------------
# Special loader kwargs
# ---------------------------------------------------------------------------


class TestSpecialLoaderKwargs:
    """Verify that specific extensions carry the correct special kwargs."""

    def test_tsv_has_tab_delimiter(self):
        """TSV entry uses CSVLoader with tab delimiter."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
        )

        entry = LOADER_REGISTRY[".tsv"]
        assert entry["loader_kwargs"]["csv_args"]["delimiter"] == "\t"

    def test_txt_has_autodetect_encoding(self):
        """TXT entry specifies autodetect_encoding=True."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
        )

        kwargs = LOADER_REGISTRY[".txt"]["loader_kwargs"]
        assert kwargs["autodetect_encoding"] is True
        assert kwargs["encoding"] == "utf-8"

    def test_notebook_include_outputs(self):
        """Notebook entry has include_outputs=True and remove_newline=True."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
        )

        kwargs = LOADER_REGISTRY[".ipynb"]["loader_kwargs"]
        assert kwargs["include_outputs"] is True
        assert kwargs["remove_newline"] is True

    def test_evernote_not_single_document(self):
        """Evernote entry has load_single_document=False."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
        )

        kwargs = LOADER_REGISTRY[".enex"]["loader_kwargs"]
        assert kwargs["load_single_document"] is False


# ---------------------------------------------------------------------------
# Optional loader flag gating (module-level HAS_* flags)
# ---------------------------------------------------------------------------


class TestOptionalLoaderFlagGating:
    """Test that HAS_* flags control whether optional extensions are registered."""

    def test_odt_absent_when_flag_false(self):
        """When HAS_ODT_LOADER is False, .odt must not be in the registry."""
        import local_deep_research.document_loaders.loader_registry as mod

        if not mod.HAS_ODT_LOADER:
            assert ".odt" not in mod.LOADER_REGISTRY
        else:
            pytest.skip("HAS_ODT_LOADER is True in this environment")

    def test_odt_present_when_flag_true(self):
        """When HAS_ODT_LOADER is True, .odt must be in the registry."""
        import local_deep_research.document_loaders.loader_registry as mod

        if mod.HAS_ODT_LOADER:
            assert ".odt" in mod.LOADER_REGISTRY
            assert (
                mod.LOADER_REGISTRY[".odt"]["loader_class"].__name__
                == "UnstructuredODTLoader"
            )
        else:
            pytest.skip("HAS_ODT_LOADER is False in this environment")

    def test_epub_gated_by_flag(self):
        """EPUB registration matches HAS_EPUB_LOADER flag."""
        import local_deep_research.document_loaders.loader_registry as mod

        assert (".epub" in mod.LOADER_REGISTRY) == mod.HAS_EPUB_LOADER

    def test_rtf_gated_by_flag(self):
        """RTF registration matches HAS_RTF_LOADER flag."""
        import local_deep_research.document_loaders.loader_registry as mod

        assert (".rtf" in mod.LOADER_REGISTRY) == mod.HAS_RTF_LOADER

    def test_rst_gated_by_flag(self):
        """RST registration matches HAS_RST_LOADER flag."""
        import local_deep_research.document_loaders.loader_registry as mod

        assert (".rst" in mod.LOADER_REGISTRY) == mod.HAS_RST_LOADER

    def test_org_gated_by_flag(self):
        """Org-mode registration matches HAS_ORG_LOADER flag."""
        import local_deep_research.document_loaders.loader_registry as mod

        assert (".org" in mod.LOADER_REGISTRY) == mod.HAS_ORG_LOADER

    def test_image_extensions_gated_by_flag(self):
        """Image extensions are present iff the loader class AND the OCR
        runtime dependency (pytesseract + tesseract binary) are available."""
        import local_deep_research.document_loaders.loader_registry as mod

        image_exts = [
            ".png",
            ".jpg",
            ".jpeg",
            ".tiff",
            ".tif",
            ".bmp",
            ".heic",
        ]
        expected = mod.HAS_IMAGE_LOADER and mod.HAS_OCR_DEP
        for ext in image_exts:
            assert (ext in mod.LOADER_REGISTRY) == expected, (
                f"{ext} registration does not match "
                f"HAS_IMAGE_LOADER={mod.HAS_IMAGE_LOADER} "
                f"HAS_OCR_DEP={mod.HAS_OCR_DEP}"
            )


# ---------------------------------------------------------------------------
# Path handling -- string conversion and uppercase extension
# ---------------------------------------------------------------------------


class TestPathHandling:
    """Test that get_loader_for_path handles various path forms correctly."""

    def test_string_path_is_converted_to_pathlib(self):
        """A plain string path should work identically to a Path object."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
            get_loader_for_path,
        )

        mock_loader_instance = MagicMock()
        mock_class = MagicMock(return_value=mock_loader_instance)

        with patch.dict(
            LOADER_REGISTRY,
            {
                ".txt": {
                    "loader_class": mock_class,
                    "loader_kwargs": {"encoding": "utf-8"},
                }
            },
        ):
            result = get_loader_for_path("/some/dir/notes.txt")
            assert result is mock_loader_instance
            mock_class.assert_called_once_with(
                "/some/dir/notes.txt", encoding="utf-8"
            )

    def test_uppercase_extension_resolves_correctly(self):
        """A file with .CSV extension should still resolve via .lower()."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
            get_loader_for_path,
        )

        mock_loader_instance = MagicMock()
        mock_class = MagicMock(return_value=mock_loader_instance)

        with patch.dict(
            LOADER_REGISTRY,
            {".csv": {"loader_class": mock_class, "loader_kwargs": {}}},
        ):
            result = get_loader_for_path("/data/REPORT.CSV")
            assert result is mock_loader_instance
            mock_class.assert_called_once_with("/data/REPORT.CSV")

    def test_path_object_suffix_extracted(self):
        """Path object suffix is used for extension lookup, not the full name."""
        from local_deep_research.document_loaders.loader_registry import (
            LOADER_REGISTRY,
            get_loader_for_path,
        )

        mock_loader_instance = MagicMock()
        mock_class = MagicMock(return_value=mock_loader_instance)

        with patch.dict(
            LOADER_REGISTRY,
            {".json": {"loader_class": mock_class, "loader_kwargs": {}}},
        ):
            result = get_loader_for_path(Path("/tmp/config.backup.json"))
            assert result is mock_loader_instance
            call_args = mock_class.call_args
            assert call_args[0][0].endswith("config.backup.json")
