// Auto-generated by crates/tele-codegen. Do not edit manually.
use serde::Serialize;

use crate::{Error, Result};

use crate::types::validation::{
    non_negative_i64 as validate_non_negative_i64, positive_i64 as validate_positive_i64,
    required_len as validate_required_vec, required_string as validate_required_string,
    string_id as validate_string_id,
};

use super::AdvancedRequest;

trait GeneratedValidate {
    fn validate_generated(&self) -> Result<()>;
}

impl GeneratedValidate for crate::types::sticker::InputSticker {
    fn validate_generated(&self) -> Result<()> {
        self.validate()
    }
}

fn validate_items<T: GeneratedValidate>(values: &[T]) -> Result<()> {
    for value in values {
        value.validate_generated()?;
    }

    Ok(())
}

fn validate_required_items<T: GeneratedValidate>(field: &str, values: &[T]) -> Result<()> {
    if values.is_empty() {
        return Err(Error::InvalidRequest {
            reason: format!("{field} cannot be empty"),
        });
    }

    validate_items(values)
}

fn validate_string_items(field: &str, values: &[String]) -> Result<()> {
    for (index, value) in values.iter().enumerate() {
        validate_string_id(&format!("{field}[{index}]"), value)?;
    }

    Ok(())
}

fn validate_required_string_items(field: &str, values: &[String]) -> Result<()> {
    validate_required_vec(field, values.len())?;
    validate_string_items(field, values)
}

/// Auto-generated request for `setUserEmojiStatus`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetUserEmojiStatusRequest {
    pub user_id: crate::types::common::UserId,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub emoji_status_custom_emoji_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub emoji_status_expiration_date: Option<i64>,
}

impl AdvancedSetUserEmojiStatusRequest {
    pub fn new(user_id: crate::types::common::UserId) -> Self {
        Self {
            user_id,
            emoji_status_custom_emoji_id: None,
            emoji_status_expiration_date: None,
        }
    }
}

impl AdvancedRequest for AdvancedSetUserEmojiStatusRequest {
    type Response = bool;
    const METHOD: &'static str = "setUserEmojiStatus";

    fn validate(&self) -> Result<()> {
        self.user_id.validate()?;
        if let Some(value) = self.emoji_status_custom_emoji_id.as_deref() {
            validate_string_id("emoji_status_custom_emoji_id", value)?;
        }
        if let Some(value) = self.emoji_status_expiration_date {
            validate_positive_i64("emoji_status_expiration_date", value)?;
        }
        Ok(())
    }
}

/// Auto-generated request for `sendSticker`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSendStickerRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub business_connection_id: Option<String>,
    pub chat_id: crate::types::common::ChatId,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub message_thread_id: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub direct_messages_topic_id: Option<i64>,
    pub sticker: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub emoji: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub disable_notification: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub protect_content: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub allow_paid_broadcast: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub message_effect_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub suggested_post_parameters: Option<crate::types::telegram::SuggestedPostParameters>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reply_parameters: Option<crate::types::telegram::ReplyParameters>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reply_markup: Option<crate::types::telegram::ReplyMarkup>,
}

impl AdvancedSendStickerRequest {
    pub fn new(
        chat_id: impl Into<crate::types::common::ChatId>,
        sticker: impl Into<String>,
    ) -> Self {
        Self {
            business_connection_id: None,
            chat_id: chat_id.into(),
            message_thread_id: None,
            direct_messages_topic_id: None,
            sticker: sticker.into(),
            emoji: None,
            disable_notification: None,
            protect_content: None,
            allow_paid_broadcast: None,
            message_effect_id: None,
            suggested_post_parameters: None,
            reply_parameters: None,
            reply_markup: None,
        }
    }
}

impl AdvancedRequest for AdvancedSendStickerRequest {
    type Response = crate::types::message::Message;
    const METHOD: &'static str = "sendSticker";

