def test_serve_site(client, auth_headers):
    client.put("/api/sites/mypage", content=b"<h1>Hi</h1>", headers=auth_headers)
    resp = client.get("/mypage")
    assert resp.status_code == 200
    assert resp.headers["content-type"].startswith("text/html")
    assert "<h1>Hi</h1>" in resp.text


def test_serve_404(client):
    resp = client.get("/nonexistent")
    assert resp.status_code == 404
    assert resp.text == "Not found"


def test_serve_invalid_name(client):
    resp = client.get("/../../etc/passwd")
    assert resp.status_code == 404


def test_serve_site_with_hyphen(client, auth_headers):
    client.put("/api/sites/my-page", content=b"<p>hyphens</p>", headers=auth_headers)
    resp = client.get("/my-page")
    assert resp.status_code == 200
    assert "<p>hyphens</p>" in resp.text


def test_serve_site_with_underscore(client, auth_headers):
    client.put(
        "/api/sites/my_page", content=b"<p>underscores</p>", headers=auth_headers
    )
    resp = client.get("/my_page")
    assert resp.status_code == 200


def test_serve_updated_content(client, auth_headers):
    client.put("/api/sites/page", content=b"<p>v1</p>", headers=auth_headers)
    client.put("/api/sites/page", content=b"<p>v2</p>", headers=auth_headers)
    resp = client.get("/page")
    assert "<p>v2</p>" in resp.text


def test_no_csp_on_served_site(client, auth_headers):
    client.put("/api/sites/testsite", content=b"<h1>Hi</h1>", headers=auth_headers)
    resp = client.get("/testsite")
    assert "Content-Security-Policy" not in resp.headers


def test_serve_site_has_etag(client, auth_headers):
    client.put("/api/sites/page1", content=b"<h1>Hi</h1>", headers=auth_headers)
    resp = client.get("/page1")
    assert resp.status_code == 200
    assert "ETag" in resp.headers
    assert resp.headers["ETag"].startswith('"') and resp.headers["ETag"].endswith('"')


def test_serve_site_304_not_modified(client, auth_headers):
    client.put("/api/sites/page2", content=b"<h1>Hi</h1>", headers=auth_headers)
    resp = client.get("/page2")
    etag = resp.headers["ETag"]
    resp2 = client.get("/page2", headers={"If-None-Match": etag})
    assert resp2.status_code == 304
    assert resp2.headers["ETag"] == etag
    assert resp2.content == b""


def test_serve_site_etag_mismatch(client, auth_headers):
    client.put("/api/sites/page3", content=b"<h1>Hi</h1>", headers=auth_headers)
    resp = client.get("/page3", headers={"If-None-Match": '"stale"'})
    assert resp.status_code == 200
    assert "<h1>Hi</h1>" in resp.text


def test_serve_site_etag_changes_on_update(client, auth_headers):
    client.put("/api/sites/page4", content=b"<p>v1</p>", headers=auth_headers)
    etag1 = client.get("/page4").headers["ETag"]
    client.put("/api/sites/page4", content=b"<p>v2</p>", headers=auth_headers)
    etag2 = client.get("/page4").headers["ETag"]
    assert etag1 != etag2


def test_serve_site_cache_control(client, auth_headers):
    client.put("/api/sites/page5", content=b"<h1>Hi</h1>", headers=auth_headers)
    resp = client.get("/page5")
    assert resp.headers["Cache-Control"] == "no-cache"


def test_api_not_caught_by_site_router(client, auth_headers):
    """API routes must not be intercepted by the catch-all site router."""
    resp = client.get("/api/sites", headers=auth_headers)
    assert resp.status_code == 200
    assert "sites" in resp.json()
