use mumu::parser::interpreter::{Interpreter, DynamicFnInfo};
use mumu::parser::types::{FunctionValue, Value};
use crate::register::credentials::SESSIONS;
use crate::functions::sigv4::{build_aws_sigv4_headers, hex_sha256_str};
use std::sync::{Arc, Mutex};
use reqwest::blocking::Client;
use reqwest::header::{HeaderValue, USER_AGENT, CONTENT_TYPE};
use chrono::Utc;
use indexmap::IndexMap;

/* ────────────────────────────────────────────────────────────────────────── */
fn make_error(msg: impl Into<String>) -> Value {
    let mut m = IndexMap::new();
    m.insert("ok".to_string(), Value::Bool(false));
    m.insert("error".to_string(), Value::SingleString(msg.into()));
    Value::KeyedArray(m)
}
/* ────────────────────────────────────────────────────────────────────────── */

pub fn register_s3_create_bucket(interp: &mut Interpreter) {
    let f = Arc::new(Mutex::new(|interp: &mut Interpreter, args: Vec<Value>| {
        if interp.is_verbose() {
            eprintln!(
                "[aws:s3:create_bucket] called with args: {:?}",
                args
            );
        }
        let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            aws_s3_create_bucket_function(interp, args)
        }));
        match res {
            Ok(Ok(v)) => Ok(v),
            Ok(Err(msg)) => Ok(make_error(format!("aws:s3:create_bucket: {}", msg))),
            Err(e) => Ok(make_error(format!(
                "aws:s3:create_bucket: fatal plugin panic: {:?}",
                e
            ))),
        }
    }));
    let info = DynamicFnInfo::new(f, false);
    interp.register_dynamic_function_ex("aws:s3:create_bucket", info);

    interp.set_variable(
        "aws:s3:create_bucket",
        Value::Function(Box::new(FunctionValue::Named(
            "aws:s3:create_bucket".to_string(),
        ))),
    );
}

pub fn aws_s3_create_bucket_function(
    interp: &mut Interpreter,
    args: Vec<Value>,
) -> Result<Value, String> {
    if args.len() != 1 {
        return Err("aws:s3:create_bucket expects a keyed‑array argument".into());
    }
    let opts = match &args[0] {
        Value::KeyedArray(m) => m.clone(),
        _ => return Err("aws:s3:create_bucket argument must be a keyed array".into()),
    };

    let cred_id = match opts.get("credentials") {
        Some(Value::SingleString(s)) => s,
        _ => return Err("Missing 'credentials'".into()),
    };
    let bucket = match opts.get("bucket") {
        Some(Value::SingleString(s)) => s,
        _ => return Err("Missing 'bucket'".into()),
    };

    let sessions = SESSIONS.lock().unwrap();
    let sess = sessions
        .get(cred_id)
        .ok_or_else(|| format!("No session found with id {}", cred_id))?;

    let host = sess
        .endpoint
        .as_ref()
        .map(|ep| ep.trim_start_matches("http://").trim_start_matches("https://"))
        .unwrap_or("s3.amazonaws.com");

    /* ---------- SigV4 --------------------------------------------------- */
    let now = Utc::now();
    let amz_date = now.format("%Y%m%dT%H%M%SZ").to_string();
    let date_stamp = now.format("%Y%m%d").to_string();
    let (authz, mut headers) = build_aws_sigv4_headers(
        "PUT",
        &format!("/{}", bucket),
        "",
        &hex_sha256_str(""),
        host,
        &amz_date,
        &date_stamp,
        &sess.region,
        "s3",
        &sess.access_key,
        &sess.secret_key,
    );
    headers.insert(USER_AGENT, HeaderValue::from_static("aws-mumu/0.1"));
    headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/xml"));

    if interp.is_verbose() {
        eprintln!(
            "[aws:s3:create_bucket] Built SigV4 headers: {:?}, authz={}",
            headers, authz
        );
    }

    /* ---------- HTTP call ---------------------------------------------- */
    let client = Client::builder()
        .build()
        .map_err(|e| format!("Building client: {}", e))?;
    let url = format!(
        "{}://{}/{}",
        if sess.endpoint.is_some() { "http" } else { "https" },
        host,
        bucket
    );
    if interp.is_verbose() {
        eprintln!("[aws:s3:create_bucket] Sending PUT {}", url);
    }
    let resp = client
        .put(&url)
        .headers(headers)
        .body("")
        .send()
        .map_err(|e| format!("HTTP request error: {}", e))?;

    /* capture status BEFORE consuming body */
    let status = resp.status();
    let body = resp.text().unwrap_or_default();

    if !status.is_success() {
        return Err(format!("AWS error status {} – body: {}", status, body));
    }

    /* ---------- Success ------------------------------------------------- */
    let mut ok = IndexMap::new();
    ok.insert("ok".into(), Value::Bool(true));
    ok.insert("bucket".into(), Value::SingleString(bucket.clone()));
    Ok(Value::KeyedArray(ok))
}
