"""Observation Log — append-only JSONL store + computed statistics (Task 59b/c v1).

Pins the user's decision (2026-06-28): observations are CALIBRATION data, not product data -> an
append-only JSONL log under knowledge/observations/, NO DB, NO migration. Distribution and confidence are
COMPUTED from the log; only REVIEWED observations calibrate (review gate); a later review is a new line
that supersedes by observation_id. Nothing is ever written back to a hypothesis.
"""

from __future__ import annotations

from compliance.onboarding import (
    ObservationRecord,
    ObservationType,
    aggregate_by_hypothesis,
    append_observation,
    load_observations,
    review_queue,
)


def _rec(oid, hyp, otype, reviewed=False, **kw):
    return ObservationRecord(
        observation_id=oid, hypothesis_id=hyp, observation_type=otype, reviewed=reviewed,
        timestamp="2026-07-01T00:00:00Z", customer_archetype="machine_builder+ISO27001", **kw)


def test_append_only_round_trip(tmp_path):
    p = str(tmp_path / "obs.jsonl")
    append_observation(_rec("o1", "HYP-secure_dev", ObservationType.CONFIRMED, reviewed=True), p)
    append_observation(_rec("o2", "HYP-secure_dev", ObservationType.REFUTED, reviewed=True), p)
    recs = load_observations(p)
    assert {r.observation_id for r in recs} == {"o1", "o2"}
    assert all(r.customer_archetype == "machine_builder+ISO27001" for r in recs)  # anonymised archetype, not a name


def test_review_supersedes_by_id_append_only(tmp_path):
    p = str(tmp_path / "obs.jsonl")
    append_observation(_rec("o1", "HYP-x", ObservationType.CONFIRMED, reviewed=False), p)   # raw answer
    append_observation(_rec("o1", "HYP-x", ObservationType.CONFIRMED, reviewed=True,
                            reviewed_by="anna"), p)                                          # later review event
    assert len(load_observations(p, reconcile=False)) == 2                                  # both lines kept (append-only)
    recs = load_observations(p)                                                             # reconciled
    assert len(recs) == 1 and recs[0].reviewed and recs[0].reviewed_by == "anna"


def test_statistics_apply_the_review_gate(tmp_path):
    p = str(tmp_path / "obs.jsonl")
    append_observation(_rec("a", "HYP-sdl", ObservationType.CONFIRMED, reviewed=True), p)
    append_observation(_rec("b", "HYP-sdl", ObservationType.CONFIRMED, reviewed=True), p)
    append_observation(_rec("c", "HYP-sdl", ObservationType.REFUTED, reviewed=True), p)
    append_observation(_rec("d", "HYP-sdl", ObservationType.CONFIRMED, reviewed=False), p)  # unreviewed -> ignored
    stats = {s.hypothesis_id: s for s in aggregate_by_hypothesis(load_observations(p))}
    s = stats["HYP-sdl"]
    assert s.total_count == 4 and s.reviewed_count == 3
    assert s.distribution["confirmed"] == 2 and s.distribution["refuted"] == 1   # unreviewed one excluded
    assert s.confidence == round(2 / 3, 2)                                        # (2 + 0.5*0) / 3


def test_review_queue_lists_unreviewed(tmp_path):
    p = str(tmp_path / "obs.jsonl")
    append_observation(_rec("a", "HYP-y", ObservationType.CONFIRMED, reviewed=True), p)
    append_observation(_rec("b", "HYP-y", ObservationType.PARTIAL, reviewed=False), p)
    q = review_queue(load_observations(p))
    assert [r.observation_id for r in q] == ["b"]


def test_load_directory_of_monthly_files(tmp_path):
    d = tmp_path / "observations"
    d.mkdir()
    append_observation(_rec("a", "HYP-z", ObservationType.CONFIRMED, reviewed=True), str(d / "2026-06.jsonl"))
    append_observation(_rec("b", "HYP-z", ObservationType.REFUTED, reviewed=True), str(d / "2026-07.jsonl"))
    recs = load_observations(str(d))
    assert {r.observation_id for r in recs} == {"a", "b"}
