from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Any

import networkx as nx

from hieromem_core.policy.evaluator import MemoryPolicyEvaluator
from hieromem_core.policy.parser import load_policy
from hieromem_core.retrieval.confidence import ConfidenceWeights, compute_confidence


def _sample_policy() -> dict[str, Any]:
    return {
        "apiVersion": "hieromem/v1",
        "kind": "MemoryPolicy",
        "metadata": {"name": "test-policy", "namespace": "default"},
        "spec": {
            "retention": {"horizon": "1d", "decay_curve": "exponential", "base_lambda": 0.9},
            "summarization": {"trigger": {"episode_count": 2, "or_age": "1h"}, "depth": 1},
            "graph": {"edge_ttl": "2d", "prune_orphans": True, "max_hops": 3},
            "governance": {"forbidden_relations": ["secret"], "max_episodes": 3},
            "priority": {"high_priority_patterns": ["safety"], "low_priority_patterns": []},
        },
    }


def test_policy_parser_round_trip() -> None:
    policy = load_policy(_sample_policy())
    assert policy.name == "test-policy"
    assert policy.retention.horizon is not None
    assert policy.governance.max_episodes == 3


def test_policy_evaluator_blocks_forbidden_relation() -> None:
    policy = load_policy(_sample_policy())
    evaluator = MemoryPolicyEvaluator(policy)
    graph = nx.DiGraph()
    graph.add_edge("a", "b", relation="secret")
    decision = evaluator.evaluate_insert(
        graph=graph,
        total_episodes=1,
        namespace="default",
    )
    assert decision.allowed is False
    assert any("forbidden" in reason for reason in decision.reasons)


def test_policy_summarise_trigger_by_age() -> None:
    policy = load_policy(_sample_policy())
    evaluator = MemoryPolicyEvaluator(policy)

    @dataclass
    class EpisodeStub:
        tocc: datetime

    episodes = [
        EpisodeStub(tocc=datetime.now() - timedelta(hours=2)),
        EpisodeStub(tocc=datetime.now()),
    ]
    assert evaluator.should_summarise(episodes) is True


def test_compute_confidence_normalises_weights() -> None:
    score = compute_confidence(
        vector_similarity=0.8,
        graph_path_score=0.5,
        trust_score=0.9,
        freshness=0.7,
        weights=ConfidenceWeights(alpha=2, beta=2, gamma=2, delta=2),
    )
    assert 0.0 <= score <= 1.0
