"""Tests for paths module."""

import hashlib
from pathlib import Path
from unittest.mock import patch

import pytest

from local_deep_research.config.paths import (
    get_data_directory,
    get_research_outputs_directory,
    get_cache_directory,
    get_logs_directory,
    get_encrypted_database_path,
    get_user_database_filename,
    get_data_dir,
)


class TestGetDataDirectory:
    """Tests for get_data_directory function."""

    def test_uses_env_var_override(self, tmp_path, monkeypatch):
        """Should use LDR_DATA_DIR if set."""
        monkeypatch.setenv("LDR_DATA_DIR", str(tmp_path))
        result = get_data_directory()
        assert result == tmp_path

    def test_uses_platformdirs_when_no_env_var(self, monkeypatch):
        """Should use platformdirs when no env var set."""
        monkeypatch.delenv("LDR_DATA_DIR", raising=False)
        with patch("platformdirs.user_data_dir", return_value="/mock/path"):
            result = get_data_directory()
            assert result == Path("/mock/path")

    def test_returns_path_object(self, mock_env_data_dir):
        """Should return Path object."""
        result = get_data_directory()
        assert isinstance(result, Path)

    def test_apostrophe_in_path_is_allowed(self, tmp_path, monkeypatch):
        """Regression for #3090: a legitimate POSIX path containing an
        apostrophe (e.g. /home/O'Brien/ldr) must NOT crash startup. The
        over-broad quote rejection was removed; the actual ATTACH-DATABASE
        sink validates the interpolated path separately."""
        data_dir = tmp_path / "O'Brien" / "ldr"
        monkeypatch.setenv("LDR_DATA_DIR", str(data_dir))
        result = get_data_directory()
        assert result == data_dir.resolve()

    def test_relative_path_rejected(self, monkeypatch):
        """A relative LDR_DATA_DIR is rejected (must be absolute)."""
        monkeypatch.setenv("LDR_DATA_DIR", "relative/dir")
        with pytest.raises(ValueError, match="absolute"):
            get_data_directory()

    def test_control_characters_rejected(self, tmp_path, monkeypatch):
        """A newline in LDR_DATA_DIR is still rejected (could break a SQL/
        ATTACH statement), and the offending value is not echoed."""
        monkeypatch.setenv("LDR_DATA_DIR", str(tmp_path) + "\nDROP")
        with pytest.raises(ValueError, match="control character") as exc_info:
            get_data_directory()
        assert "DROP" not in str(exc_info.value)


class TestGetResearchOutputsDirectory:
    """Tests for get_research_outputs_directory function."""

    def test_returns_subdirectory_of_data_dir(self, mock_env_data_dir):
        """Should return research_outputs subdirectory."""
        result = get_research_outputs_directory()
        assert result.name == "research_outputs"
        assert result.parent == mock_env_data_dir

    def test_creates_directory(self, mock_env_data_dir):
        """Should create directory if it doesn't exist."""
        result = get_research_outputs_directory()
        assert result.exists()
        assert result.is_dir()


class TestGetCacheDirectory:
    """Tests for get_cache_directory function."""

    def test_returns_cache_subdirectory(self, mock_env_data_dir):
        """Should return cache subdirectory."""
        result = get_cache_directory()
        assert result.name == "cache"
        assert result.parent == mock_env_data_dir

    def test_creates_directory(self, mock_env_data_dir):
        """Should create directory if it doesn't exist."""
        result = get_cache_directory()
        assert result.exists()


class TestGetLogsDirectory:
    """Tests for get_logs_directory function."""

    def test_returns_logs_subdirectory(self, mock_env_data_dir):
        """Should return logs subdirectory."""
        result = get_logs_directory()
        assert result.name == "logs"
        assert result.parent == mock_env_data_dir

    def test_creates_directory(self, mock_env_data_dir):
        """Should create directory if it doesn't exist."""
        result = get_logs_directory()
        assert result.exists()


class TestGetEncryptedDatabasePath:
    """Tests for get_encrypted_database_path function."""

    def test_returns_encrypted_databases_subdirectory(self, mock_env_data_dir):
        """Should return encrypted_databases subdirectory."""
        result = get_encrypted_database_path()
        assert result.name == "encrypted_databases"
        assert result.parent == mock_env_data_dir

    def test_creates_directory(self, mock_env_data_dir):
        """Should create directory if it doesn't exist."""
        result = get_encrypted_database_path()
        assert result.exists()


class TestGetUserDatabaseFilename:
    """Tests for get_user_database_filename function."""

    def test_generates_hashed_filename(self):
        """Should generate filename with username hash."""
        result = get_user_database_filename("testuser")
        expected_hash = hashlib.sha256("testuser".encode()).hexdigest()[:16]
        assert result == f"ldr_user_{expected_hash}.db"

    def test_consistent_for_same_username(self):
        """Should return same filename for same username."""
        result1 = get_user_database_filename("testuser")
        result2 = get_user_database_filename("testuser")
        assert result1 == result2

    def test_different_for_different_usernames(self):
        """Should return different filenames for different usernames."""
        result1 = get_user_database_filename("user1")
        result2 = get_user_database_filename("user2")
        assert result1 != result2

    def test_handles_special_characters(self):
        """Should handle special characters in username."""
        result = get_user_database_filename("user@domain.com")
        assert result.startswith("ldr_user_")
        assert result.endswith(".db")


class TestGetDataDir:
    """Tests for get_data_dir backward compat function."""

    def test_returns_string(self, mock_env_data_dir):
        """Should return string instead of Path."""
        result = get_data_dir()
        assert isinstance(result, str)
        assert result == str(mock_env_data_dir)
