"""Per-kind probes — presence, JWT decode, skip semantics (SPEC §4 probe verb)."""

from __future__ import annotations

import base64
import json
import time

from mgf.secrets.context import Context
from mgf.secrets.forge import DeployKey
from mgf.secrets.hosts import HostStat
from mgf.secrets.probes import run_probe
from mgf.secrets.registry import load
from tests._fakes import FakeForge, FakeHost


def _entry(tmp_path, text, entry_id):
    p = tmp_path / "SECRETS.toml"
    p.write_text(text, encoding="utf-8")
    return load([p]).get(entry_id)


LOCAL = """\
[t]
family = "mgf"
kind = "password"
purpose = "p"
consumers = ["c"]
recovery = "r"
state = "active"
policy = { allowed_repos = "*", blast_radius = "b" }
rotation = { class = "password", staged = true }
verify = { probe = "login" }
surfaces = [ { type = "local-file", repo = "mgf", path = "tokens/t.txt", mode = "0600" } ]
"""


def test_probe_local_present_ok(tmp_path) -> None:
    e = _entry(tmp_path, LOCAL, "t")
    f = tmp_path / "mgf" / "my_stuff" / "tokens" / "t.txt"
    f.parent.mkdir(parents=True)
    f.write_text("v", encoding="utf-8")
    r = run_probe(e, Context(fed_root=tmp_path))
    assert r.status == "ok" and r.exit_code() == 0


def test_probe_local_missing_is_finding(tmp_path) -> None:
    e = _entry(tmp_path, LOCAL, "t")
    r = run_probe(e, Context(fed_root=tmp_path))
    assert r.status == "finding" and r.exit_code() == 1


JWT = LOCAL.replace('kind = "password"', 'kind = "jwt-minted"')


def _jwt(days):
    def b64(o):
        return base64.urlsafe_b64encode(json.dumps(o).encode()).rstrip(b"=").decode()

    return f"{b64({'alg': 'HS256'})}.{b64({'exp': int(time.time()) + days * 86400})}.s"


def test_probe_jwt_valid_and_expired(tmp_path) -> None:
    e = _entry(tmp_path, JWT, "t")
    f = tmp_path / "mgf" / "my_stuff" / "tokens" / "t.txt"
    f.parent.mkdir(parents=True)
    f.write_text(_jwt(30), encoding="utf-8")
    assert run_probe(e, Context(fed_root=tmp_path)).status == "ok"
    f.write_text(_jwt(-1), encoding="utf-8")
    r = run_probe(e, Context(fed_root=tmp_path))
    assert r.status == "finding" and "EXPIRED" in r.message


DEPLOY = """\
[k]
family = "mgf"
kind = "ssh-deploy-key"
purpose = "p"
consumers = ["c"]
recovery = "r"
state = "active"
policy = { allowed_repos = "*", blast_radius = "b" }
rotation = { class = "static-key", staged = true }
verify = { probe = "fp" }
surfaces = [ { type = "forge-deploy-key", repos = "ALL_MANAGED", readonly = true, title = "ci-clone" } ]
"""


def test_probe_deploy_key_skips_without_forge_client(tmp_path) -> None:
    e = _entry(tmp_path, DEPLOY, "k")
    assert run_probe(e, Context(fed_root=tmp_path)).status == "skipped"


def test_probe_deploy_key_ok_with_forge(tmp_path) -> None:
    e = _entry(tmp_path, DEPLOY, "k")
    ctx = Context(fed_root=tmp_path, forge=FakeForge({"x": [DeployKey("ci-clone", "fp", True)]}))
    assert run_probe(e, ctx).status == "ok"


HOSTSA = """\
[sa]
family = "mgf"
kind = "service-account"
purpose = "p"
consumers = ["c"]
recovery = "r"
state = "active"
policy = { allowed_repos = "*", blast_radius = "b" }
rotation = { class = "sa", staged = true }
verify = { probe = "oo" }
surfaces = [ { type = "host-file", host = "h1", path = "/etc/mgf/x", mode = "0600", owner = "root" } ]
"""


def test_probe_service_account_host(tmp_path) -> None:
    e = _entry(tmp_path, HOSTSA, "sa")
    assert run_probe(e, Context(fed_root=tmp_path)).status == "skipped"
    ctx = Context(
        fed_root=tmp_path,
        hosts=FakeHost({("h1", "/etc/mgf/x"): HostStat("present", mode="600", owner="root")}),
    )
    assert run_probe(e, ctx).status == "ok"
    ctx = Context(fed_root=tmp_path, hosts=FakeHost({("h1", "/etc/mgf/x"): HostStat("missing")}))
    assert run_probe(e, ctx).status == "finding"
    # unreachable (present-but-unverifiable) is skipped, never a finding
    ctx = Context(
        fed_root=tmp_path, hosts=FakeHost({("h1", "/etc/mgf/x"): HostStat("unreachable")})
    )
    assert run_probe(e, ctx).status == "skipped"


