use crate::endpoints::{Empty, Endpoint};
use crate::types::notification::{NotificationType, PackNotification};
use crate::util_types::{deserialize_array_urlenc, deserialize_opt_array_urlenc};
use http::Method;
use magnetar_sdk_macros::Endpoint;
use serde::{Deserialize, Serialize};
use ts_rs::TS;

use crate::types::user::{PackUserBase, PackUserMaybeAll, PackUserSelfMaybeAll};

// Get self
#[derive(Serialize, Deserialize, TS)]
#[ts(export)]
pub struct UserSelfReq {
    #[ts(optional)]
    pub profile: Option<bool>,
    #[ts(optional)]
    pub pins: Option<bool>,
    #[ts(optional)]
    pub detail: Option<bool>,
    #[ts(optional)]
    pub secrets: Option<bool>,
    #[ts(optional)]
    pub self_detail: Option<bool>,
}

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/@self",
    method = Method::GET,
    request = "UserSelfReq",
    response = "PackUserSelfMaybeAll"
)]
pub struct GetUserSelf;

// Get user by id
#[derive(Serialize, Deserialize, TS)]
#[ts(export)]
pub struct UserByIdReq {
    #[ts(optional)]
    pub profile: Option<bool>,
    #[ts(optional)]
    pub pins: Option<bool>,
    #[ts(optional)]
    pub detail: Option<bool>,
    #[ts(optional)]
    pub relation: Option<bool>,
    #[ts(optional)]
    pub auth: Option<bool>,
}

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/:user_id",
    method = Method::GET,
    request = "UserByIdReq",
    response = "PackUserMaybeAll"
)]
pub struct GetUserById;

// Get many users by an ID array
#[derive(Serialize, Deserialize, TS)]
#[ts(export)]
pub struct ManyUsersByIdReq {
    #[serde(deserialize_with = "deserialize_array_urlenc")]
    pub id: Vec<String>,
}

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/lookup-many",
    method = Method::GET,
    request = "ManyUsersByIdReq",
    response = "Vec<Option<PackUserBase>>"
)]
pub struct GetManyUsersById;

// Get user by fedi tag

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/by-acct/:user_acct",
    method = Method::GET,
    request = "UserByIdReq",
    response = "PackUserMaybeAll"
)]
pub struct GetUserByAcct;

#[derive(Serialize, Deserialize, TS)]
#[ts(export)]
pub struct NotificationsReq {
    #[ts(optional)]
    #[serde(default)]
    #[serde(deserialize_with = "deserialize_opt_array_urlenc")]
    pub include_types: Option<Vec<NotificationType>>,
    #[ts(optional)]
    #[serde(default)]
    #[serde(deserialize_with = "deserialize_opt_array_urlenc")]
    pub exclude_types: Option<Vec<NotificationType>>,
    #[ts(optional)]
    pub unread_only: Option<bool>,
}

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/@self/notifications",
    method = Method::GET,
    request = "NotificationsReq",
    response = "Vec<PackNotification>",
    paginated = true
)]
pub struct GetNotifications;

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/:id/followers",
    method = Method::GET,
    request = "Empty",
    response = "Vec<PackUserMaybeAll>",
    paginated = true
)]
pub struct GetFollowersById;

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/:id/following",
    method = Method::GET,
    request = "Empty",
    response = "Vec<PackUserMaybeAll>",
    paginated = true
)]
pub struct GetFollowingById;

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/@self/followers",
    method = Method::GET,
    request = "Empty",
    response = "Vec<PackUserMaybeAll>",
    paginated = true
)]
pub struct GetFollowersSelf;

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/@self/following",
    method = Method::GET,
    request = "Empty",
    response = "Vec<PackUserMaybeAll>",
    paginated = true
)]
pub struct GetFollowingSelf;

#[derive(Endpoint)]
#[endpoint(
    endpoint = "/users/@self/follow-requests",
    method = Method::GET,
    request = "Empty",
    response = "Vec<PackUserMaybeAll>",
    paginated = true
)]
pub struct GetFollowRequestsSelf;
