"""Tests for scratchpad.py.

Refs: Epic #367, Sub-issue #372
"""

from __future__ import annotations

import json
import os
import sys
from pathlib import Path
from unittest.mock import patch

import pytest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))

from mempalace.scratchpad import (
    write_scratch,
    read_scratch,
    delete_scratch,
    list_sessions,
    clear_session,
    _scratch_path,
)


@pytest.fixture
def scratch_dir(tmp_path):
    """Provide a temporary scratchpad directory."""
    with patch("mempalace.scratchpad.SCRATCHPAD_DIR", tmp_path):
        yield tmp_path


class TestScratchPath:
    def test_sanitizes_session_id(self):
        path = _scratch_path("safe-id_123")
        assert "safe-id_123.json" in str(path)

    def test_strips_dangerous_chars(self):
        path = _scratch_path("../../etc/passwd")
        assert ".." not in path.name
        assert "/" not in path.name
        # Dots are stripped, so only alphanumeric chars remain
        assert path.name == "etcpasswd.json"


class TestWriteAndRead:
    def test_write_then_read(self, scratch_dir):
        write_scratch("sess1", "note", "hello world")
        result = read_scratch("sess1", "note")
        assert "note" in result
        assert result["note"]["value"] == "hello world"

    def test_read_all_keys(self, scratch_dir):
        write_scratch("sess1", "a", 1)
        write_scratch("sess1", "b", 2)
        result = read_scratch("sess1")
        assert "a" in result
        assert "b" in result

    def test_read_missing_key(self, scratch_dir):
        write_scratch("sess1", "exists", "yes")
        result = read_scratch("sess1", "missing")
        assert result == {}

    def test_read_missing_session(self, scratch_dir):
        result = read_scratch("nonexistent")
        assert result == {}

    def test_overwrite_key(self, scratch_dir):
        write_scratch("sess1", "key", "v1")
        write_scratch("sess1", "key", "v2")
        result = read_scratch("sess1", "key")
        assert result["key"]["value"] == "v2"


class TestDelete:
    def test_delete_existing_key(self, scratch_dir):
        write_scratch("sess1", "key", "val")
        assert delete_scratch("sess1", "key") is True
        assert read_scratch("sess1", "key") == {}

    def test_delete_missing_key(self, scratch_dir):
        write_scratch("sess1", "other", "val")
        assert delete_scratch("sess1", "missing") is False


class TestListSessions:
    def test_lists_sessions(self, scratch_dir):
        write_scratch("alpha", "k", "v")
        write_scratch("beta", "k", "v")
        sessions = list_sessions()
        assert "alpha" in sessions
        assert "beta" in sessions

    def test_empty_directory(self, scratch_dir):
        assert list_sessions() == []


class TestClearSession:
    def test_clears_existing(self, scratch_dir):
        write_scratch("sess1", "k", "v")
        assert clear_session("sess1") is True
        assert read_scratch("sess1") == {}

    def test_clear_nonexistent(self, scratch_dir):
        assert clear_session("ghost") is False
