use crate::config::{Config, GiteaConfig};
use crate::error::GeneralError;
use reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION};
use reqwest::{ClientBuilder, StatusCode};
use serde::de::DeserializeOwned;
use url::Url;

#[derive(Debug)]
pub struct Client {
    token: String,
    base_uri: String,
}

fn is_client_for_url(url: &Url, config: &GiteaConfig) -> bool {
    if url.domain() == Some(config.domain.as_str()) {
        return true;
    }
    false
}

pub(crate) fn has_client_for_url(url: &Url, config: &Config) -> bool {
    for c in &config.gitea {
        if is_client_for_url(url, c) {
            return true;
        }
    }

    false
}

fn client_for_url(url: &Url, config: &Config) -> Result<Client, GeneralError> {
    for c in &config.gitea {
        if is_client_for_url(url, c) {
            return Ok(Client::from_config(&c));
        }
    }

    Err(GeneralError {
        description: format!("No gitea client found for url {}", url),
    })
}

impl Client {
    pub fn from_config(config: &GiteaConfig) -> Self {
        Self::new(&config.token, &config.domain)
    }

    pub fn new(token: &String, domain: &String) -> Self {
        Client {
            token: token.clone(),
            base_uri: format!("https://{}", domain.clone()),
        }
    }

    pub async fn get<T: DeserializeOwned>(&self, url: Url) -> Result<T, GeneralError> {
        let mut headers = HeaderMap::new();
        headers.append(AUTHORIZATION, format!("token {}", self.token).parse()?);
        headers.append(ACCEPT, "application/json".parse()?);

        let client = ClientBuilder::new()
            .default_headers(headers)
            .build()
            .unwrap();

        let response = client.get(url.clone()).send().await?;

        match response.status() {
            StatusCode::OK => {
                let result: T = response.json().await?;

                Ok(result)
            }
            _ => Err(GeneralError {
                description: format!(
                    "Could not call GET on {:?}, error code {}",
                    url,
                    response.status()
                ),
            }),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_is_client_for_url() {
        let config = GiteaConfig {
            domain: "gitea.champs-libres.be".into(),
            token: "<PASSWORD>".into(),
        };

        assert_eq!(
            is_client_for_url(
                &Url::parse("https://gitea.champs-libres.be/something/somewhere").unwrap(),
                &config
            ),
            true
        );
        assert_eq!(
            is_client_for_url(
                &Url::parse("https://somewhere.else/something/somewhere").unwrap(),
                &config
            ),
            false
        );
    }
}