"""Unit tests for the pure memory-extractor helpers (no LLM, no I/O)."""

from __future__ import annotations

from app.services.memory.memory_extractor import (
    merge_facts,
    merge_profile,
    normalize_key,
    render_context_str,
)
from app.services.memory.memory_schema import MemoryFact


def test_normalize_key_collapses_and_lowercases():
    assert normalize_key("  An  CÓ   Mèo ") == "an có mèo"


def test_merge_profile_new_nonnull_wins_and_interests_union():
    existing = {"name": "An", "interests": ["vẽ"]}
    update = {"name": None, "nickname": "bé An", "interests": ["Vẽ", "Lego"]}
    merged = merge_profile(existing, update)
    assert merged["name"] == "An"  # None did not overwrite
    assert merged["nickname"] == "bé An"
    # union, case-insensitive dedup, order-preserving
    assert merged["interests"] == ["vẽ", "Lego"]


def test_merge_facts_dedup_higher_salience_wins_and_caps():
    existing = [
        {
            "content": "An có mèo",
            "category": "relationship",
            "salience": 0.5,
            "dedup_key": "an có mèo",
            "created_at": "2026-01-01T00:00:00",
        }
    ]
    new = [
        MemoryFact(content="An có mèo", category="relationship", salience=0.9),
        MemoryFact(content="An thích Lego", category="preference", salience=0.7),
    ]
    merged = merge_facts(existing, new, max_facts=10)
    by = {f["content"]: f for f in merged}
    assert by["An có mèo"]["salience"] == 0.9  # higher wins, no dup
    assert "An thích Lego" in by
    assert len(merged) == 2


def test_merge_facts_caps_to_max_keeping_highest_salience():
    new = [
        MemoryFact(content=f"fact {i}", category="misc", salience=i / 10)
        for i in range(1, 6)
    ]
    merged = merge_facts([], new, max_facts=2)
    assert len(merged) == 2
    assert {f["content"] for f in merged} == {"fact 5", "fact 4"}


def test_render_context_str_includes_profile_and_facts():
    profile = {"name": "An", "interests": ["Lego"]}
    facts = [{"content": "An có mèo Miu", "salience": 0.9}]
    out = render_context_str(profile, facts)
    assert "Profile:" in out and "name: An" in out and "Lego" in out
    assert "Recent facts:" in out and "An có mèo Miu" in out


def test_render_context_str_empty():
    assert render_context_str({}, []) == ""
