"""Tests for the SignalR subscriber and TurnAccumulator."""

import os
from pathlib import Path

import pytest

from neo_cortex.subscriber import TurnAccumulator, configure_paths, parse_args


class TestTurnAccumulator:
    def test_initial_state(self) -> None:
        acc = TurnAccumulator()
        assert acc.session_id == ""
        assert acc.question == ""
        assert acc.answer == ""
        assert acc.model == "unknown"
        assert acc.tools_used == []
        assert acc.turn_number == 0
        assert not acc.is_complete

    def test_on_user_message(self) -> None:
        acc = TurnAccumulator()
        acc.on_user_message("s1", "What is Python?")
        assert acc.session_id == "s1"
        assert acc.question == "What is Python?"
        assert acc.turn_number == 1

    def test_on_assistant_message(self) -> None:
        acc = TurnAccumulator()
        acc.on_assistant_message("s1", "Python is a language", "opus")
        assert acc.answer == "Python is a language"
        assert acc.model == "opus"

    def test_on_tool_use(self) -> None:
        acc = TurnAccumulator()
        acc.on_tool_use("s1", "Read")
        acc.on_tool_use("s1", "Write")
        assert acc.tools_used == ["Read", "Write"]

    def test_on_tool_use_deduplicates(self) -> None:
        acc = TurnAccumulator()
        acc.on_tool_use("s1", "Read")
        acc.on_tool_use("s1", "Read")
        assert acc.tools_used == ["Read"]

    def test_is_complete_requires_both(self) -> None:
        acc = TurnAccumulator()
        acc.on_user_message("s1", "question")
        assert not acc.is_complete

        acc.on_assistant_message("s1", "answer", "opus")
        assert acc.is_complete

    def test_reset_clears_turn_data(self) -> None:
        acc = TurnAccumulator()
        acc.on_user_message("s1", "question")
        acc.on_assistant_message("s1", "answer", "opus")
        acc.on_tool_use("s1", "Read")

        acc.reset()
        assert acc.question == ""
        assert acc.answer == ""
        assert acc.tools_used == []
        # session_id and turn_number persist across turns
        assert acc.session_id == "s1"
        assert acc.turn_number == 1

    def test_multiple_turns(self) -> None:
        acc = TurnAccumulator()

        # Turn 1
        acc.on_user_message("s1", "q1")
        acc.on_assistant_message("s1", "a1", "opus")
        assert acc.turn_number == 1
        assert acc.is_complete
        acc.reset()

        # Turn 2
        acc.on_user_message("s1", "q2")
        acc.on_assistant_message("s1", "a2", "sonnet")
        assert acc.turn_number == 2
        assert acc.question == "q2"
        assert acc.model == "sonnet"

    def test_full_turn_flow(self) -> None:
        acc = TurnAccumulator()
        acc.on_user_message("sess123", "Fix the bug in auth.py")
        acc.on_tool_use("sess123", "Read")
        acc.on_tool_use("sess123", "Edit")
        acc.on_assistant_message("sess123", "I fixed the auth bug by...", "opus")

        assert acc.is_complete
        assert acc.session_id == "sess123"
        assert acc.question == "Fix the bug in auth.py"
        assert acc.answer == "I fixed the auth bug by..."
        assert acc.model == "opus"
        assert acc.tools_used == ["Read", "Edit"]
        assert acc.turn_number == 1


class TestConfigurePaths:
    def test_sets_env_vars(self, tmp_path: Path) -> None:
        data_dir = str(tmp_path / "test_data")
        configure_paths(data_dir)

        assert os.environ["CORTEX_DB_PATH"] == str(Path(data_dir) / "cortex_db")
        assert os.environ["MEMORY_INDEX_DB_PATH"] == str(Path(data_dir) / "cortex_db" / "memory_index.db")
        assert os.environ["CONVERSATION_DB_PATH"] == str(Path(data_dir) / "cortex_db" / "conversation_log.db")

    def test_paths_are_under_data_dir(self, tmp_path: Path) -> None:
        data_dir = str(tmp_path / "my_project")
        configure_paths(data_dir)

        for key in ["CORTEX_DB_PATH", "MEMORY_INDEX_DB_PATH", "CONVERSATION_DB_PATH"]:
            assert os.environ[key].startswith(data_dir)


class TestParseArgs:
    def test_required_args(self) -> None:
        args = parse_args(["--hub-url", "http://localhost:5070/hub/memory", "--data-dir", "/tmp/data"])
        assert args.hub_url == "http://localhost:5070/hub/memory"
        assert args.data_dir == "/tmp/data"

    def test_missing_hub_url_fails(self) -> None:
        with pytest.raises(SystemExit):
            parse_args(["--data-dir", "/tmp/data"])

    def test_missing_data_dir_fails(self) -> None:
        with pytest.raises(SystemExit):
            parse_args(["--hub-url", "http://localhost:5070/hub/memory"])
