"""
Behavioral tests for config/paths module.

Tests the real logic: LDR_DATA_DIR env var override, SHA-256 username hashing,
and structural invariants (all subdirs under data dir).
"""

import re


class TestDataDirectoryEnvOverride:
    """Tests for LDR_DATA_DIR environment variable handling."""

    def test_custom_dir_from_env(self, tmp_path, monkeypatch):
        """LDR_DATA_DIR overrides the default platformdirs path."""
        from local_deep_research.config.paths import get_data_directory

        custom_dir = str(tmp_path / "custom_data")
        monkeypatch.setenv("LDR_DATA_DIR", custom_dir)
        assert get_data_directory() == tmp_path / "custom_data"

    def test_empty_env_var_uses_default(self, monkeypatch):
        """Empty LDR_DATA_DIR is falsy — falls through to platformdirs."""
        from local_deep_research.config.paths import get_data_directory

        monkeypatch.setenv("LDR_DATA_DIR", "")
        result = get_data_directory()
        # Empty string is falsy, so os.getenv returns "" but `if custom_path:`
        # is False — should use platformdirs default
        assert "local-deep-research" in str(result)

    def test_unset_env_var_uses_default(self, monkeypatch):
        """Without LDR_DATA_DIR, uses platformdirs default."""
        from local_deep_research.config.paths import get_data_directory

        monkeypatch.delenv("LDR_DATA_DIR", raising=False)
        result = get_data_directory()
        assert "local-deep-research" in str(result)

    def test_custom_dir_propagates_to_all_subdirectories(
        self, tmp_path, monkeypatch
    ):
        """LDR_DATA_DIR affects every subdirectory function."""
        from local_deep_research.config.paths import (
            get_cache_directory,
            get_config_directory,
            get_data_directory,
            get_encrypted_database_path,
            get_library_directory,
            get_logs_directory,
            get_models_directory,
            get_research_outputs_directory,
        )

        custom_dir = str(tmp_path / "custom")
        monkeypatch.setenv("LDR_DATA_DIR", custom_dir)

        data_dir = get_data_directory()
        subdirs = [
            get_research_outputs_directory(),
            get_cache_directory(),
            get_logs_directory(),
            get_encrypted_database_path(),
            get_library_directory(),
            get_config_directory(),
            get_models_directory(),
        ]
        for subdir in subdirs:
            assert subdir.parent == data_dir, f"{subdir} not under {data_dir}"


class TestUserDatabaseFilenameHashing:
    """Tests for get_user_database_filename SHA-256 hashing logic."""

    def test_deterministic_same_input(self):
        """Same username always produces the same filename."""
        from local_deep_research.config.paths import get_user_database_filename

        assert get_user_database_filename(
            "alice"
        ) == get_user_database_filename("alice")

    def test_different_users_different_filenames(self):
        """Different usernames produce different filenames."""
        from local_deep_research.config.paths import get_user_database_filename

        assert get_user_database_filename(
            "alice"
        ) != get_user_database_filename("bob")

    def test_case_sensitive(self):
        """'Alice' and 'alice' hash differently (SHA-256 is case-sensitive)."""
        from local_deep_research.config.paths import get_user_database_filename

        assert get_user_database_filename(
            "Alice"
        ) != get_user_database_filename("alice")

    def test_hash_is_16_hex_characters(self):
        """Hash portion is exactly 16 lowercase hex characters."""
        from local_deep_research.config.paths import get_user_database_filename

        result = get_user_database_filename("testuser")
        hash_part = result.removeprefix("ldr_user_").removesuffix(".db")
        assert len(hash_part) == 16
        assert re.fullmatch(r"[0-9a-f]+", hash_part), (
            f"Non-hex chars in hash: {hash_part}"
        )

    def test_special_characters_sanitized_by_hashing(self):
        """Path-traversal chars in username don't leak into filename."""
        from local_deep_research.config.paths import get_user_database_filename

        result = get_user_database_filename("user@example.com/../../etc/passwd")
        hash_part = result.removeprefix("ldr_user_").removesuffix(".db")
        assert re.fullmatch(r"[0-9a-f]+", hash_part)

    def test_unicode_username_hashed_via_utf8(self):
        """Unicode usernames are encoded as UTF-8 before hashing."""
        from local_deep_research.config.paths import get_user_database_filename

        result = get_user_database_filename("用户名")
        hash_part = result.removeprefix("ldr_user_").removesuffix(".db")
        assert len(hash_part) == 16

    def test_empty_username_produces_known_hash_prefix(self):
        """Empty string is valid input — SHA-256('') starts with e3b0c442."""
        from local_deep_research.config.paths import get_user_database_filename

        result = get_user_database_filename("")
        hash_part = result.removeprefix("ldr_user_").removesuffix(".db")
        assert hash_part.startswith("e3b0c442")


class TestSubdirectoryStructure:
    """Tests for structural invariants across all subdirectory functions."""

    def test_all_subdirs_have_correct_names_and_parent(self):
        """Each subdirectory function returns the right name under data dir."""
        from local_deep_research.config.paths import (
            get_cache_directory,
            get_config_directory,
            get_data_directory,
            get_encrypted_database_path,
            get_library_directory,
            get_logs_directory,
            get_models_directory,
            get_research_outputs_directory,
        )

        data_dir = get_data_directory()
        expected = {
            "research_outputs": get_research_outputs_directory,
            "cache": get_cache_directory,
            "logs": get_logs_directory,
            "encrypted_databases": get_encrypted_database_path,
            "library": get_library_directory,
            "config": get_config_directory,
            "models": get_models_directory,
        }
        for name, func in expected.items():
            result = func()
            assert result.parent == data_dir, (
                f"{func.__name__} not under data dir"
            )
            assert result.name == name, f"{func.__name__} has wrong name"

    def test_no_subdirectory_name_collisions(self):
        """All 7 subdirectory functions use distinct names."""
        from local_deep_research.config.paths import (
            get_cache_directory,
            get_config_directory,
            get_encrypted_database_path,
            get_library_directory,
            get_logs_directory,
            get_models_directory,
            get_research_outputs_directory,
        )

        names = [
            get_research_outputs_directory().name,
            get_cache_directory().name,
            get_logs_directory().name,
            get_encrypted_database_path().name,
            get_library_directory().name,
            get_config_directory().name,
            get_models_directory().name,
        ]
        assert len(names) == len(set(names)), f"Duplicate names: {names}"

    def test_backward_compat_get_data_dir_returns_string(self):
        """get_data_dir() returns string version of get_data_directory()."""
        from local_deep_research.config.paths import (
            get_data_dir,
            get_data_directory,
        )

        assert get_data_dir() == str(get_data_directory())