    fn validate(&self) -> Result<()> {
        if let Some(value) = self.business_connection_id.as_deref() {
            validate_string_id("business_connection_id", value)?;
        }
        self.chat_id.validate()?;
        if let Some(value) = self.message_thread_id {
            validate_positive_i64("message_thread_id", value)?;
        }
        if let Some(value) = self.direct_messages_topic_id {
            validate_positive_i64("direct_messages_topic_id", value)?;
        }
        validate_required_string("sticker", &self.sticker)?;
        if let Some(value) = self.message_effect_id.as_deref() {
            validate_string_id("message_effect_id", value)?;
        }
        if let Some(value) = self.suggested_post_parameters.as_ref() {
            value.validate()?;
        }
        if let Some(value) = self.reply_parameters.as_ref() {
            value.validate()?;
        }
        if let Some(value) = self.reply_markup.as_ref() {
            value.validate()?;
        }
        Ok(())
    }
}

/// Auto-generated request for `getStickerSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedGetStickerSetRequest {
    pub name: String,
}

impl AdvancedGetStickerSetRequest {
    pub fn new(name: impl Into<String>) -> Self {
        Self { name: name.into() }
    }
}

impl AdvancedRequest for AdvancedGetStickerSetRequest {
    type Response = crate::types::sticker::StickerSet;
    const METHOD: &'static str = "getStickerSet";

    fn validate(&self) -> Result<()> {
        validate_required_string("name", &self.name)?;
        Ok(())
    }
}

/// Auto-generated request for `getCustomEmojiStickers`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedGetCustomEmojiStickersRequest {
    pub custom_emoji_ids: Vec<String>,
}

impl AdvancedGetCustomEmojiStickersRequest {
    pub fn new(custom_emoji_ids: Vec<String>) -> Self {
        Self { custom_emoji_ids }
    }
}

impl AdvancedRequest for AdvancedGetCustomEmojiStickersRequest {
    type Response = Vec<crate::types::sticker::Sticker>;
    const METHOD: &'static str = "getCustomEmojiStickers";

    fn validate(&self) -> Result<()> {
        validate_required_string_items("custom_emoji_ids", &self.custom_emoji_ids)?;
        Ok(())
    }
}

/// Auto-generated request for `createNewStickerSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedCreateNewStickerSetRequest {
    pub user_id: crate::types::common::UserId,
    pub name: String,
    pub title: String,
    pub stickers: Vec<crate::types::sticker::InputSticker>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sticker_type: Option<crate::types::sticker::StickerType>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub needs_repainting: Option<bool>,
}

impl AdvancedCreateNewStickerSetRequest {
    pub fn new(
        user_id: crate::types::common::UserId,
        name: impl Into<String>,
        title: impl Into<String>,
        stickers: Vec<crate::types::sticker::InputSticker>,
    ) -> Self {
        Self {
            user_id,
            name: name.into(),
            title: title.into(),
            stickers,
            sticker_type: None,
            needs_repainting: None,
        }
    }
}

impl AdvancedRequest for AdvancedCreateNewStickerSetRequest {
    type Response = bool;
    const METHOD: &'static str = "createNewStickerSet";

    fn validate(&self) -> Result<()> {
        self.user_id.validate()?;
        validate_required_string("name", &self.name)?;
        validate_required_string("title", &self.title)?;
        validate_required_items::<crate::types::sticker::InputSticker>("stickers", &self.stickers)?;
        Ok(())
    }
}

/// Auto-generated request for `addStickerToSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedAddStickerToSetRequest {
    pub user_id: crate::types::common::UserId,
    pub name: String,
    pub sticker: crate::types::sticker::InputSticker,
}

impl AdvancedAddStickerToSetRequest {
    pub fn new(
        user_id: crate::types::common::UserId,
        name: impl Into<String>,
        sticker: crate::types::sticker::InputSticker,
    ) -> Self {
        Self {
            user_id,
            name: name.into(),
            sticker,
        }
    }
}

