"""Fake-surface reconciler contract tests (SPEC §6.1).

Whole sync lifecycles against in-proc FakeWoodpecker/FakeForge/FakeHost:
``plan → apply → plan`` empty; injected drift (wrong scope, missing key, wrong
perm) detected then fixed; deploy-key pubkey sourced from an existing repo (no
store); never-delete (an undeclared live secret is NOT removed by apply); held
entries never armed.
"""

from __future__ import annotations

from mgf.secrets.forge import DeployKey
from mgf.secrets.hosts import HostStat
from mgf.secrets.registry import load
from mgf.secrets.sync import Reconciler
from tests._fakes import FakeForge, FakeHost, FakeWoodpecker

FAKE_VALUE = b"fixture-value-never-real"


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


def _rec(reg, tmp_path, **clients):
    return Reconciler(reg, fed_root=tmp_path, value_provider=lambda _id: FAKE_VALUE, **clients)


ORG = """\
[org_secret_a]
family = "mgf"
kind = "api-token"
purpose = "a shared org secret"
consumers = ["clone"]
recovery = "re-mint"
state = "active"
policy = { allowed_repos = "*", blast_radius = "low" }
rotation = { class = "token", staged = true }
verify = { probe = "forge-auth" }
surfaces = [ { type = "woodpecker-org-secret", events = ["push", "tag"] } ]
"""


# --------------------------------------------------------------------------- #
# plan → apply → plan empty.
# --------------------------------------------------------------------------- #


def test_missing_org_secret_created_then_idempotent(tmp_path) -> None:
    reg = _reg(tmp_path, ORG)
    wp = FakeWoodpecker(org_secrets={}, repos=[])  # secret absent
    rec = _rec(reg, tmp_path, woodpecker=wp)
    plan = rec.plan(["woodpecker"])
    assert [a.op for a in plan.actions] == ["create-secret"]
    # apply, then re-plan is empty (idempotent)
    report = rec.apply(["woodpecker"], skip_canary=True)
    assert report.ok() and len(report.applied) == 1
    assert rec.plan(["woodpecker"]).is_empty
    # and the created secret carries the exact declared scope
    assert wp.org_secret_states()["org_secret_a"].events == frozenset({"push", "tag"})


def test_scope_drift_detected_and_fixed(tmp_path) -> None:
    reg = _reg(tmp_path, ORG)
    wp = FakeWoodpecker(org_secrets={"org_secret_a": {"push"}}, repos=[])  # missing 'tag'
    rec = _rec(reg, tmp_path, woodpecker=wp)
    plan = rec.plan(["woodpecker"])
    assert [a.op for a in plan.actions] == ["update-secret"]
    assert plan.actions[0].detail["events"] == ["push", "tag"]
    rec.apply(["woodpecker"], skip_canary=True)
    assert rec.plan(["woodpecker"]).is_empty
    assert wp.org_secret_states()["org_secret_a"].events == frozenset({"push", "tag"})


def test_sync_ignores_declared_images_no_action(tmp_path) -> None:
    """SPEC-P3 FIX-2: sync no longer manages image restrictions. A declared `images`
    is IGNORED (Woodpecker rejects dotted tags + a fleet-wide `python` isolates
    nothing) — a secret already at the right event scope yields NO action, and a live
    (out-of-band) restriction is preserved, never cleared."""
    reg = _reg(
        tmp_path,
        """\
[devpi_password]
family = "mgf"
kind = "password"
purpose = "publish secret; a declared images list must be ignored by sync"
consumers = ["publish"]
recovery = "reset"
state = "active"
policy = { allowed_repos = "*", blast_radius = "org-wide" }
rotation = { class = "password", staged = true }
verify = { probe = "devpi-login" }
surfaces = [ { type = "woodpecker-org-secret", events = ["tag"], images = ["python:3.12-slim"] } ]
""",
    )
    # live secret at the right scope with an out-of-band image restriction present.
    wp = FakeWoodpecker(
        org_secrets={"devpi_password": {"tag"}}, org_images={"devpi_password": ["ghcr.io/x"]}
    )
    rec = _rec(reg, tmp_path, woodpecker=wp)
    assert rec.plan(["woodpecker"]).is_empty  # declared images ignored → no action
    # and a scope fix preserves the live images rather than clearing them.
    wp2 = FakeWoodpecker(
        org_secrets={"devpi_password": {"push"}}, org_images={"devpi_password": ["ghcr.io/x"]}
    )
    rec2 = _rec(reg, tmp_path, woodpecker=wp2)
    rec2.apply(["woodpecker"], skip_canary=True)
    assert wp2.org_secret_states()["devpi_password"].events == frozenset({"tag"})
    assert wp2.org_secret_states()["devpi_password"].images == ("ghcr.io/x",)  # preserved