# --------------------------------------------------------------------------- #
# P2 live probes — does the STORED VALUE authenticate? (2026-07-30)
# --------------------------------------------------------------------------- #


class TestLiveProbes:
    """`devpi_password` sat in the store returning 401 on publish while its probe
    reported OK, because the probe checked *file presence*. These pin the three
    properties that make a live probe worth trusting.
    """

    def _entry(self, probe: str, kind: str = "password"):
        from mgf.secrets.model import Entry

        return Entry(
            id="e",
            family="mgf",
            kind=kind,
            purpose="p",
            consumers=[],
            recovery="r",
            state="active",
            surfaces=[],
            policy={},
            rotation={},
            verify={"probe": probe},
        )

    def test_unreachable_is_unverifiable_never_ok(self, monkeypatch) -> None:
        """A probe that could not look must not report clean (F-36)."""
        from mgf.secrets import probes

        monkeypatch.setattr(probes, "_http_status_body", lambda *a, **k: None)
        r = probes.run_live_probe(self._entry("devpi-login"), "pw")
        assert r.status == "unverifiable"
        assert "unreachable" in r.message
        assert r.exit_code() == 0, "unknown is not a finding either"

    def test_401_is_a_finding(self, monkeypatch) -> None:
        from mgf.secrets import probes

        monkeypatch.setattr(probes, "_http_status_body", lambda *a, **k: 401)
        r = probes.run_live_probe(self._entry("devpi-login"), "pw")
        assert r.status == "finding"
        assert r.exit_code() == 1
        assert "did NOT authenticate" in r.message

    def test_200_is_ok(self, monkeypatch) -> None:
        from mgf.secrets import probes

        monkeypatch.setattr(probes, "_http_status_body", lambda *a, **k: 200)
        assert probes.run_live_probe(self._entry("devpi-login"), "pw").status == "ok"

    def test_devpi_probe_uses_the_login_endpoint_not_api(self, monkeypatch) -> None:
        """The regression that nearly shipped.

        `/+api` returns **200 for every caller** — wrong password, empty password,
        no header at all. The first draft of this probe used it and passed against
        a garbage credential. Asserting the URL is what stops that coming back.
        """
        from mgf.secrets import probes

        seen: dict[str, str] = {}

        def _capture(url, *, body, headers):
            seen["url"] = url
            return 200

        monkeypatch.setattr(probes, "_http_status_body", _capture)
        probes.run_live_probe(self._entry("devpi-login"), "pw")
        assert seen["url"].endswith("/+login")
        assert "+api" not in seen["url"]

    def test_forge_probe_avoids_slash_user(self, monkeypatch) -> None:
        """Family tokens are least-privilege and correctly 403 on /user; probing it
        would report a healthy token as dead."""
        from mgf.secrets import probes

        seen: dict[str, str] = {}
        monkeypatch.setattr(
            probes, "_http_status", lambda url, **k: (seen.__setitem__("url", url), 200)[1]
        )
        probes.run_live_probe(self._entry("forge-auth", "api-token"), "tok")
        assert "/repos/" in seen["url"]
        assert not seen["url"].endswith("/user")

    def test_undeclared_probe_is_skipped_by_name(self) -> None:
        """A declared probe with no implementation is reported, never silently passed."""
        from mgf.secrets import probes

        r = probes.run_live_probe(self._entry("openstack-token"), "v")
        assert r.status == "skipped"
        assert "openstack-token" in r.message
        assert "NOT checked" in r.message

    def test_compound_probe_reports_the_part_it_did_not_cover(self, monkeypatch) -> None:
        """`devpi-login+org-scope-match` checks the login half only. Say so —
        a partial check must never read as a whole one."""
        from mgf.secrets import probes

        monkeypatch.setattr(probes, "_http_status_body", lambda *a, **k: 200)
        r = probes.run_live_probe(self._entry("devpi-login+org-scope-match"), "pw")
        assert r.status == "ok"
        assert r.evidence["not_covered"] == "org-scope-match"
        assert "not covered" in r.message

    def test_no_declared_probe_is_skipped(self) -> None:
        from mgf.secrets import probes
        from mgf.secrets.model import Entry

        e = Entry(
            id="e",
            family="mgf",
            kind="password",
            purpose="p",
            consumers=[],
            recovery="r",
            state="active",
            surfaces=[],
            policy={},
            rotation={},
            verify={},
        )
        assert probes.run_live_probe(e, "v").status == "skipped"

    def test_the_value_never_reaches_the_message_or_evidence(self, monkeypatch) -> None:
        """AG-18 over the live path, including the failure branch."""
        from mgf.secrets import probes

        secret = "CANARY_LIVE_PROBE_VALUE_zz9"
        for code in (200, 401, None):
            monkeypatch.setattr(probes, "_http_status_body", lambda *a, _c=code, **k: _c)
            r = probes.run_live_probe(self._entry("devpi-login"), secret)
            assert secret not in r.message
            assert secret not in str(r.evidence)
            assert secret not in str(r.to_json())