impl AdvancedRequest for AdvancedAddStickerToSetRequest {
    type Response = bool;
    const METHOD: &'static str = "addStickerToSet";

    fn validate(&self) -> Result<()> {
        self.user_id.validate()?;
        validate_required_string("name", &self.name)?;
        self.sticker.validate()?;
        Ok(())
    }
}

/// Auto-generated request for `setStickerPositionInSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetStickerPositionInSetRequest {
    pub sticker: String,
    pub position: i64,
}

impl AdvancedSetStickerPositionInSetRequest {
    pub fn new(sticker: impl Into<String>, position: i64) -> Self {
        Self {
            sticker: sticker.into(),
            position,
        }
    }
}

impl AdvancedRequest for AdvancedSetStickerPositionInSetRequest {
    type Response = bool;
    const METHOD: &'static str = "setStickerPositionInSet";

    fn validate(&self) -> Result<()> {
        validate_required_string("sticker", &self.sticker)?;
        validate_non_negative_i64("position", self.position)?;
        Ok(())
    }
}

/// Auto-generated request for `deleteStickerFromSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedDeleteStickerFromSetRequest {
    pub sticker: String,
}

impl AdvancedDeleteStickerFromSetRequest {
    pub fn new(sticker: impl Into<String>) -> Self {
        Self {
            sticker: sticker.into(),
        }
    }
}

impl AdvancedRequest for AdvancedDeleteStickerFromSetRequest {
    type Response = bool;
    const METHOD: &'static str = "deleteStickerFromSet";

    fn validate(&self) -> Result<()> {
        validate_required_string("sticker", &self.sticker)?;
        Ok(())
    }
}

/// Auto-generated request for `replaceStickerInSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedReplaceStickerInSetRequest {
    pub user_id: crate::types::common::UserId,
    pub name: String,
    pub old_sticker: String,
    pub sticker: crate::types::sticker::InputSticker,
}

impl AdvancedReplaceStickerInSetRequest {
    pub fn new(
        user_id: crate::types::common::UserId,
        name: impl Into<String>,
        old_sticker: impl Into<String>,
        sticker: crate::types::sticker::InputSticker,
    ) -> Self {
        Self {
            user_id,
            name: name.into(),
            old_sticker: old_sticker.into(),
            sticker,
        }
    }
}

impl AdvancedRequest for AdvancedReplaceStickerInSetRequest {
    type Response = bool;
    const METHOD: &'static str = "replaceStickerInSet";

    fn validate(&self) -> Result<()> {
        self.user_id.validate()?;
        validate_required_string("name", &self.name)?;
        validate_required_string("old_sticker", &self.old_sticker)?;
        self.sticker.validate()?;
        Ok(())
    }
}

/// Auto-generated request for `setStickerEmojiList`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetStickerEmojiListRequest {
    pub sticker: String,
    pub emoji_list: Vec<String>,
}

impl AdvancedSetStickerEmojiListRequest {
    pub fn new(sticker: impl Into<String>, emoji_list: Vec<String>) -> Self {
        Self {
            sticker: sticker.into(),
            emoji_list,
        }
    }
}

impl AdvancedRequest for AdvancedSetStickerEmojiListRequest {
    type Response = bool;
    const METHOD: &'static str = "setStickerEmojiList";

    fn validate(&self) -> Result<()> {
        validate_required_string("sticker", &self.sticker)?;
        validate_required_string_items("emoji_list", &self.emoji_list)?;
        Ok(())
    }
}

/// Auto-generated request for `setStickerKeywords`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetStickerKeywordsRequest {
    pub sticker: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub keywords: Option<Vec<String>>,
}

impl AdvancedSetStickerKeywordsRequest {
    pub fn new(sticker: impl Into<String>) -> Self {
        Self {
            sticker: sticker.into(),
            keywords: None,
        }
    }
}

impl AdvancedRequest for AdvancedSetStickerKeywordsRequest {
    type Response = bool;
    const METHOD: &'static str = "setStickerKeywords";

