//! Простые удобные методы для отправки сообщений.
//!
//! Этот модуль предоставляет типаж `MaxClientSimpleExt`, который добавляет
//! быстрые методы для отправки часто используемых типов сообщений:
//! текст, markdown, html, изображения, видео, аудио, файлы, стикеры, геолокация, контакты, ссылки и клавиатуры.

use std::future::Future;
use std::path::Path;

use crate::attachments::{Attachment, ContactData, InlineKeyboard, ShareData};
use crate::client::MaxClient;
use crate::error::Result;
use crate::SendMessageParamsBuilder;

/// Расширяющий типаж для `MaxClient` с быстрыми методами отправки.
pub trait MaxClientSimpleExt {
    /// Отправляет обычный текст в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `text` - текст сообщения
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    ///
    /// # Пример
    /// ```no_run
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64) -> Result<(), maxbot::Error> {
    /// use maxbot::MaxClientSimpleExt;
    /// let mid = client.send_plain_text_to_chat(chat_id, "Привет!").await?;
    /// # Ok(())
    /// # }
    /// ```
    fn send_plain_text_to_chat(
        &self,
        chat_id: i64,
        text: &str,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет текст с Markdown-форматированием в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `text` - текст сообщения с Markdown-разметкой
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    ///
    /// # Пример
    /// ```no_run
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64) -> Result<(), maxbot::Error> {
    /// use maxbot::MaxClientSimpleExt;
    /// client.send_markdown_to_chat(chat_id, "**bold** и *italic*").await?;
    /// # Ok(())
    /// # }
    /// ```
    fn send_markdown_to_chat(
        &self,
        chat_id: i64,
        text: &str,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет текст с HTML-форматированием в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `text` - текст сообщения с HTML-разметкой
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_html_to_chat(
        &self,
        chat_id: i64,
        text: &str,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет изображение из локального файла в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `path` - путь к файлу изображения
    /// * `caption` - необязательная подпись к изображению
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_image_to_chat(
        &self,
        chat_id: i64,
        path: &Path,
        caption: Option<&str>,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет видео из локального файла в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `path` - путь к видеофайлу
    /// * `caption` - необязательная подпись
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_video_to_chat(
        &self,
        chat_id: i64,
        path: &Path,
        caption: Option<&str>,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет аудио из локального файла в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `path` - путь к аудиофайлу
    /// * `caption` - необязательная подпись
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_audio_to_chat(
        &self,
        chat_id: i64,
        path: &Path,
        caption: Option<&str>,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет произвольный файл из локального пути в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `path` - путь к файлу
    /// * `caption` - необязательная подпись
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_file_to_chat(
        &self,
        chat_id: i64,
        path: &Path,
        caption: Option<&str>,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет стикер по коду в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `code` - код стикера (например, "154ed15bb")
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_sticker_to_chat(
        &self,
        chat_id: i64,
        code: &str,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет геолокацию в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `latitude` - широта
    /// * `longitude` - долгота
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_location_to_chat(
        &self,
        chat_id: i64,
        latitude: f64,
        longitude: f64,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет контакт в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `contact` - данные контакта (имя, ID, VCF)
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_contact_to_chat(
        &self,
        chat_id: i64,
        contact: ContactData,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет ссылку (share) в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `url` - URL, которым нужно поделиться
    /// * `text` - необязательный текст сообщения
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_share_to_chat(
        &self,
        chat_id: i64,
        url: &str,
        text: Option<&str>,
    ) -> impl Future<Output = Result<Vec<String>>>;

    /// Отправляет сообщение с inline-клавиатурой в чат.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата
    /// * `text` - текст сообщения
    /// * `keyboard` - inline-клавиатура
    ///
    /// # Возвращает
    /// Набор `mid` фрагментов отправленного сообщения.
    fn send_keyboard_to_chat(
        &self,
        chat_id: i64,
        text: &str,
        keyboard: InlineKeyboard,
    ) -> impl Future<Output = Result<Vec<String>>>;
}

impl MaxClientSimpleExt for MaxClient {
    async fn send_plain_text_to_chat(&self, chat_id: i64, text: &str) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .text(text)
            .chat_id(chat_id);
        self.send_message_builder(builder).await
    }

    async fn send_markdown_to_chat(&self, chat_id: i64, text: &str) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .text(text)
            .chat_id(chat_id)
            .format_markdown();
        self.send_message_builder(builder).await
    }

    async fn send_html_to_chat(&self, chat_id: i64, text: &str) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .text(text)
            .chat_id(chat_id)
            .format_html();
        self.send_message_builder(builder).await
    }

    async fn send_image_to_chat(&self, chat_id: i64, path: &Path, caption: Option<&str>) -> Result<Vec<String>> {
        let mut builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::image_local(path));
        if let Some(cap) = caption {
            builder = builder.text(cap);
        }
        self.send_message_builder(builder).await
    }

    async fn send_video_to_chat(&self, chat_id: i64, path: &Path, caption: Option<&str>) -> Result<Vec<String>> {
        let mut builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::video_local(path));
        if let Some(cap) = caption {
            builder = builder.text(cap);
        }
        self.send_message_builder(builder).await
    }

    async fn send_audio_to_chat(&self, chat_id: i64, path: &Path, caption: Option<&str>) -> Result<Vec<String>> {
        let mut builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::audio_local(path));
        if let Some(cap) = caption {
            builder = builder.text(cap);
        }
        self.send_message_builder(builder).await
    }

    async fn send_file_to_chat(&self, chat_id: i64, path: &Path, caption: Option<&str>) -> Result<Vec<String>> {
        let mut builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::file_local(path));
        if let Some(cap) = caption {
            builder = builder.text(cap);
        }
        self.send_message_builder(builder).await
    }

    async fn send_sticker_to_chat(&self, chat_id: i64, code: &str) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::sticker(code));
        self.send_message_builder(builder).await
    }

    async fn send_location_to_chat(&self, chat_id: i64, latitude: f64, longitude: f64) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::location(latitude, longitude));
        self.send_message_builder(builder).await
    }

    async fn send_contact_to_chat(&self, chat_id: i64, contact: ContactData) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::contact(contact));
        self.send_message_builder(builder).await
    }

    async fn send_share_to_chat(&self, chat_id: i64, url: &str, text: Option<&str>) -> Result<Vec<String>> {
        let share = ShareData {
            url: Some(url.to_string()),
            token: None,
        };
        let mut builder = SendMessageParamsBuilder::new()
            .chat_id(chat_id)
            .attachment(Attachment::share(share));
        if let Some(txt) = text {
            builder = builder.text(txt);
        }
        self.send_message_builder(builder).await
    }

    async fn send_keyboard_to_chat(
        &self,
        chat_id: i64,
        text: &str,
        keyboard: InlineKeyboard,
    ) -> Result<Vec<String>> {
        let builder = SendMessageParamsBuilder::new()
            .text(text)
            .chat_id(chat_id)
            .attachment(Attachment::inline_keyboard(keyboard));
        self.send_message_builder(builder).await
    }
}
