use crate::enums::media::{MediaSort, MediaType};
use crate::enums::media_list::MediaListStatus;
use crate::enums::user::{UserSort, UserStatisticsSort};
use crate::errors::AniListError;
use crate::objects::responses::Page;
use crate::objects::user::User;
use crate::{client::AniListClient, queries::user};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserOptions {
pub id: Option<i32>,
pub name: Option<String>,
pub search: Option<String>,
pub sort: Option<Vec<UserSort>>,
#[serde(rename = "isModerator")]
pub is_moderator: Option<bool>,
pub page: Option<i32>,
#[serde(rename = "perPage")]
pub per_page: Option<i32>,
#[serde(rename = "includeFavourites")]
pub include_favourites: Option<bool>,
#[serde(rename = "includeStatistics")]
pub include_statistics: Option<bool>,
#[serde(rename = "about_as_html")]
pub about_as_html: Option<bool>,
}
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserOneOptions {
pub id: Option<i32>,
pub name: Option<String>,
#[serde(rename = "about_as_html")]
pub about_as_html: Option<bool>,
}
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserFollowersOptions {
#[serde(rename = "userId")]
pub user_id: i32,
pub page: Option<i32>,
#[serde(rename = "perPage")]
pub per_page: Option<i32>,
}
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserFollowingOptions {
#[serde(rename = "userId")]
pub user_id: i32,
pub page: Option<i32>,
#[serde(rename = "perPage")]
pub per_page: Option<i32>,
}
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserFavoritesOptions {
#[serde(rename = "userId")]
pub user_id: i32,
#[serde(rename = "fetchAnime")]
pub fetch_anime: Option<bool>,
#[serde(rename = "fetchManga")]
pub fetch_manga: Option<bool>,
#[serde(rename = "fetchCharacters")]
pub fetch_characters: Option<bool>,
#[serde(rename = "fetchStaff")]
pub fetch_staff: Option<bool>,
#[serde(rename = "fetchStudios")]
pub fetch_studios: Option<bool>,
#[serde(rename = "animePage")]
pub anime_page: Option<i32>,
#[serde(rename = "animePerPage")]
pub anime_per_page: Option<i32>,
#[serde(rename = "animeSort")]
pub anime_sort: Option<Vec<MediaSort>>,
#[serde(rename = "mangaPage")]
pub manga_page: Option<i32>,
#[serde(rename = "mangaPerPage")]
pub manga_per_page: Option<i32>,
#[serde(rename = "mangaSort")]
pub manga_sort: Option<Vec<MediaSort>>,
#[serde(rename = "charactersPage")]
pub characters_page: Option<i32>,
#[serde(rename = "charactersPerPage")]
pub characters_per_page: Option<i32>,
#[serde(rename = "staffPage")]
pub staff_page: Option<i32>,
#[serde(rename = "staffPerPage")]
pub staff_per_page: Option<i32>,
#[serde(rename = "studiosPage")]
pub studios_page: Option<i32>,
#[serde(rename = "studiosPerPage")]
pub studios_per_page: Option<i32>,
}
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserMediaListOptions {
#[serde(rename = "userId")]
pub user_id: Option<i32>,
pub username: Option<String>,
#[serde(rename = "type")]
pub media_type: Option<MediaType>,
pub status: Option<MediaListStatus>,
pub notes: Option<String>,
#[serde(rename = "startedAt")]
pub started_at: Option<i32>,
#[serde(rename = "completedAt")]
pub completed_at: Option<i32>,
pub sort: Option<Vec<MediaSort>>,
pub page: Option<i32>,
#[serde(rename = "perPage")]
pub per_page: Option<i32>,
}
#[skip_serializing_none]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct FetchUserStatsOptions {
#[serde(rename = "userId")]
pub user_id: i32,
pub sort: Option<Vec<UserStatisticsSort>>,
}
pub struct UserEndpoint {
client: AniListClient,
}
impl UserEndpoint {
pub fn new(client: AniListClient) -> Self {
Self { client }
}
pub async fn fetch(&self, options: FetchUserOptions) -> Result<Page<Vec<User>>, AniListError> {
let query = user::FETCH;
self.client.fetch(query, Some(&options)).await
}
pub async fn fetch_one(&self, options: &FetchUserOneOptions) -> Result<User, AniListError> {
let query = user::FETCH_ONE;
self.client.fetch(query, Some(options)).await
}
pub async fn fetch_basic(&self) -> Result<User, AniListError> {
let query = user::BASIC;
self.client.fetch(query, Option::<&()>::None).await
}
pub async fn followers(
&self,
options: &FetchUserFollowersOptions,
) -> Result<Page<Vec<User>>, AniListError> {
let query = user::FOLLOWERS;
self.client.fetch(query, Some(options)).await
}
pub async fn following(
&self,
options: &FetchUserFollowingOptions,
) -> Result<Page<Vec<User>>, AniListError> {
let query = user::FOLLOWING;
self.client.fetch(query, Some(options)).await
}
pub async fn favorites(
&self,
options: &FetchUserFavoritesOptions,
) -> Result<Page<Vec<User>>, AniListError> {
let query = user::FAVORITES;
self.client.fetch(query, Some(options)).await
}
pub async fn media_list(
&self,
options: &FetchUserMediaListOptions,
) -> Result<Page<Vec<User>>, AniListError> {
let query = user::MEDIA_LIST;
self.client.fetch(query, Some(options)).await
}
pub async fn stats(&self, options: &FetchUserStatsOptions) -> Result<User, AniListError> {
let query = user::STATS;
self.client.fetch(query, Some(options)).await
}
pub async fn get_current_user(&self) -> Result<User, AniListError> {
let response = self.client.user().fetch_basic().await?;
let id = response.id;
self.fetch_one(&FetchUserOneOptions {
id: Some(id),
..Default::default()
})
.await
}
pub async fn get_by_id(&self, id: i32) -> Result<User, AniListError> {
self.fetch_one(&FetchUserOneOptions {
id: Some(id),
..Default::default()
})
.await
}
pub async fn get_by_name(&self, name: &str) -> Result<User, AniListError> {
self.fetch_one(&FetchUserOneOptions {
name: Some(name.to_string()),
..Default::default()
})
.await
}
pub async fn search(
&self,
query: &str,
page: Option<i32>,
per_page: Option<i32>,
) -> Result<Page<Vec<User>>, AniListError> {
self.fetch(FetchUserOptions {
search: Some(query.to_string()),
page,
per_page,
sort: Some(vec![UserSort::SearchMatch]),
..Default::default()
})
.await
}
pub async fn get_most_anime_watched(
&self,
page: Option<i32>,
per_page: Option<i32>,
) -> Result<Page<Vec<User>>, AniListError> {
self.fetch(FetchUserOptions {
page,
per_page,
sort: Some(vec![UserSort::WatchedTimeDesc]),
..Default::default()
})
.await
}
pub async fn get_most_manga_read(
&self,
page: Option<i32>,
per_page: Option<i32>,
) -> Result<Page<Vec<User>>, AniListError> {
self.fetch(FetchUserOptions {
page,
per_page,
sort: Some(vec![UserSort::ChaptersReadDesc]),
..Default::default()
})
.await
}
}