use crate::creds::Credentials;
use crate::error::Error;
use crate::http::{self, Request, Response};
use crate::region::Region;
use crate::{sigv4, xml};

const CONTENT_TYPE: &str = "application/x-www-form-urlencoded";

pub fn call(
    creds: &Credentials,
    region: &Region,
    service: &str,
    action: &str,
    version: &str,
    params: &[(&str, String)],
) -> Result<String, Error> {
    let mut form = vec![
        ("Action".to_string(), action.to_string()),
        ("Version".to_string(), version.to_string()),
    ];
    for (k, v) in params {
        form.push((k.to_string(), v.clone()));
    }
    let body = sigv4::encode_query(&form, false);

    let req = Request::new("POST", service)
        .header("Content-Type", CONTENT_TYPE)
        .body(body.into_bytes());

    let resp = http::send(creds, region, &req)?;
    if resp.is_success() {
        Ok(resp.body_str())
    } else {
        Err(query_error(resp))
    }
}

fn query_error(resp: Response) -> Error {
    let status = resp.status;
    let body = resp.body_str();
    match (
        xml::inner(&body, "Code").map(xml::unescape),
        xml::inner(&body, "Message").map(xml::unescape),
    ) {
        (Some(code), message) => Error::Aws {
            code,
            message: message.unwrap_or_default(),
            status,
        },
        _ => Error::Http { status, body },
    }
}