    fn validate(&self) -> Result<()> {
        validate_required_string("sticker", &self.sticker)?;
        if let Some(values) = self.keywords.as_deref() {
            validate_string_items("keywords", values)?;
        }
        Ok(())
    }
}

/// Auto-generated request for `setStickerMaskPosition`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetStickerMaskPositionRequest {
    pub sticker: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mask_position: Option<crate::types::sticker::MaskPosition>,
}

impl AdvancedSetStickerMaskPositionRequest {
    pub fn new(sticker: impl Into<String>) -> Self {
        Self {
            sticker: sticker.into(),
            mask_position: None,
        }
    }
}

impl AdvancedRequest for AdvancedSetStickerMaskPositionRequest {
    type Response = bool;
    const METHOD: &'static str = "setStickerMaskPosition";

    fn validate(&self) -> Result<()> {
        validate_required_string("sticker", &self.sticker)?;
        if let Some(value) = self.mask_position.as_ref() {
            value.validate()?;
        }
        Ok(())
    }
}

/// Auto-generated request for `setStickerSetTitle`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetStickerSetTitleRequest {
    pub name: String,
    pub title: String,
}

impl AdvancedSetStickerSetTitleRequest {
    pub fn new(name: impl Into<String>, title: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            title: title.into(),
        }
    }
}

impl AdvancedRequest for AdvancedSetStickerSetTitleRequest {
    type Response = bool;
    const METHOD: &'static str = "setStickerSetTitle";

    fn validate(&self) -> Result<()> {
        validate_required_string("name", &self.name)?;
        validate_required_string("title", &self.title)?;
        Ok(())
    }
}

/// Auto-generated request for `setStickerSetThumbnail`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetStickerSetThumbnailRequest {
    pub name: String,
    pub user_id: crate::types::common::UserId,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub thumbnail: Option<String>,
    pub format: crate::types::sticker::StickerFormat,
}

impl AdvancedSetStickerSetThumbnailRequest {
    pub fn new(
        name: impl Into<String>,
        user_id: crate::types::common::UserId,
        format: crate::types::sticker::StickerFormat,
    ) -> Self {
        Self {
            name: name.into(),
            user_id,
            thumbnail: None,
            format,
        }
    }
}

impl AdvancedRequest for AdvancedSetStickerSetThumbnailRequest {
    type Response = bool;
    const METHOD: &'static str = "setStickerSetThumbnail";

    fn validate(&self) -> Result<()> {
        validate_required_string("name", &self.name)?;
        self.user_id.validate()?;
        Ok(())
    }
}

/// Auto-generated request for `setCustomEmojiStickerSetThumbnail`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedSetCustomEmojiStickerSetThumbnailRequest {
    pub name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub custom_emoji_id: Option<String>,
}

impl AdvancedSetCustomEmojiStickerSetThumbnailRequest {
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            custom_emoji_id: None,
        }
    }
}

impl AdvancedRequest for AdvancedSetCustomEmojiStickerSetThumbnailRequest {
    type Response = bool;
    const METHOD: &'static str = "setCustomEmojiStickerSetThumbnail";

    fn validate(&self) -> Result<()> {
        validate_required_string("name", &self.name)?;
        if let Some(value) = self.custom_emoji_id.as_deref() {
            validate_string_id("custom_emoji_id", value)?;
        }
        Ok(())
    }
}

/// Auto-generated request for `deleteStickerSet`.
#[derive(Clone, Debug, Serialize)]
pub struct AdvancedDeleteStickerSetRequest {
    pub name: String,
}

impl AdvancedDeleteStickerSetRequest {
    pub fn new(name: impl Into<String>) -> Self {
        Self { name: name.into() }
    }
}

impl AdvancedRequest for AdvancedDeleteStickerSetRequest {
    type Response = bool;
    const METHOD: &'static str = "deleteStickerSet";

    fn validate(&self) -> Result<()> {
        validate_required_string("name", &self.name)?;
        Ok(())
    }
}
