use crc_all::Crc;
use fastly::http::StatusCode;
use fastly::{Error, Request, Response};
use regex::Regex;

const BACKEND_NAME: &str = "origin_0";

#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
    log_fastly::init_simple("my_log", log::LevelFilter::Info);
    fastly::log::set_panic_endpoint("my_log")?;

    if let Some((id, expected_crc_str)) = get_product_id_and_crc32(req.get_path()) {
        // Calculate CRC-32/BZIP2, which is used by Fastly VCL function digest.hash_crc32()
        let mut crc32_bzip2 = Crc::<u32>::new(0x04c11db7, 32, 0xffffffff, 0xffffffff, false);
        let crc_u32 = crc32_bzip2.update(id.as_bytes());

        // Get first two bytes of CRC32 hash value to a string
        let crc_bytes_vec = (crc_u32 as u16).to_le_bytes();
        let calculated_crc_str = format!("{:02x}{:02x}", crc_bytes_vec[0], crc_bytes_vec[1]);

        if expected_crc_str != calculated_crc_str {
            log::info!(
                "Block Request, crc is {}, expecting {}",
                calculated_crc_str,
                expected_crc_str
            );

            let resp_block = Response::from_status(StatusCode::BAD_REQUEST)
                .with_body("Not a valid product code\n");

            return Ok(resp_block);
        }

        log::info!("Passed checksum based on CRC32 hash");
    }

    // Send request to backend
    let resp = req.send(BACKEND_NAME)?;

    Ok(resp)
}

/// Get product ID and CRC string from URL path
fn get_product_id_and_crc32(url: &str) -> Option<(&str, &str)> {
    let id_crc_cap = Regex::new(r"^/products/(\d+)(....)$")
        .unwrap()
        .captures(url)?;

    let id = id_crc_cap.get(1)?.as_str();
    let crc = id_crc_cap.get(2)?.as_str();

    Some((id, crc))
}