def test_forge_coverage_gap_registered_then_idempotent(tmp_path) -> None:
    reg = _reg(
        tmp_path,
        """\
[fleet_key]
family = "mgf"
kind = "ssh-deploy-key"
purpose = "fleet clone key"
consumers = ["clone"]
recovery = "re-add"
state = "active"
policy = { allowed_repos = "*", blast_radius = "read" }
rotation = { class = "static-key", staged = true }
verify = { probe = "forge-key-fingerprint" }
surfaces = [ { type = "forge-deploy-key", repos = "ALL_MANAGED", readonly = true, title = "ci-clone" } ]
""",
    )
    key = DeployKey(title="ci-clone", fingerprint="SHA256:a", read_only=True)
    wp = FakeWoodpecker(repos=[(1, "repo-a"), (2, "repo-b")])
    forge = FakeForge({"repo-a": [key], "repo-b": []})  # repo-b missing the fleet key
    rec = _rec(
        reg, tmp_path, woodpecker=wp, forge=forge, key_provider=lambda _id: "ssh-ed25519 AAAA"
    )
    plan = rec.plan(["forge"])
    assert [(a.op, a.detail["repo"]) for a in plan.actions] == [("register-deploy-key", "repo-b")]
    rec.apply(["forge"], skip_canary=True)
    assert rec.plan(["forge"]).is_empty
    assert any(k.title == "ci-clone" for k in forge.repo_deploy_keys("repo-b"))


def test_forge_coverage_matches_by_fingerprint_not_title(tmp_path) -> None:
    """SPEC-P3 FIX (title-vs-fingerprint): a repo carrying the fleet key's PUBLIC-KEY
    FINGERPRINT under a DIFFERENT title is COVERED. Matching by title alone both
    false-flags such a repo AND 422s on apply (re-adding an already-present key) —
    mgf-uitest-web carries the fleet ci-clone key titled 'woodpecker-ci-clone'."""
    reg = _reg(
        tmp_path,
        """\
[fleet_key]
family = "mgf"
kind = "ssh-deploy-key"
purpose = "fleet clone key"
consumers = ["clone"]
recovery = "re-add"
state = "active"
policy = { allowed_repos = "*", blast_radius = "read" }
rotation = { class = "static-key", staged = true }
verify = { probe = "forge-key-fingerprint" }
surfaces = [ { type = "forge-deploy-key", repos = "ALL_MANAGED", readonly = true, title = "ci-clone-2026-07-12" } ]
""",
    )
    pub = "ssh-ed25519 AAAAfleet ci-clone"
    titled = DeployKey("ci-clone-2026-07-12", "SHA256:FLEET", read_only=True, key=pub)
    # SAME fingerprint (content), DIFFERENT title — must count as covered:
    by_fp = DeployKey("woodpecker-ci-clone", "SHA256:FLEET", read_only=True, key=pub)
    wp = FakeWoodpecker(repos=[(1, "has-titled"), (2, "has-by-fp"), (3, "genuine-gap")])
    forge = FakeForge({"has-titled": [titled], "has-by-fp": [by_fp], "genuine-gap": []})
    rec = _rec(reg, tmp_path, woodpecker=wp, forge=forge)
    plan = rec.plan(["forge"])
    # ONLY genuine-gap needs registration; has-by-fp is covered by fingerprint,
    # NOT flagged (and never re-registered, which would 422 on the live forge).
    assert [(a.op, a.detail["repo"]) for a in plan.actions] == [
        ("register-deploy-key", "genuine-gap")
    ]


