"""Chaos: Shadow Mode (Spec Diff Impact).

Proving: "Spec changes are visible and explainable before they affect production."
Requires native extension with reconcile_local for reconcile tests.
"""
from __future__ import annotations

import pytest

from tests.contract.conftest import (
    SINGLE_SOURCE_SPEC,
    make_source,
    make_spec,
    requires_native,
    requires_reconcile,
)

from kanoniv.diff import diff


# ---------------------------------------------------------------------------
# Shadow / impact tests
# ---------------------------------------------------------------------------

STRICT_SPEC = """\
api_version: kanoniv/v2
identity_version: test_v1.0
entity:
  name: customer
sources:
  - name: main
    system: csv
    table: main
    id: id
    attributes:
      email: email
      first_name: first_name
      last_name: last_name
      phone: phone
blocking:
  strategy: composite
  keys:
    - [email]
    - [phone]
rules:
  - name: email_exact
    type: exact
    field: email
    weight: 1.0
  - name: phone_exact
    type: exact
    field: phone
    weight: 0.8
decision:
  thresholds:
    match: 0.9
    review: 0.5
  conflict_strategy: prefer_high_confidence
"""

LOOSE_SPEC = """\
api_version: kanoniv/v2
identity_version: test_v1.0
entity:
  name: customer
sources:
  - name: main
    system: csv
    table: main
    id: id
    attributes:
      email: email
      first_name: first_name
      last_name: last_name
      phone: phone
blocking:
  strategy: composite
  keys:
    - [email]
    - [phone]
rules:
  - name: email_exact
    type: exact
    field: email
    weight: 1.0
  - name: phone_exact
    type: exact
    field: phone
    weight: 0.8
decision:
  thresholds:
    match: 0.5
    review: 0.2
  conflict_strategy: prefer_high_confidence
"""


SHADOW_ROWS = [
    {"id": "1", "email": "alice@example.com", "first_name": "Alice",
     "last_name": "Smith", "phone": "555-0001"},
    {"id": "2", "email": "bob@example.com", "first_name": "Bob",
     "last_name": "Jones", "phone": "555-0001"},
    {"id": "3", "email": "carol@example.com", "first_name": "Carol",
     "last_name": "Brown", "phone": "555-0002"},
    {"id": "4", "email": "alice@example.com", "first_name": "Alice",
     "last_name": "Smith", "phone": "555-0003"},
]


@requires_reconcile
class TestShadowReconcile:
    def test_looser_threshold_more_merges(self, tmp_path):
        """Lower match threshold → cluster_count decreases (more merges)."""
        from kanoniv.reconcile import reconcile

        src = make_source(tmp_path, "main", SHADOW_ROWS)
        strict_result = reconcile([src], make_spec(STRICT_SPEC))
        loose_result = reconcile([src], make_spec(LOOSE_SPEC))
        assert loose_result.cluster_count <= strict_result.cluster_count

    def test_stricter_threshold_fewer_merges(self, tmp_path):
        """Raise match threshold → cluster_count increases (fewer merges)."""
        from kanoniv.reconcile import reconcile

        src = make_source(tmp_path, "main", SHADOW_ROWS)
        strict_result = reconcile([src], make_spec(STRICT_SPEC))
        loose_result = reconcile([src], make_spec(LOOSE_SPEC))
        assert strict_result.cluster_count >= loose_result.cluster_count

    def test_added_rule_changes_result(self, tmp_path):
        """Adding a rule can change cluster count."""
        from kanoniv.reconcile import reconcile

        base_rows = [
            {"id": "1", "email": "alice@example.com", "first_name": "Alice",
             "last_name": "Smith", "phone": "555-0001"},
            {"id": "2", "email": "alice@example.com", "first_name": "Alice",
             "last_name": "Smith", "phone": "555-0002"},
            {"id": "3", "email": "bob@example.com", "first_name": "Bob",
             "last_name": "Jones", "phone": "555-0003"},
        ]
        src = make_source(tmp_path, "main", base_rows)
        result_base = reconcile([src], make_spec(SINGLE_SOURCE_SPEC))
        assert result_base.cluster_count == 2

    def test_weight_increase_shifts_results(self, tmp_path):
        """Increasing a rule's weight → changes merge behavior."""
        from kanoniv.reconcile import reconcile

        rows = [
            {"id": "1", "email": "a@example.com", "first_name": "Alice",
             "last_name": "Smith", "phone": "555-0001"},
            {"id": "2", "email": "b@example.com", "first_name": "Bob",
             "last_name": "Jones", "phone": "555-0001"},
        ]
        src = make_source(tmp_path, "main", rows)

        low_weight_spec = SINGLE_SOURCE_SPEC.replace("weight: 0.8", "weight: 0.3")
        result_low = reconcile([src], make_spec(low_weight_spec))

        high_weight_spec = SINGLE_SOURCE_SPEC.replace("weight: 0.8", "weight: 1.0")
        result_high = reconcile([src], make_spec(high_weight_spec))

        assert result_high.cluster_count <= result_low.cluster_count


@requires_native
class TestShadowDiff:
    def test_diff_predicts_direction(self):
        """diff(strict, loose) shows threshold lowered."""
        strict = make_spec(STRICT_SPEC)
        loose = make_spec(LOOSE_SPEC)
        result = diff(strict, loose)
        assert result.thresholds_changed
