use crate::web;
use actix_web::http::header::{AcceptEncoding, ContentEncoding, Encoding, Header};
use actix_web::{HttpRequest, HttpResponse};
use rebuilderd_common::errors::{Context, Error, format_err};
use rebuilderd_common::utils::{is_zstd_compressed, zstd_decompress};

pub mod v0;
pub mod v1;

pub async fn forward_compressed_data(
    request: HttpRequest,
    content_type: &str,
    data: Vec<u8>,
) -> web::Result<HttpResponse> {
    let mut builder = HttpResponse::Ok();

    builder
        .content_type(content_type)
        .append_header(("X-Content-Type-Options", "nosniff"))
        .append_header(("Content-Security-Policy", "default-src 'none'"));

    if is_zstd_compressed(data.as_slice()) {
        let client_supports_zstd = AcceptEncoding::parse(&request)
            .ok()
            .and_then(|a| a.negotiate([Encoding::zstd()].iter()))
            .map(|e| e == Encoding::zstd())
            .unwrap_or(false);

        if client_supports_zstd {
            builder.insert_header(ContentEncoding::Zstd);

            let resp = builder.body(data);
            Ok(resp)
        } else {
            let decoded_log = zstd_decompress(data.as_slice())
                .await
                .map_err(Error::from)?;

            let resp = builder.body(decoded_log);
            Ok(resp)
        }
    } else {
        let resp = builder.body(data);
        Ok(resp)
    }
}

pub fn header<'a>(req: &'a HttpRequest, key: &str) -> rebuilderd_common::errors::Result<&'a str> {
    let value = req
        .headers()
        .get(key)
        .ok_or_else(|| format_err!("Missing header"))?
        .to_str()
        .context("Failed to decode header value")?;

    Ok(value)
}
