//! Методы для работы с чатами (групповыми и диалогами).

use crate::client::MaxClient;
use crate::error::Result;
use crate::types::{Chat, ChatMember, Message, UpdateChatInfo};
use log::info;

impl MaxClient {
    // -------------------------------------------------------------------------
    // Базовые операции с чатами
    // -------------------------------------------------------------------------

    /// Получает информацию о чате по его идентификатору.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - числовой идентификатор чата.
    pub async fn get_chat(&self, chat_id: i64) -> Result<Chat> {
        self.request_with_rate_limit(
            reqwest::Method::GET,
            &format!("/chats/{}", chat_id),
            &[],
            None,
        )
        .await
    }

    /// Возвращает список групповых чатов, в которых участвует бот.
    ///
    /// Поддерживает постраничный вывод с помощью параметров `count` и `marker`.
    ///
    /// # Аргументы
    ///
    /// * `count` - количество возвращаемых чатов (от 1 до 100).
    /// * `marker` - маркер для продолжения вывода (значение из предыдущего ответа).
    ///
    /// # Возвращаемое значение
    ///
    /// Кортеж `(чаты, следующий_маркер)`. Если `следующий_маркер` равен `None`, достигнут конец списка.
    pub async fn get_chats(
        &self,
        count: Option<u32>,
        marker: Option<i64>,
    ) -> Result<(Vec<Chat>, Option<i64>)> {
        let mut query = Vec::new();
        if let Some(c) = count {
            query.push(("count", c.to_string()));
        }
        if let Some(m) = marker {
            query.push(("marker", m.to_string()));
        }
        let resp: serde_json::Value = self
            .request_with_rate_limit(reqwest::Method::GET, "/chats", &query, None)
            .await?;
        let chats = serde_json::from_value(resp["chats"].clone())?;
        let next_marker = resp.get("marker").and_then(|v| v.as_i64());
        Ok((chats, next_marker))
    }

    /// Обновляет информацию о чате (название, описание, иконка, ссылка, публичность).
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `info` - структура [`UpdateChatInfo`] с полями для обновления (все необязательные).
    pub async fn update_chat(&self, chat_id: i64, info: UpdateChatInfo) -> Result<Chat> {
        let mut body = serde_json::Map::new();

        if let Some(title) = info.title {
            body.insert("title".into(), title.into());
        }
        if let Some(desc) = info.description {
            body.insert("description".into(), desc.into());
        }

        // Иконка: объект с полем url или token (взаимоисключающие)
        if let Some(url) = info.icon_url {
            let mut icon_obj = serde_json::Map::new();
            icon_obj.insert("url".into(), url.into());
            body.insert("icon".into(), icon_obj.into());
        } else if let Some(token) = info.icon_token {
            let mut icon_obj = serde_json::Map::new();
            icon_obj.insert("token".into(), token.into());
            body.insert("icon".into(), icon_obj.into());
        }

        if let Some(link) = info.link {
            body.insert("link".into(), link.into());
        }
        if let Some(is_public) = info.is_public {
            body.insert("is_public".into(), is_public.into());
        }
        if let Some(pin) = info.pin {
            body.insert("pin".into(), pin.into());
        }
        if let Some(notify) = info.notify {
            body.insert("notify".into(), notify.into());
        }

        self.request_with_rate_limit(
            reqwest::Method::PATCH,
            &format!("/chats/{}", chat_id),
            &[],
            Some(serde_json::Value::Object(body)),
        )
        .await
    }

    /// Удаляет групповой чат (только для владельца чата).
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    pub async fn delete_chat(&self, chat_id: i64) -> Result<()> {
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::DELETE,
            &format!("/chats/{}", chat_id),
            &[],
            None,
        )
        .await?;

