mod client;
mod forgejo;
mod github;
mod gitlab;
mod spec;

use anyhow::Result;
pub use spec::{ProviderKind, RemoteSpec};

pub type Repositories = Vec<String>;

pub async fn repositories(spec: RemoteSpec) -> Result<Repositories> {
    match spec.kind {
        ProviderKind::GitHub => github::repositories(&spec).await,
        ProviderKind::GitLab => gitlab::repositories(&spec).await,
        ProviderKind::Forgejo => forgejo::repositories(&spec).await,
    }
}

#[cfg(test)]
mod tests {
    use super::{ProviderKind, RemoteSpec, repositories};
    use crate::testing::{StubResponse, spawn_server};

    #[tokio::test]
    async fn repositories_dispatches_to_github_provider() {
        let server = spawn_server(vec![(
            "/users/wykwit/repos?per_page=100".to_string(),
            StubResponse::json(
                r#"[{"clone_url":"https://example.com/one.git","owner":{"login":"wykwit"}}]"#,
            ),
        )])
        .await;

        let repos = repositories(RemoteSpec {
            kind: ProviderKind::GitHub,
            base_url: Some(server.url().to_string()),
            owner: "wykwit".to_string(),
        })
        .await
        .unwrap();

        assert_eq!(repos, vec!["https://example.com/one.git".to_string()]);
    }

    #[tokio::test]
    async fn repositories_dispatches_to_gitlab_provider() {
        let server = spawn_server(vec![
            (
                "/api/v4/users?username=wykwit".to_string(),
                StubResponse::json(r#"[{"id":7}]"#),
            ),
            (
                "/api/v4/users/7/projects?page=1&per_page=100&simple=true".to_string(),
                StubResponse::json(r#"[{"http_url_to_repo":"https://example.com/one.git"}]"#),
            ),
            (
                "/api/v4/users/7/projects?page=2&per_page=100&simple=true".to_string(),
                StubResponse::json("[]"),
            ),
        ])
        .await;

        let repos = repositories(RemoteSpec {
            kind: ProviderKind::GitLab,
            base_url: Some(server.url().to_string()),
            owner: "wykwit".to_string(),
        })
        .await
        .unwrap();

        assert_eq!(repos, vec!["https://example.com/one.git".to_string()]);
    }

    #[tokio::test]
    async fn repositories_dispatches_to_forgejo_provider() {
        let server = spawn_server(vec![
            (
                "/api/v1/users/wykwit/repos?page=1&limit=50".to_string(),
                StubResponse::json(r#"[{"clone_url":"https://example.com/one.git"}]"#),
            ),
            (
                "/api/v1/users/wykwit/repos?page=2&limit=50".to_string(),
                StubResponse::json("[]"),
            ),
        ])
        .await;

        let repos = repositories(RemoteSpec {
            kind: ProviderKind::Forgejo,
            base_url: Some(server.url().to_string()),
            owner: "wykwit".to_string(),
        })
        .await
        .unwrap();

        assert_eq!(repos, vec!["https://example.com/one.git".to_string()]);
    }
}
