"""Tests for ieum.sessions -- session management and thread IDs.

Covers:
- Thread ID generation produces hex strings of correct length
- Thread IDs are unique
- Database path functions return valid paths
- _format_timestamp handling of various inputs
- save_env_file / load_env_file roundtrip (using temp directory)
"""

import os
import asyncio
import tempfile
from pathlib import Path
from unittest.mock import patch

import pytest

from ieum.sessions import (
    _format_timestamp,
    append_web_audit_event,
    generate_thread_id,
    get_db_path,
    get_store_db_path,
    get_web_sessions_db_path,
    init_web_sessions_db,
    list_web_audit_events,
    load_web_sessions,
    load_env_file,
    save_web_session,
    save_env_file,
)


# ---------------------------------------------------------------------------
# Thread ID generation
# ---------------------------------------------------------------------------


class TestGenerateThreadId:
    """Test thread ID generation."""

    def test_returns_string(self):
        tid = generate_thread_id()
        assert isinstance(tid, str)

    def test_length_is_8(self):
        tid = generate_thread_id()
        assert len(tid) == 8

    def test_is_hex(self):
        tid = generate_thread_id()
        int(tid, 16)  # Should not raise if valid hex

    def test_unique_ids(self):
        ids = {generate_thread_id() for _ in range(100)}
        assert len(ids) == 100  # All should be unique


# ---------------------------------------------------------------------------
# Database paths
# ---------------------------------------------------------------------------


class TestDatabasePaths:
    """Test database path resolution."""

    def test_db_path_under_home(self):
        path = get_db_path()
        assert str(Path.home()) in str(path)
        assert path.name == "sessions.db"

    def test_store_db_path(self):
        path = get_store_db_path()
        assert path.name == "memories.db"

    def test_web_sessions_db_path(self):
        path = get_web_sessions_db_path()
        assert path.name == "web_sessions.db"

    def test_all_paths_under_ieum_dir(self):
        for path in (get_db_path(), get_store_db_path(), get_web_sessions_db_path()):
            assert ".ieum" in str(path)


# ---------------------------------------------------------------------------
# _format_timestamp
# ---------------------------------------------------------------------------


class TestFormatTimestamp:
    """Test timestamp formatting for display."""

    def test_none_returns_empty(self):
        assert _format_timestamp(None) == ""

    def test_empty_string_returns_empty(self):
        assert _format_timestamp("") == ""

    def test_valid_iso_format(self):
        result = _format_timestamp("2024-12-30T18:10:00+09:00")
        assert isinstance(result, str)
        assert len(result) > 0

    def test_invalid_format_returns_empty(self):
        assert _format_timestamp("not-a-timestamp") == ""


# ---------------------------------------------------------------------------
# save_env_file / load_env_file roundtrip
# ---------------------------------------------------------------------------


class TestEnvFileRoundtrip:
    """Test saving and loading .env files."""

    def test_save_and_load_global(self, temp_dir, monkeypatch):
        """Test roundtrip with global env file."""
        # Patch Path.home to use temp dir
        monkeypatch.setattr(Path, "home", lambda: Path(temp_dir))

        settings = {
            "provider": "openai",
            "api_key": "sk-test-key",
            "model": "gpt-4o",
        }
        env_path = save_env_file(settings, target="global")
        assert os.path.exists(env_path)

        loaded = load_env_file(target="global")
        assert loaded is not None
        assert loaded["provider"] == "openai"
        assert loaded["api_key"] == "sk-test-key"
        assert loaded["model"] == "gpt-4o"

    def test_save_preserves_existing_vars(self, temp_dir, monkeypatch):
        """Existing non-managed vars should survive a save."""
        monkeypatch.setattr(Path, "home", lambda: Path(temp_dir))

        # Create initial env with a custom variable
        env_dir = Path(temp_dir) / ".ieum"
        env_dir.mkdir(parents=True, exist_ok=True)
        env_path = env_dir / ".env"
        env_path.write_text("CUSTOM_VAR=hello\n")

        # Save managed settings
        save_env_file({"provider": "anthropic"}, target="global")

        # Read back and verify custom var is preserved
        content = env_path.read_text()
        assert "CUSTOM_VAR=hello" in content
        assert "IEUM_PROVIDER=anthropic" in content

    def test_load_nonexistent_returns_none(self, temp_dir, monkeypatch):
        monkeypatch.setattr(Path, "home", lambda: Path(temp_dir))
        result = load_env_file(target="global")
        assert result is None

    def test_github_settings(self, temp_dir, monkeypatch):
        monkeypatch.setattr(Path, "home", lambda: Path(temp_dir))
        settings = {
            "provider": "openai",
            "github_pat": "ghp_test123",
            "github_host": "github.example.com",
        }
        save_env_file(settings, target="global")
        loaded = load_env_file(target="global")
        assert loaded["github_pat"] == "ghp_test123"
        assert loaded["github_host"] == "github.example.com"


class TestWebSessionPersistence:
    """Test web session persistence schema and audit log helpers."""

    def test_save_and_load_web_session_with_policy_fields(self, temp_dir, monkeypatch):
        monkeypatch.setattr(Path, "home", lambda: Path(temp_dir))

        async def _run() -> None:
            await init_web_sessions_db()
            await save_web_session(
                session_id="sess-1",
                thread_id="thread-1",
                agent_id="agent",
                working_directory="/tmp/work",
                model_name="openai/gpt-4o",
                auto_approve=False,
                approval_policy="safe_write",
                timeout_minutes=45,
                max_concurrent_sessions=3,
                rate_limit_max_requests=10,
                rate_limit_window_seconds=60,
                created_at="2026-01-01T00:00:00+00:00",
                last_activity="2026-01-01T00:00:00+00:00",
                status="active",
                user_id="u1",
                workspace_id="w1",
            )
            sessions = await load_web_sessions()
            assert len(sessions) == 1
            row = sessions[0]
            assert row["approval_policy"] == "safe_write"
            assert row["timeout_minutes"] == 45
            assert row["max_concurrent_sessions"] == 3
            assert row["rate_limit_max_requests"] == 10
            assert row["rate_limit_window_seconds"] == 60

        asyncio.run(_run())

    def test_append_and_list_audit_events(self, temp_dir, monkeypatch):
        monkeypatch.setattr(Path, "home", lambda: Path(temp_dir))

        async def _run() -> None:
            await init_web_sessions_db()
            await append_web_audit_event(
                session_id="sess-2",
                user_id="u2",
                workspace_id="w2",
                event_type="chat.send",
                payload={"content": "hello"},
            )
            await append_web_audit_event(
                session_id="sess-2",
                user_id="u2",
                workspace_id="w2",
                event_type="tool.start",
                payload={"tool_name": "write_file"},
            )
            events = await list_web_audit_events(
                session_id="sess-2",
                user_id="u2",
                limit=10,
            )
            assert len(events) == 2
            assert events[0]["event_type"] == "chat.send"
            assert events[1]["event_type"] == "tool.start"
            assert events[0]["payload"]["content"] == "hello"

        asyncio.run(_run())