        // API MAX может вернуть 200 OK, но с полем success = false
        if let Some(success) = resp.get("success").and_then(|v| v.as_bool()) {
            if !success {
                let message = resp
                    .get("message")
                    .and_then(|v| v.as_str())
                    .unwrap_or("Unknown error");
                return Err(crate::error::Error::Api {
                    code: 200,
                    message: message.to_string(),
                });
            }
        }
        Ok(())
    }

    /// Позволяет боту покинуть чат.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата, из которого нужно выйти.
    pub async fn leave_chat(&self, chat_id: i64) -> Result<()> {
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::DELETE,
            &format!("/chats/{}/members/me", chat_id),
            &[],
            None,
        )
        .await?;
        if let Some(success) = resp.get("success").and_then(|v| v.as_bool()) {
            if !success {
                let message = resp
                    .get("message")
                    .and_then(|v| v.as_str())
                    .unwrap_or("Unknown error");
                return Err(crate::error::Error::Api {
                    code: 200,
                    message: message.to_string(),
                });
            }
        }
        Ok(())
    }

    // -------------------------------------------------------------------------
    // Участники и администраторы
    // -------------------------------------------------------------------------

    /// Возвращает список участников чата с постраничным выводом.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `marker` - маркер для следующего вывода (необязательно).
    /// * `count` - количество участников на странице (необязательно).
    ///
    /// # Возвращаемое значение
    ///
    /// Кортеж `(участники, следующий_маркер)`.
    pub async fn get_chat_members(
        &self,
        chat_id: i64,
        marker: Option<i64>,
        count: Option<u32>,
    ) -> Result<(Vec<ChatMember>, Option<i64>)> {
        let mut query = Vec::new();
        if let Some(m) = marker {
            query.push(("marker", m.to_string()));
        }
        if let Some(c) = count {
            query.push(("count", c.to_string()));
        }
        let resp: serde_json::Value = self
            .request_with_rate_limit(
                reqwest::Method::GET,
                &format!("/chats/{}/members", chat_id),
                &query,
                None,
            )
            .await?;
        let members = serde_json::from_value(resp["members"].clone())?;
        let next_marker = resp.get("marker").and_then(|v| v.as_i64());
        Ok((members, next_marker))
    }

    /// Возвращает информацию о конкретных участниках чата по их идентификаторам.
    ///
    /// # Аргументы
    /// * `chat_id` - идентификатор чата.
    /// * `user_ids` - список идентификаторов пользователей.
    ///
    /// # Возвращаемое значение
    /// Набор структур [`ChatMember`] для запрошенных пользователей. Если пользователь не является участником,
    /// он не включается в результат.
    ///
    /// # Пример
    /// ```no_run
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64) -> Result<(), Box<dyn std::error::Error>> {
    /// let members = client.get_chat_members_by_ids(chat_id, vec![111, 222]).await?;
    /// for member in members {
    ///     println!("{}", member.user.first_name);
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn get_chat_members_by_ids(
        &self,
        chat_id: i64,
        user_ids: Vec<i64>,
    ) -> Result<Vec<ChatMember>> {
        if user_ids.is_empty() {
            return Ok(Vec::new());
        }
        let user_ids_str: Vec<String> = user_ids.iter().map(|id| id.to_string()).collect();
        let query = vec![("user_ids", user_ids_str.join(","))];
        let resp: serde_json::Value = self
            .request_with_rate_limit(
                reqwest::Method::GET,
                &format!("/chats/{}/members", chat_id),
                &query,
                None,
            )
            .await?;
        let members = serde_json::from_value(resp["members"].clone())?;
        Ok(members)
    }

    /// Получает список администраторов чата.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    ///
    /// # Возвращаемое значение
    ///
    /// Вектор структур [`ChatMember`], представляющих администраторов.
    /// Если бот не имеет прав или администраторы отсутствуют, возвращается пустой вектор.
    pub async fn get_chat_admins(&self, chat_id: i64) -> Result<Vec<ChatMember>> {
        let resp: serde_json::Value = self
            .request_with_rate_limit(
                reqwest::Method::GET,
                &format!("/chats/{}/members/admins", chat_id),
                &[],
                None,
            )
            .await?;

        // API возвращает поле "members", которое может быть null
        let members = resp.get("members").cloned().unwrap_or(serde_json::Value::Null);
        if members.is_null() {
            return Ok(Vec::new());
        }
        Ok(serde_json::from_value(members)?)
    }

    /// Назначает пользователя администратором чата с указанными правами и псевдонимом.
    ///
    /// # Аргументы
    /// * `chat_id` – идентификатор чата.
    /// * `user_id` – идентификатор пользователя.
    /// * `permissions` – список разрешений (см. `ChatAdminPermissionKind`).
    /// * `alias` – отображаемое имя администратора (необязательно).
    ///
    /// # Пример
    /// ```no_run
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64, user_id: i64) -> Result<(), Box<dyn std::error::Error>> {
    /// client.add_chat_admin(
    ///     chat_id,
    ///     user_id,
    ///     vec!["read_all_messages".to_string(), "write".to_string()],
    ///     Some("Помощник".to_string())
    /// ).await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn add_chat_admin(
        &self,
        chat_id: i64,
        user_id: i64,
        permissions: Vec<String>,
        alias: Option<String>,
    ) -> Result<()> {
        let admins = vec![serde_json::json!({
            "user_id": user_id,
            "permissions": permissions,
            "alias": alias,
        })];
        let body = serde_json::json!({ "admins": admins });
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::POST,
            &format!("/chats/{}/members/admins", chat_id),
            &[],
            Some(body),
        ).await?;

        if !resp["success"].as_bool().unwrap_or(false) {
            let msg = resp["message"].as_str().unwrap_or("unknown error");
            return Err(crate::error::Error::Api {
                code: 200,
                message: msg.to_string(),
            });
        }
        Ok(())
    }

    /// Назначает нескольких пользователей администраторами чата за один запрос.
    ///
    /// # Аргументы
    /// * `chat_id` – идентификатор чата.
    /// * `admins` – набор структур `ChatAdminRequest`.
    ///
    /// # Пример
    /// ```no_run
    /// # use maxbot::ChatAdminRequest;
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64) -> Result<(), Box<dyn std::error::Error>> {
    /// let admins = vec![
    ///     ChatAdminRequest {
    ///         user_id: 123456,
    ///         permissions: vec!["read_all_messages".to_string()],
    ///         alias: Some("Наблюдатель".to_string()),
    ///     },
    ///     ChatAdminRequest {
    ///         user_id: 789012,
    ///         permissions: vec!["write".to_string(), "pin_message".to_string()],
    ///         alias: None,
    ///     },
    /// ];
    /// client.add_chat_admins(chat_id, admins).await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn add_chat_admins(
        &self,
        chat_id: i64,
        admins: Vec<ChatAdminRequest>,
    ) -> Result<()> {
        let admins_json: Vec<serde_json::Value> = admins
            .into_iter()
            .map(|a| {
                let mut obj = serde_json::json!({
                    "user_id": a.user_id,
                    "permissions": a.permissions,
                });
                if let Some(alias) = a.alias {
                    obj["alias"] = alias.into();
                }
                obj
            })
            .collect();
        let body = serde_json::json!({ "admins": admins_json });
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::POST,
            &format!("/chats/{}/members/admins", chat_id),
            &[],
            Some(body),
        ).await?;

        if !resp["success"].as_bool().unwrap_or(false) {
            let msg = resp["message"].as_str().unwrap_or("unknown error");
            return Err(crate::error::Error::Api {
                code: 200,
                message: msg.to_string(),
            });
        }
        Ok(())
    }

    /// Снимает права администратора с пользователя.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `user_id` - идентификатор пользователя.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64, user_id: i64) -> Result<(), Box<dyn std::error::Error>> {
    /// client.remove_chat_admin(chat_id, user_id).await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn remove_chat_admin(&self, chat_id: i64, user_id: i64) -> Result<()> {
        let resp: serde_json::Value = self
            .request_with_rate_limit(
                reqwest::Method::DELETE,
                &format!("/chats/{}/members/admins/{}", chat_id, user_id),
                &[],
                None,
            )
            .await?;

        // Проверяем поле success, так как API может вернуть 200 OK с success = false
        if !resp["success"].as_bool().unwrap_or(false) {
            let msg = resp["message"]
                .as_str()
                .unwrap_or("unknown error")
                .to_string();
            return Err(crate::error::Error::Api {
                code: 200,
                message: msg,
            });
        }
        Ok(())
    }

    /// Снимает права администратора с нескольких пользователей последовательно.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `user_ids` - вектор идентификаторов пользователей.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # async fn example(client: &maxbot::MaxClient, chat_id: i64) -> Result<(), Box<dyn std::error::Error>> {
    /// client.remove_chat_admins(chat_id, vec![111, 222]).await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn remove_chat_admins(&self, chat_id: i64, user_ids: Vec<i64>) -> Result<()> {
        for &user_id in &user_ids {
            if let Err(e) = self.remove_chat_admin(chat_id, user_id).await {
                eprintln!("Warning: failed to remove admin {}: {}", user_id, e);
                // Продолжаем попытки для остальных пользователей
            }
        }
        Ok(())
    }

    /// Добавляет пользователей в чат.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `user_ids` - вектор идентификаторов пользователей.
    pub async fn add_chat_members(&self, chat_id: i64, user_ids: Vec<i64>) -> Result<()> {
        let body = serde_json::json!({ "user_ids": user_ids });
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::POST,
            &format!("/chats/{}/members", chat_id),
            &[],
            Some(body),
        )
        .await?;
        Ok(())
    }

    /// Удаляет участника из чата.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `user_id` - идентификатор пользователя.
    pub async fn remove_chat_member(&self, chat_id: i64, user_id: i64) -> Result<()> {
        self.request_with_rate_limit::<serde_json::Value>(
            reqwest::Method::DELETE,
            &format!("/chats/{}/members", chat_id),
            &[("user_id", user_id.to_string())],
            None,
        )
        .await?;
        Ok(())
    }

    /// Возвращает информацию о боте как об участнике чата.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    pub async fn get_bot_member(&self, chat_id: i64) -> Result<ChatMember> {
        self.request_with_rate_limit(
            reqwest::Method::GET,
            &format!("/chats/{}/members/me", chat_id),
            &[],
            None,
        )
        .await
    }

    // -------------------------------------------------------------------------
    // Действия в чате (печать, загрузка и т.п.)
    // -------------------------------------------------------------------------

    /// Отправляет действие бота в чате (например, "typing_on", "sending_photo").
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `action` - строка, описывающая действие. Допустимые значения:
    ///   `"typing_on"`, `"sending_photo"`, `"sending_video"`, `"sending_audio"`,
    ///   `"sending_file"`, `"mark_seen"`.
    pub async fn send_chat_action(&self, chat_id: i64, action: &str) -> Result<()> {
        let body = serde_json::json!({ "action": action });
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::POST,
            &format!("/chats/{}/actions", chat_id),
            &[],
            Some(body),
        )
        .await?;

        info!("RESP: {resp:?}");

        if let Some(success) = resp.get("success").and_then(|v| v.as_bool()) {
            if !success {
                let message = resp
                    .get("message")
                    .and_then(|v| v.as_str())
                    .unwrap_or("Unknown error");
                return Err(crate::error::Error::Api {
                    code: 200,
                    message: message.to_string(),
                });
            }
        }
        Ok(())
    }

    // -------------------------------------------------------------------------
    // Закреплённые сообщения
    // -------------------------------------------------------------------------

    /// Возвращает закреплённое сообщение в чате.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    pub async fn get_pinned_message(&self, chat_id: i64) -> Result<Message> {
        self.request_with_rate_limit(
            reqwest::Method::GET,
            &format!("/chats/{}/pin", chat_id),
            &[],
            None,
        )
        .await
    }

    /// Закрепляет сообщение в чате.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    /// * `message_mid` - строковый идентификатор сообщения (`mid`).
    pub async fn pin_message(&self, chat_id: i64, message_mid: &str) -> Result<()> {
        let body = serde_json::json!({ "message_id": message_mid });
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::PUT,
            &format!("/chats/{}/pin", chat_id),
            &[],
            Some(body),
        )
        .await?;
        if let Some(success) = resp.get("success").and_then(|v| v.as_bool()) {
            if !success {
                let message = resp
                    .get("message")
                    .and_then(|v| v.as_str())
                    .unwrap_or("Unknown error");
                return Err(crate::error::Error::Api {
                    code: 200,
                    message: message.to_string(),
                });
            }
        }
        Ok(())
    }

    /// Открепляет закреплённое сообщение в чате.
    ///
    /// # Аргументы
    ///
    /// * `chat_id` - идентификатор чата.
    pub async fn unpin_message(&self, chat_id: i64) -> Result<()> {
        let resp: serde_json::Value = self.request_with_rate_limit(
            reqwest::Method::DELETE,
            &format!("/chats/{}/pin", chat_id),
            &[],
            None,
        )
        .await?;
        if let Some(success) = resp.get("success").and_then(|v| v.as_bool()) {
            if !success {
                let message = resp
                    .get("message")
                    .and_then(|v| v.as_str())
                    .unwrap_or("Unknown error");
                return Err(crate::error::Error::Api {
                    code: 200,
                    message: message.to_string(),
                });
            }
        }
        Ok(())
    }
}

/// Параметры для добавления администратора в чат.
#[derive(Debug, Clone)]
pub struct ChatAdminRequest {
    /// Идентификатор пользователя.
    pub user_id: i64,
    /// Список прав (например, `"read_all_messages"`, `"write"`).
    pub permissions: Vec<String>,
    /// Псевдоним, отображаемый в интерфейсе.
    pub alias: Option<String>,
}
