mod common;

use axum::http::StatusCode;
use tower::ServiceExt;

/// Write a blob straight into the harness storage root at `key`, bypassing the
/// upload handlers — the only way to land a key whose extension resolves to the
/// `application/octet-stream` fallback (uploads always mint image extensions).
fn write_blob(h: &common::Harness, key: &str, bytes: &[u8]) {
    let path = h._storage_dir.path().join(key);
    std::fs::create_dir_all(path.parent().unwrap()).unwrap();
    std::fs::write(path, bytes).unwrap();
}

#[sqlx::test(migrations = "./migrations")]
async fn octet_stream_blobs_are_served_as_attachment(pool: sqlx::PgPool) {
    // A blob with an unknown extension serves as application/octet-stream. Such a
    // body could be crafted HTML/JS, so it must never render inline: force a
    // download with Content-Disposition: attachment (nosniff is already set).
    let h = common::harness(pool);
    write_blob(&h, "misc/blob.bin", b"\x00\x01not-an-image");

    let resp = h
        .app
        .oneshot(common::get("/api/v1/files/misc/blob.bin"))
        .await
        .unwrap();
    assert_eq!(resp.status(), StatusCode::OK);
    assert_eq!(
        resp.headers().get("content-type").unwrap(),
        "application/octet-stream"
    );
    assert_eq!(
        resp.headers().get("content-disposition").unwrap(),
        "attachment"
    );
}

#[sqlx::test(migrations = "./migrations")]
async fn image_blobs_are_served_inline(pool: sqlx::PgPool) {
    // Regression guard: known image types keep rendering inline (no attachment
    // disposition), so covers/pages still display in the reader.
    let h = common::harness(pool);
    write_blob(&h, "misc/pic.png", &common::fake_png_bytes());

    let resp = h
        .app
        .oneshot(common::get("/api/v1/files/misc/pic.png"))
        .await
        .unwrap();
    assert_eq!(resp.status(), StatusCode::OK);
    assert_eq!(resp.headers().get("content-type").unwrap(), "image/png");
    assert!(
        resp.headers().get("content-disposition").is_none(),
        "images must render inline, not download"
    );
}