def test_register_sources_pubkey_from_existing_repo_no_store(tmp_path) -> None:
    """SPEC-P3 FIX-1: registering a missing repo's deploy key sources the PUBLIC key
    from a repo that already carries the same titled key — NO store entry, NO private
    key, NO --key provider (the fleet clone key's private half is a Woodpecker secret,
    not in the store)."""
    reg = _reg(
        tmp_path,
        """\
[codeberg_ssh_clone_key]
family = "mgf"
kind = "ssh-deploy-key"
purpose = "fleet clone key; private half is a Woodpecker secret, not in the store"
consumers = ["clone"]
recovery = "re-add"
state = "active"
policy = { allowed_repos = "*", blast_radius = "read" }
rotation = { class = "static-key", staged = true }
verify = { probe = "forge-key-fingerprint" }
surfaces = [ { type = "forge-deploy-key", repos = "ALL_MANAGED", readonly = true, title = "ci-clone-2026-07-12" } ]
""",
    )
    pub = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5REALPUBLICKEY ci-clone"
    have = DeployKey(title="ci-clone-2026-07-12", fingerprint="SHA256:z", read_only=True, key=pub)
    wp = FakeWoodpecker(repos=[(1, "has-key-repo"), (2, "missing-repo")])
    forge = FakeForge({"has-key-repo": [have], "missing-repo": []})
    # NO store_root, NO value_provider for the key, NO key_provider.
    rec = Reconciler(reg, fed_root=tmp_path, woodpecker=wp, forge=forge)
    rec.apply(["forge"], skip_canary=True)  # must NOT raise "no stored value"
    registered = [
        k for k in forge.repo_deploy_keys("missing-repo") if k.title == "ci-clone-2026-07-12"
    ]
    assert registered and registered[0].key == pub  # reused the public half verbatim
    assert rec.plan(["forge"]).is_empty


def test_host_perm_and_owner_drift_fixed(tmp_path) -> None:
    reg = _reg(
        tmp_path,
        """\
[server_env]
family = "mgf"
kind = "password"
purpose = "a root-600 server env file"
consumers = ["woodpecker server"]
recovery = "reset"
state = "active"
policy = { allowed_repos = "*", blast_radius = "low" }
rotation = { class = "password", staged = true }
verify = { probe = "server-env-present" }
surfaces = [ { type = "host-file", host = "h1", path = "/opt/x/.env", mode = "0600", owner = "root" } ]
""",
    )
    hosts = FakeHost({("h1", "/opt/x/.env"): HostStat("present", mode="644", owner="ubuntu")})
    rec = _rec(reg, tmp_path, hosts=hosts)
    plan = rec.plan(["hosts"])
    assert sorted(a.op for a in plan.actions) == ["chmod", "chown"]
    rec.apply(["hosts"], skip_canary=True)
    assert rec.plan(["hosts"]).is_empty
    st = hosts.stat("h1", "/opt/x/.env")
    assert st.mode == "0600" and st.owner == "root"


# --------------------------------------------------------------------------- #
# never-delete + held-inviolable.
# --------------------------------------------------------------------------- #


def test_undeclared_live_secret_is_never_deleted(tmp_path) -> None:
    reg = _reg(tmp_path, ORG)
    wp = FakeWoodpecker(
        org_secrets={"org_secret_a": {"push", "tag"}, "ungoverned_x": {"push"}}, repos=[]
    )
    rec = _rec(reg, tmp_path, woodpecker=wp)
    # nothing to do for the declared secret; the undeclared one is NOT in any action.
    plan = rec.plan(["woodpecker"])
    assert plan.is_empty
    rec.apply(["woodpecker"], skip_canary=True)
    # the ungoverned secret is still live — sync never removed it (it's a doctor C3).
    assert "ungoverned_x" in wp.org_secret_states()


def test_held_entry_is_never_armed(tmp_path) -> None:
    reg = _reg(
        tmp_path,
        """\
[held_secret]
family = "mgf"
kind = "api-token"
purpose = "held deploy secret — never armed by sync"
consumers = ["deploy"]
recovery = "arm on founder word only"
state = "held"
policy = { allowed_repos = "*", blast_radius = "deploy" }
rotation = { class = "token", staged = true }
verify = { probe = "repo-scope-match" }
surfaces = [ { type = "woodpecker-org-secret", events = ["deployment"] } ]
""",
    )
    wp = FakeWoodpecker(org_secrets={}, repos=[])  # not live
    rec = _rec(reg, tmp_path, woodpecker=wp)
    plan = rec.plan(["woodpecker"])
    assert plan.is_empty  # NO create action for a held entry
    assert any(n.kind == "held" and n.id == "held_secret" for n in plan.notes)
    rec.apply(["woodpecker"], skip_canary=True)
    assert "held_secret" not in wp.org_secret_states()  # never armed


def test_retiring_entry_not_reconciled(tmp_path) -> None:
    reg = _reg(
        tmp_path,
        ORG.replace('state = "active"', 'state = "retiring"'),
    )
    wp = FakeWoodpecker(org_secrets={}, repos=[])
    rec = _rec(reg, tmp_path, woodpecker=wp)
    plan = rec.plan(["woodpecker"])
    assert plan.is_empty
    assert any(n.kind == "retiring" and n.id == "org_secret_a" for n in plan.notes)
