"""
Tests for HippoConfig.

Issue: #814
"""

from __future__ import annotations

import pytest

from cortex.hippo.config import HippoConfig, load_hippo_config


def test_default_config():
    """Default config has expected values."""
    config = HippoConfig()
    assert config.enabled is False
    assert config.db_path == "./hippo.db"
    assert config.fresh_tail_count == 8
    assert config.context_threshold == 0.75
    assert config.max_tokens == 100_000
    assert config.summarization_model == "gemini-2.5-flash"
    assert config.quality_threshold == 0.6
    assert config.cornerstone_provider is None


def test_config_from_dict():
    """Config can be created from a dictionary."""
    config = HippoConfig(
        enabled=True,
        db_path="/custom/path.db",
        fresh_tail_count=16,
        max_tokens=200_000,
    )
    assert config.enabled is True
    assert config.db_path == "/custom/path.db"
    assert config.fresh_tail_count == 16
    assert config.max_tokens == 200_000


def test_load_hippo_config_from_toml():
    """load_hippo_config parses nested TOML structure."""
    toml_dict = {
        "cortex": {
            "hippo": {
                "enabled": True,
                "db_path": "/data/hippo.db",
                "fresh_tail_count": 8,
                "context_threshold": 0.8,
            }
        }
    }
    config = load_hippo_config(toml_dict)
    assert config.enabled is True
    assert config.db_path == "/data/hippo.db"
    assert config.fresh_tail_count == 8
    assert config.context_threshold == 0.8


def test_load_hippo_config_flat():
    """load_hippo_config handles flat {hippo: {...}} structure."""
    toml_dict = {
        "hippo": {
            "enabled": True,
            "max_tokens": 50_000,
        }
    }
    config = load_hippo_config(toml_dict)
    assert config.enabled is True
    assert config.max_tokens == 50_000


def test_load_hippo_config_none():
    """load_hippo_config returns defaults when None."""
    config = load_hippo_config(None)
    assert config.enabled is False
    assert config.db_path == "./hippo.db"


def test_load_hippo_config_no_hippo_section():
    """load_hippo_config returns defaults when hippo section missing."""
    config = load_hippo_config({"cortex": {"storage": {"db_path": "cortex.db"}}})
    assert config.enabled is False


def test_config_validation_threshold_range():
    """context_threshold must be 0-1."""
    with pytest.raises(Exception):
        HippoConfig(context_threshold=1.5)

    with pytest.raises(Exception):
        HippoConfig(context_threshold=-0.1)


def test_config_validation_fresh_tail_min():
    """fresh_tail_count must be >= 1."""
    with pytest.raises(Exception):
        HippoConfig(fresh_tail_count=0)


def test_config_extra_fields_ignored():
    """Extra fields are ignored (extra='ignore')."""
    config = HippoConfig(
        enabled=True,
        unknown_field="should be ignored",
    )
    assert config.enabled is True
    assert not hasattr(config, "unknown_field")


def test_config_defaults_aligned_with_ts():
    """Config defaults match lossless-claw TypeScript defaults (#1169)."""
    config = HippoConfig()
    assert config.leaf_target_tokens == 1200
    assert config.condensed_target_tokens == 2000
    assert config.leaf_min_fanout == 8
    assert config.condensed_min_fanout == 4
    assert config.condensed_min_fanout_hard == 2
    assert config.incremental_condensed_max_depth == 0
    assert config.context_threshold == 0.75
    assert config.fresh_tail_count == 8
    assert config.leaf_chunk_tokens == 20_000
    assert config.large_file_token_threshold == 25_000
    assert config.autocompact_disabled is False
    assert config.prune_heartbeat_ok is False


def test_config_cornerstone_provider():
    """Cornerstone provider can be set."""
    config = HippoConfig(cornerstone_provider="http://localhost:8000")
    assert config.cornerstone_provider == "http://localhost:8000"


def test_config_all_fields():
    """All config fields can be set together."""
    config = HippoConfig(
        enabled=True,
        db_path="/data/hippo.db",
        enable_wal=True,
        busy_timeout_ms=3000,
        context_threshold=0.8,
        fresh_tail_count=16,
        max_tokens=200_000,
        summarization_model="claude-3-haiku",
        quality_threshold=0.7,
        cornerstone_provider="http://cortex:8000",
        enable_embeddings=False,
        timezone="Asia/Bangkok",
    )
    assert config.enabled is True
    assert config.db_path == "/data/hippo.db"
    assert config.busy_timeout_ms == 3000
    assert config.timezone == "Asia/Bangkok"


class TestMinExpandTokenCap:
    """#1232: min_expand_token_cap is configurable."""

    def test_default_value(self):
        config = HippoConfig()
        assert config.min_expand_token_cap == 512

    def test_custom_value(self):
        config = HippoConfig(min_expand_token_cap=256)
        assert config.min_expand_token_cap == 256

    def test_minimum_clamp(self):
        """ge=1 validation should reject 0."""
        with pytest.raises(Exception):
            HippoConfig(min_expand_token_cap=0)

    def test_from_toml(self):
        config = load_hippo_config({"hippo": {"min_expand_token_cap": 1024}})
        assert config.min_expand_token_cap == 1024


class TestRerankerTimeoutConfig:
    """#1226: retrieval_reranker_timeout_seconds is configurable."""

    def test_default_value(self):
        config = HippoConfig()
        assert config.retrieval_reranker_timeout_seconds == 30.0

    def test_custom_value(self):
        config = HippoConfig(retrieval_reranker_timeout_seconds=60.0)
        assert config.retrieval_reranker_timeout_seconds == 60.0

    def test_rejects_zero(self):
        """gt=0.0 validation should reject 0."""
        with pytest.raises(Exception):
            HippoConfig(retrieval_reranker_timeout_seconds=0.0)

    def test_from_toml(self):
        config = load_hippo_config({"hippo": {"retrieval_reranker_timeout_seconds": 45.0}})
        assert config.retrieval_reranker_timeout_seconds == 45.0
