use anyhow::Result;
use serde::Deserialize;

use super::Repositories;
use super::client::RemoteClient;
use super::spec::RemoteSpec;

#[derive(Deserialize)]
struct ForgejoRepo {
    clone_url: String,
}

pub async fn repositories(spec: &RemoteSpec) -> Result<Repositories> {
    let client = RemoteClient::new(spec)?;
    let base_url = spec.normalized_base_url();
    let mut repositories = Vec::new();
    let mut page = 1;

    loop {
        let url = format!(
            "{}/api/v1/users/{}/repos?page={page}&limit=50",
            base_url, spec.owner
        );
        let repos = client.get_json::<Vec<ForgejoRepo>>(&url).await?;
        if repos.is_empty() {
            break;
        }

        repositories.extend(repos.into_iter().map(|repo| repo.clone_url));
        page += 1;
    }

    Ok(repositories)
}

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

    #[tokio::test]
    async fn repositories_collects_pages_until_empty() {
        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(r#"[{"clone_url":"https://example.com/two.git"}]"#),
            ),
            (
                "/api/v1/users/wykwit/repos?page=3&limit=50".to_string(),
                StubResponse::json("[]"),
            ),
        ])
        .await;
        let spec = RemoteSpec {
            kind: ProviderKind::Forgejo,
            base_url: Some(server.url().to_string()),
            owner: "wykwit".to_string(),
        };

        let repos = repositories(&spec).await.unwrap();

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