//! Testing support for sending various HTTP header (referer, user-agent).
//
//
// To run tests while enabling printing to stdout/stderr
//
//    RUST_LOG=info cargo test --test headers -- --show-output
//
// What happens in this test:
//
//   - Start an axum HTTP server that serves the manifest and our media segments.
//
//   - Fetch the associated media content using dash-mpd-cli via "cargo run" with the --referer,
//   --user-agent, -add-header and --header options. Check that both the MPD manifest and a media
//   segment are retrieved with the expected headers.


pub mod common;
use fs_err as fs;
use std::env;
use std::time::Duration;
use tokio::net::TcpListener;
use assert_cmd::cargo::cargo_bin_cmd;
use axum::{routing::get, Router};
use axum::response::{Response, IntoResponse};
use axum::http::header::HeaderMap;
use axum::http::{header, StatusCode};
use axum::body::Body;
use dash_mpd::{MPD, Period, AdaptationSet, Representation, SegmentTemplate};
use anyhow::Result;
use common::{generate_minimal_mp4, setup_logging};


#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_headers() -> Result<()> {
    async fn send_mpd(headers: HeaderMap) -> impl IntoResponse {
        assert_eq!(headers["user-agent"], "MyFakeUserAgent/42.0");
        assert_eq!(headers["referer"], "https://twiddles.org/");
        assert_eq!(headers["x-twizzles"], "extra");
        assert_eq!(headers["x-foobles"], "bøzzles".as_bytes());

        let segment_template = SegmentTemplate {
            initialization: Some("/media/f1.mp4".to_string()),
            ..Default::default()
        };
        let rep = Representation {
            id: Some("1".to_string()),
            mimeType: Some("video/mp4".to_string()),
            codecs: Some("avc1.640028".to_string()),
            width: Some(1920),
            height: Some(800),
            bandwidth: Some(1980081),
            SegmentTemplate: Some(segment_template),
            ..Default::default()
        };
        let adapt = AdaptationSet {
            id: Some("1".to_string()),
            contentType: Some("video".to_string()),
            representations: vec!(rep),
            ..Default::default()
        };
        let period = Period {
            id: Some("1".to_string()),
            duration: Some(Duration::new(5, 0)),
            adaptations: vec!(adapt.clone()),
            ..Default::default()
        };
        let mpd = MPD {
            mpdtype: Some("static".to_string()),
            periods: vec!(period),
            ..Default::default()
        };
        let xml = quick_xml::se::to_string(&mpd).unwrap();
        ([(header::CONTENT_TYPE, "application/dash+xml")], xml)
    }

    async fn send_mp4(headers: HeaderMap) -> Response {
        assert_eq!(headers["user-agent"], "MyFakeUserAgent/42.0");
        assert_eq!(headers["referer"], "https://twiddles.org/");
        assert_eq!(headers["x-twizzles"], "extra");
        assert_eq!(headers["x-foobles"], "bøzzles".as_bytes());

        let data = generate_minimal_mp4();
        Response::builder()
            .status(StatusCode::OK)
            .header(header::CONTENT_TYPE, "video/mp4")
            .body(Body::from(data))
            .unwrap()
    }

    setup_logging();
    let app = Router::new()
        .route("/mpd", get(send_mpd))
        .route("/media/{seg}", get(send_mp4));
    let listener = TcpListener::bind("127.0.0.1:6661").await.unwrap();
    let backend = async {
        axum::serve(listener, app.into_make_service())
            .await
            .unwrap()
    };
    tokio::spawn(backend);
    tokio::time::sleep(Duration::from_millis(1000)).await;
    let outpath = env::temp_dir().join("referer.mp4");
    cargo_bin_cmd!()
        .args(["-v", "-v", "-v",
               "--referer", "https://twiddles.org/",
               "--user-agent", "MyFakeUserAgent/42.0",
               "--add-header", "X-FOOBLES:bøzzles",
               "--header", "X-Twizzles: extra",
               "-o", outpath.to_str().unwrap(),
               "http://localhost:6661/mpd"])
        .assert()
        .success();
    assert!(fs::metadata(outpath).is_ok());
    Ok(())
}
