import pytest

from frisk_sdk.redact import RedactOption, redact_dictionary


@pytest.mark.unit
def test_redact_dictionary_noop_when_redact_is_false():
    d = {"a": 1, "b": {"c": True}}

    result = redact_dictionary(d, False)

    # No redaction should occur.
    assert result.value == d
    assert result.redacted_paths == []


@pytest.mark.unit
def test_redact_dictionary_noop_when_redact_is_none():
    from typing import cast

    d = {"a": 1}

    # normalize_redact_option(None) => False. We use cast to exercise this behavior
    # without fighting static type-checkers.
    result = redact_dictionary(d, cast(RedactOption | None, None))

    assert result.value == d
    assert result.redacted_paths == []


@pytest.mark.unit
def test_redact_dictionary_noop_when_redact_is_empty_list():
    d = {"a": 1, "b": 2}

    result = redact_dictionary(d, [])

    assert result.value == d
    assert result.redacted_paths == []


@pytest.mark.unit
def test_redact_dictionary_redact_true_redacts_entire_object_and_tracks_star():
    d = {"a": 1, "b": {"c": True, "d": "secret"}}

    result = redact_dictionary(d, True)

    # Current core behavior: redact=True produces an empty object and records '*'.
    assert result.value == {}
    assert result.redacted_paths
    assert "*" in result.redacted_paths


@pytest.mark.unit
def test_redact_dictionary_redacts_selected_paths_by_removing_them():
    d = {"keep": 1, "secret": "x", "nested": {"secret": "y", "keep": 2}}

    result = redact_dictionary(d, ["secret", "nested.secret"])

    # Should keep non-redacted data.
    assert result.value["keep"] == 1
    assert result.value["nested"]["keep"] == 2

    # Selected redacted keys are removed.
    assert "secret" not in result.value
    assert "secret" not in result.value["nested"]

    # Paths should be tracked.
    assert set(result.redacted_paths) == {"secret", "nested.secret"}


@pytest.mark.unit
def test_redact_dictionary_ignores_unknown_paths_and_reports_no_redactions():
    d = {"a": 1, "nested": {"b": 2}}

    result = redact_dictionary(d, ["does_not_exist", "nested.c"])

    # Nothing should change if no provided paths exist.
    assert result.value == d
    assert result.redacted_paths == []
