"""Coverage `repos` parsing — the shared normalizer + the comma-string regression.

Court verification caught a false-action bug: a comma-separated `repos` string (the
live `steward_deploy_key` shape) was treated as ONE literal repo, so sync planned a
bogus `register-deploy-key`. The fix is one shared parser used by BOTH the doctor
coverage check (C5) and the sync coverage sweep. These tests pin: the parser handles
every shape; a comma-string whose key is present on all declared repos yields ZERO
sync actions / ZERO C5 findings; missing on a subset yields actions/findings for that
subset only.
"""

from __future__ import annotations

from mgf.secrets.doctor import Doctor
from mgf.secrets.forge import DeployKey
from mgf.secrets.managed import normalize_repos
from mgf.secrets.registry import load
from mgf.secrets.sync import Reconciler
from tests._fakes import FakeForge, FakeWoodpecker

STEWARD = """\
[steward_deploy_key]
family = "sooth"
kind = "ssh-deploy-key"
purpose = "steward key on 3 repos declared as a comma-separated string (live shape)"
consumers = ["steward CI actor"]
recovery = "re-add the deploy keys"
state = "active"
policy = { allowed_repos = ["repo-a", "repo-b", "repo-c"], blast_radius = "read 3 repos" }
rotation = { class = "static-key", staged = true }
verify = { probe = "forge-key-fingerprint" }
surfaces = [ { type = "forge-deploy-key", repos = "repo-a,repo-b,repo-c", readonly = true, title = "steward@wp (read-only)" } ]
"""

TITLE = "steward@wp (read-only)"


def _reg(tmp_path):
    p = tmp_path / "SECRETS.toml"
    p.write_text(STEWARD, encoding="utf-8")
    return load([p])


def _key():
    return DeployKey(title=TITLE, fingerprint="SHA256:x", read_only=True)


# --------------------------------------------------------------------------- #
# The shared parser.
# --------------------------------------------------------------------------- #


def test_normalize_repos_every_shape() -> None:
    managed = {"m1", "m2"}
    assert normalize_repos("ALL_MANAGED", managed=managed) == {"m1", "m2"}
    assert normalize_repos("*", managed=managed) == {"m1", "m2"}
    # the comma-string shape — split + stripped, NOT one literal repo
    assert normalize_repos("a,b, c ,d", managed=managed) == {"a", "b", "c", "d"}
    # a single bare name
    assert normalize_repos("solo", managed=managed) == {"solo"}
    # a proper list (each item may itself be a sentinel / comma-string)
    assert normalize_repos(["a", "b"], managed=managed) == {"a", "b"}
    assert normalize_repos(["a,b", "ALL_MANAGED"], managed=managed) == {"a", "b", "m1", "m2"}


# --------------------------------------------------------------------------- #
# Sync — the false-action regression.
# --------------------------------------------------------------------------- #


def test_comma_string_all_present_yields_zero_sync_actions(tmp_path) -> None:
    reg = _reg(tmp_path)
    forge = FakeForge({r: [_key()] for r in ("repo-a", "repo-b", "repo-c")})
    rec = Reconciler(reg, fed_root=tmp_path, forge=forge)
    plan = rec.plan(["forge"])
    assert plan.is_empty, [a.to_json() for a in plan.actions]  # NO bogus register action


def test_comma_string_missing_subset_yields_only_that_subset(tmp_path) -> None:
    reg = _reg(tmp_path)
    forge = FakeForge({"repo-a": [_key()], "repo-b": [], "repo-c": [_key()]})  # repo-b missing
    rec = Reconciler(reg, fed_root=tmp_path, forge=forge, key_provider=lambda _id: "ssh-ed25519 AA")
    plan = rec.plan(["forge"])
    assert [(a.op, a.detail["repo"]) for a in plan.actions] == [("register-deploy-key", "repo-b")]
    # and the bogus comma-joined target never appears
    assert not any("," in a.detail["repo"] for a in plan.actions)
    rec.apply(["forge"], skip_canary=True)
    assert rec.plan(["forge"]).is_empty


# --------------------------------------------------------------------------- #
# Doctor C5 — same parser, same result (no divergence).
# --------------------------------------------------------------------------- #


def test_doctor_c5_comma_string_all_present_is_clean(tmp_path) -> None:
    reg = _reg(tmp_path)
    forge = FakeForge({r: [_key()] for r in ("repo-a", "repo-b", "repo-c")})
    wp = FakeWoodpecker(repos=[])
    report = Doctor(reg, fed_root=tmp_path, woodpecker=wp, forge=forge).run(["forge"])
    assert not any(f.check == "C5" for f in report.findings)


def test_doctor_c5_comma_string_missing_subset_reds_only_that_repo(tmp_path) -> None:
    reg = _reg(tmp_path)
    forge = FakeForge({"repo-a": [_key()], "repo-b": [], "repo-c": [_key()]})
    wp = FakeWoodpecker(repos=[])
    report = Doctor(reg, fed_root=tmp_path, woodpecker=wp, forge=forge).run(["forge"])
    c5 = [f for f in report.findings if f.check == "C5"]
    assert [f.evidence["repo"] for f in c5] == ["repo-b"]
