"""Layer 4 — CloudReconcileResult computed properties, summary, and lifecycle."""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from kanoniv.cloud import CloudReconcileResult


def _make_result(
    identity_summary: dict | None = None,
    run_health: dict | None = None,
    client: MagicMock | None = None,
    owns_client: bool = False,
) -> CloudReconcileResult:
    return CloudReconcileResult(
        job_id="j-test-001",
        status="completed",
        canonicals_created=42,
        links_created=87,
        duration_ms=1234,
        identity_summary=identity_summary or {},
        run_health=run_health or {},
        _client=client or MagicMock(),
        _owns_client=owns_client,
    )


# ---------------------------------------------------------------------------
# Computed properties
# ---------------------------------------------------------------------------

class TestComputedProperties:
    """CloudReconcileResult computed properties from identity_summary."""

    def test_cluster_count(self):
        r = _make_result(identity_summary={"output": {"canonical_identities": 42}})
        assert r.cluster_count == 42

    def test_cluster_count_missing(self):
        r = _make_result(identity_summary={})
        assert r.cluster_count == 0

    def test_merge_rate(self):
        r = _make_result(identity_summary={"output": {"merge_rate": 0.58}})
        assert r.merge_rate == pytest.approx(0.58)

    def test_merge_rate_missing(self):
        r = _make_result(identity_summary={})
        assert r.merge_rate == 0.0

    def test_match_quality(self):
        mq = {"accepted": 87, "rejected": 5}
        r = _make_result(identity_summary={"match_quality": mq})
        assert r.match_quality == mq

    def test_match_quality_missing(self):
        r = _make_result(identity_summary={})
        assert r.match_quality == {}

    def test_health_status(self):
        r = _make_result(run_health={"status": "healthy"})
        assert r.health_status == "healthy"

    def test_health_status_degraded(self):
        r = _make_result(run_health={"status": "degraded"})
        assert r.health_status == "degraded"

    def test_health_status_missing(self):
        r = _make_result(run_health={})
        assert r.health_status == "unknown"

    def test_health_flags(self):
        r = _make_result(
            identity_summary={"health_flags": ["low_confidence", "stale_source"]},
        )
        assert r.health_flags == ["low_confidence", "stale_source"]

    def test_health_flags_missing(self):
        r = _make_result(identity_summary={})
        assert r.health_flags == []


# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------

class TestSummary:
    """summary() returns human-readable text."""

    def test_contains_job_id(self):
        r = _make_result()
        assert "j-test-001" in r.summary()

    def test_contains_status(self):
        r = _make_result()
        assert "completed" in r.summary()

    def test_contains_merge_rate(self):
        r = _make_result(identity_summary={"output": {"merge_rate": 0.58}})
        s = r.summary()
        assert "58" in s  # 58.0% or 58%

    def test_contains_health_flags(self):
        r = _make_result(
            identity_summary={"health_flags": ["stale_source"]},
        )
        assert "stale_source" in r.summary()


# ---------------------------------------------------------------------------
# Lifecycle
# ---------------------------------------------------------------------------

class TestResultLifecycle:
    """close() and context manager behavior."""

    def test_close_on_owned_client(self):
        mock_client = MagicMock()
        r = _make_result(client=mock_client, owns_client=True)
        r.close()
        mock_client.close.assert_called_once()

    def test_no_close_on_unowned_client(self):
        mock_client = MagicMock()
        r = _make_result(client=mock_client, owns_client=False)
        r.close()
        mock_client.close.assert_not_called()

    def test_context_manager_calls_close(self):
        mock_client = MagicMock()
        r = _make_result(client=mock_client, owns_client=True)
        with r:
            pass
        mock_client.close.assert_called_once()
