use axum::http::{
    HeaderMap,
    header::{self, IF_NONE_MATCH},
};

use super::ContentEncoding;

pub trait HeaderMapExtended {
    fn has_etag(&self, etag: &str) -> bool;
    fn insert_etag(&mut self, etag: &str);

    fn insert_cache_control(&mut self, value: &str);
    fn insert_cache_control_must_revalidate(&mut self);

    fn insert_content_disposition_attachment(&mut self, filename: &str);

    fn insert_content_encoding(&mut self, encoding: ContentEncoding);

    fn insert_content_type_application_json(&mut self);
    fn insert_content_type_text_csv(&mut self);

    fn insert_vary_accept_encoding(&mut self);

    fn insert_deprecation(&mut self, sunset: &'static str);
}

impl HeaderMapExtended for HeaderMap {
    fn has_etag(&self, etag: &str) -> bool {
        self.get(IF_NONE_MATCH).is_some_and(|v| {
            let s = v.as_bytes();
            // Match both quoted and unquoted: "etag" or etag
            s == etag.as_bytes()
                || (s.len() == etag.len() + 2
                    && s[0] == b'"'
                    && s[s.len() - 1] == b'"'
                    && &s[1..s.len() - 1] == etag.as_bytes())
        })
    }

    fn insert_etag(&mut self, etag: &str) {
        self.insert(header::ETAG, format!("\"{etag}\"").parse().unwrap());
    }

    fn insert_cache_control(&mut self, value: &str) {
        self.insert(header::CACHE_CONTROL, value.parse().unwrap());
    }

    fn insert_cache_control_must_revalidate(&mut self) {
        self.insert_cache_control("public, max-age=1, must-revalidate");
    }

    fn insert_content_disposition_attachment(&mut self, filename: &str) {
        self.insert(
            header::CONTENT_DISPOSITION,
            format!("attachment; filename=\"{filename}\"")
                .parse()
                .unwrap(),
        );
    }

    fn insert_content_encoding(&mut self, encoding: ContentEncoding) {
        if let Some(value) = encoding.header_value() {
            self.insert(header::CONTENT_ENCODING, value);
            self.insert_vary_accept_encoding();
        }
    }

    fn insert_content_type_application_json(&mut self) {
        self.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
    }

    fn insert_content_type_text_csv(&mut self) {
        self.insert(header::CONTENT_TYPE, "text/csv".parse().unwrap());
    }

    fn insert_vary_accept_encoding(&mut self) {
        self.insert(header::VARY, "Accept-Encoding".parse().unwrap());
    }

    fn insert_deprecation(&mut self, sunset: &'static str) {
        self.insert("Deprecation", "true".parse().unwrap());
        self.insert("Sunset", sunset.parse().unwrap());
    }
}
