"""
ShelfAI test suite.

Tests core functionality: shelf operations, index parsing,
transcript parsing, session management, and CLI commands.
"""

import json
import pytest


class MockProvider:
    """Mock LLM provider for testing."""

    def __init__(self, responses=None):
        self.responses = responses or []
        self._call_index = 0
        self.calls = []

    def complete(self, system, user, max_tokens=4096):
        self.calls.append({"system": system, "user": user})
        if self._call_index < len(self.responses):
            response = self.responses[self._call_index]
            self._call_index += 1
            return response
        return json.dumps({
            "user_preferences": [],
            "agent_lessons": [],
            "task_patterns": [],
            "knowledge_corrections": [],
            "new_context": [],
            "abstract_updates": [],
        })


class FailOnSecondCallProvider:
    """Mock provider that succeeds on first call, fails on second (dedup)."""

    def __init__(self):
        self._calls = 0

    def complete(self, system, user, max_tokens=4096):
        self._calls += 1
        if self._calls == 1:
            return json.dumps({
                "user_preferences": [
                    {"content": "test pref", "confidence": "high", "evidence": "e"}
                ],
                "agent_lessons": [],
                "task_patterns": [],
                "knowledge_corrections": [],
                "new_context": [],
                "abstract_updates": [],
            })
        raise ConnectionError("Dedup call failed")


class TestAdditionalEdgeCases:
    """Tests for edge cases identified in code review."""

    def test_restore_nonexistent_raises(self, shelf_dir):
        """#24: restore_backup with bad session ID should raise."""
        from shelfai.core.safety import restore_backup

        with pytest.raises(FileNotFoundError):
            restore_backup(shelf_dir, "nonexistent_session_999")

    def test_session_id_format_and_uniqueness(self):
        """#25: Session IDs should be well-formed and unique."""
        from shelfai.core.safety import generate_session_id

        sid = generate_session_id()
        assert len(sid) >= 20
        assert "_" in sid
        sid2 = generate_session_id()
        assert sid != sid2

    def test_dedup_failure_keeps_extractions(self, shelf_dir):
        """#27: If dedup LLM call fails, extractions should be preserved."""
        from shelfai.core.shelf import Shelf
        from shelfai.agents.session import SessionManager

        shelf = Shelf(str(shelf_dir))
        manager = SessionManager(shelf, FailOnSecondCallProvider())

        report = manager.process_text("## User\nKeep it short\n\n## Assistant\nOk!")
        assert not report.extraction.is_empty
        assert len(report.extraction.user_preferences) == 1

    def test_memory_limit_blocks_writes(self, shelf_dir):
        """#28: Memory entries should be blocked when limit is reached."""
        from shelfai.core.shelf import Shelf
        from shelfai.agents.session import SessionManager

        shelf = Shelf(str(shelf_dir))

        # Read the actual configured limit instead of hardcoding
        config = shelf.load_config()
        limit = config.session.max_entries_per_file

        entries = "\n".join(f"- Entry {i} [confidence: high]" for i in range(limit + 1))
        shelf.append_to_file("memory/user/preferences.md", f"\n## 2026-01-01\n{entries}\n")

        extraction = json.dumps({
            "user_preferences": [
                {"content": "New pref", "confidence": "high", "evidence": "e"}
            ],
            "agent_lessons": [],
            "task_patterns": [],
            "knowledge_corrections": [],
            "new_context": [],
            "abstract_updates": [],
        })
        dedup_response = json.dumps({
            "user_preferences": [
                {"content": "New pref", "confidence": "high", "evidence": "e"}
            ],
            "agent_lessons": [],
            "task_patterns": [],
        })

        provider = MockProvider(responses=[extraction, dedup_response])
        manager = SessionManager(shelf, provider)
        report = manager.process_text("## User\nTest\n\n## Assistant\nOk!")

        assert len(report.skipped_changes) > 0
        assert "limit" in report.skipped_changes[0]["reason"].lower()

    def test_traversal_in_new_context_blocked(self, shelf_dir):
        """#29: Path traversal in LLM-suggested new files should be blocked."""
        from shelfai.core.shelf import Shelf
        from shelfai.agents.session import SessionManager

        shelf = Shelf(str(shelf_dir))

        extraction = json.dumps({
            "user_preferences": [],
            "agent_lessons": [],
            "task_patterns": [],
            "knowledge_corrections": [],
            "new_context": [{
                "suggested_path": "../../etc/evil.md",
                "suggested_abstract": "Evil file",
                "content_summary": "Pwned",
                "evidence": "n/a",
            }],
            "abstract_updates": [],
        })

        provider = MockProvider(responses=[extraction])
        manager = SessionManager(shelf, provider)
        report = manager.process_text("## User\nTest\n\n## Assistant\nOk!")

        assert len(report.errors) > 0
        assert "traversal" in report.errors[0]["error"].lower()
        assert not (shelf_dir.parent.parent / "etc" / "evil.md").exists()

    def test_empty_path_blocked(self, shelf_dir):
        """#3: Empty paths should be rejected."""
        from shelfai.core.safety import validate_path

        with pytest.raises(ValueError, match="Empty"):
            validate_path(shelf_dir, "")
        with pytest.raises(ValueError, match="Empty"):
            validate_path(shelf_dir, "   ")

    def test_null_byte_path_blocked(self, shelf_dir):
        """#2: Null bytes in paths should be rejected."""
        from shelfai.core.safety import validate_path

        with pytest.raises(ValueError, match="Null byte"):
            validate_path(shelf_dir, "skills/evil\x00.md")

    def test_append_to_file_validates_path(self, shelf_dir):
        """#23: append_to_file should validate paths."""
        from shelfai.core.shelf import Shelf

        shelf = Shelf(str(shelf_dir))
        with pytest.raises(ValueError, match="Path traversal blocked"):
            shelf.append_to_file("../../evil.md", "pwned")

    def test_parse_json_none_input(self):
        """#10: _parse_json_response should handle None input."""
        from shelfai.agents.session import _parse_json_response

        assert _parse_json_response(None) is None
        assert _parse_json_response("") is None


