"""Comment attachments: upload + serve, with the security posture proven —
type allow-list, magic-byte agreement, our-names-only serving (the traversal
guard), size cap, and visibility re-checked through the owning item."""

from app.services import attachments as att
from tests.conftest import OWNER, as_user

PNG = b"\x89PNG\r\n\x1a\n" + b"\x00" * 24        # minimal png-shaped bytes
PDF = b"%PDF-1.4\n%fake\n"


def _world(client, kit):
    as_user(client, OWNER)
    r = client.post("/api/punchlists", json={"title": "Attach world"})
    pid = r.json()["id"]
    r = client.post(f"/api/punchlists/{pid}/items",
                    json={"template_key": "ga4_admin_access",
                          "variables": {"who_needs_access": ["a@x.com"]}})
    iid = r.json()["id"]
    kit.member("cleo", "member")
    kit.grant("cleo", pid, "member")
    return pid, iid


def _up(client, iid, name, data, ctype="application/octet-stream"):
    return client.post(f"/api/items/{iid}/attachments",
                       files={"file": (name, data, ctype)})


def test_upload_and_serve_roundtrip(client, kit):
    _, iid = _world(client, kit)
    as_user(client, "cleo")
    r = _up(client, iid, "brand guide.png", PNG)
    assert r.status_code == 201, r.text
    a = r.json()["attachment"]
    assert a["is_image"] and a["markdown"].startswith("![")
    assert a["display"] == "brand guide.png"

    got = client.get(a["url"])
    assert got.status_code == 200
    assert got.headers["content-type"].startswith("image/png")
    assert got.headers["x-content-type-options"] == "nosniff"
    assert got.content == PNG

    # a PDF embeds as a LINK, not an image
    r = _up(client, iid, "guide.pdf", PDF)
    assert r.status_code == 201 and r.json()["attachment"]["markdown"].startswith("[")


def test_type_and_content_discipline(client, kit):
    _, iid = _world(client, kit)
    as_user(client, "cleo")
    # script-capable types never accepted
    r = _up(client, iid, "evil.svg", b"<svg onload=alert(1)>")
    assert r.status_code == 400 and "UNSUPPORTED_TYPE" in r.text
    r = _up(client, iid, "page.html", b"<html>")
    assert r.status_code == 400
    # extension lying about its contents
    r = _up(client, iid, "notreally.png", b"MZ\x90\x00 definitely not a png")
    assert r.status_code == 400 and "CONTENT_MISMATCH" in r.text
    # over the cap
    r = _up(client, iid, "big.png", PNG + b"\x00" * att.MAX_BYTES)
    assert r.status_code == 413 and "TOO_LARGE" in r.text


def test_serving_is_visibility_gated_and_traversal_proof(client, kit):
    _, iid = _world(client, kit)
    as_user(client, "cleo")
    url = _up(client, iid, "shot.png", PNG).json()["attachment"]["url"]

    # a member with no grant sees 404 (never 403 — ids must not be confirmed)
    kit.member("mallory", "member")
    as_user(client, "mallory")
    assert client.get(url).status_code == 404
    assert client.post(f"/api/items/{iid}/attachments",
                       files={"file": ("x.png", PNG, "image/png")}).status_code == 404

    # only our uuid.ext shape ever resolves. Non-matching names 404 at the
    # handler; an encoded-slash traversal doesn't even route here (the decoded
    # path misses the route and lands on the SPA shell) — the invariant is
    # that no shape but ours ever yields file bytes.
    as_user(client, "cleo")
    base = url.rsplit("/", 1)[0]
    for bad in ("a.png", "x" * 32 + ".png", "deadbeef.exe", "deadbeef" * 4 + ".exe"):
        assert client.get(f"{base}/{bad}").status_code == 404
    r = client.get(f"{base}/..%2F..%2Fapp.db")
    assert r.headers["content-type"].startswith(("application/json", "text/html"))
    assert not r.content.startswith((b"\x89PNG", b"SQLite"))
