use crate::{
    api::{endpoint::Requester, form::Form},
    consts,
    error::{FetchAasError, IntoGoogleError},
};
use std::borrow::Cow;

/// a requester for converting oauth tokens into usable aas tokens
///
/// create one with [`OAuthRequest::new`]
pub struct OAuthRequest<'a> {
    oauth_token: &'a str,
    email: &'a str,
}

impl<'a> OAuthRequest<'a> {
    /// create a new requester with an oauth token and email, email must be the one used for getting
    /// the oauth token
    #[must_use]
    pub const fn new(oauth_token: &'a str, email: &'a str) -> Self {
        Self { oauth_token, email }
    }

    /// fetch an aas token from an oauth token
    ///
    /// # Errors
    /// - `Request` - when the HTTP request fails
    /// - `Google` -  when Google returns an error
    pub async fn fetch(&self) -> Result<String, FetchAasError> {
        let headers = [
            ("content-type", "application/x-www-form-urlencoded"),
            ("user-agent", consts::AUTH_USER_AGENT),
            ("app", consts::ANDROID_VENDING),
        ];

        let form = Form::new([
            ("Email", self.email),
            ("Token", self.oauth_token),
            ("lang", consts::LANGUAGE),
            ("google_play_services_version", consts::SERVICE_VERSION),
            ("sdk_version", consts::SDK),
            ("device_country", consts::COUNTRY_CODE),
            ("service", consts::SERVICE),
            ("callerPkg", consts::ANDROID_VENDING),
            ("callerSig", consts::CALLER_SIG),
            ("droidguard_results", "null"),
            ("get_accountid", "1"),
            ("ACCESS_TOKEN", "1"),
        ]);

        let request = Requester::new().headers(&headers);
        let mut response = request.form_request("auth", form).await?;

        let result = response.remove("Token").into_google_error_map(|| {
            response
                .remove("Error")
                .unwrap_or(Cow::Borrowed("Google didn't provide a token or an error!"))
                .to_string()
        })?;

        Ok(result.to_string())
    }
}
