# Интеграция TDLib в Telegram TUI

## Обзор

TDLib (Telegram Database Library) — это официальная кроссплатформенная библиотека для создания Telegram клиентов. Она предоставляет полный функционал Telegram API с автоматическим управлением сессиями, кэшированием и синхронизацией.

## Выбор библиотеки для Rust

Существует несколько Rust-оберток для TDLib:

### 1. rust-tdlib
- **GitHub**: [antonio-antuan/rust-tdlib](https://github.com/antonio-antuan/rust-tdlib)
- **docs.rs**: https://docs.rs/rust-tdlib
- **Особенности**:
  - Async/await с tokio
  - Client/Worker архитектура
  - Требует предварительной сборки TDLib

### 2. tdlib-rs (Рекомендуется)
- **GitHub**: [FedericoBruzzone/tdlib-rs](https://github.com/FedericoBruzzone/tdlib-rs)
- **crates.io**: https://crates.io/crates/tdlib-rs
- **docs.rs**: https://docs.rs/tdlib/latest/tdlib/
- **Преимущества**:
  - ✅ Не требует предварительной установки TDLib
  - ✅ Кроссплатформенность (Windows, Linux, macOS)
  - ✅ Автоматическая загрузка прекомпилированных бинарников
  - ✅ Поддержка TDLib v1.8.29
  - ✅ Автогенерация типов из TL схемы

## Установка tdlib-rs

### Вариант 1: Автоматическая загрузка (Рекомендуется)

**Cargo.toml:**
```toml
[dependencies]
tdlib-rs = { version = "0.3", features = ["download-tdlib"] }
tokio = { version = "1", features = ["full"] }

[build-dependencies]
tdlib-rs = { version = "0.3", features = ["download-tdlib"] }
```

**build.rs:**
```rust
fn main() {
    tdlib_rs::build::build(None);
}
```

### Вариант 2: Локальная установка TDLib

Если TDLib уже установлен (версия 1.8.29):

```bash
export LOCAL_TDLIB_PATH=$HOME/lib/tdlib
```

```toml
[dependencies]
tdlib-rs = { version = "0.3", features = ["local-tdlib"] }
```

### Вариант 3: Через pkg-config

```bash
export PKG_CONFIG_PATH=$HOME/lib/tdlib/lib/pkgconfig/:$PKG_CONFIG_PATH
export LD_LIBRARY_PATH=$HOME/lib/tdlib/lib/:$LD_LIBRARY_PATH
```

```toml
[dependencies]
tdlib-rs = { version = "0.3", features = ["pkg-config"] }
```

## Архитектура TDLib

### Основные компоненты

```
┌─────────────────────────────────────────────────────────┐
│                    Your Application                      │
├─────────────────────────────────────────────────────────┤
│  ┌────────────┐  ┌──────────────┐  ┌────────────────┐  │
│  │   Client   │  │ Update Stream │  │  API Requests  │  │
│  └────────────┘  └──────────────┘  └────────────────┘  │
├─────────────────────────────────────────────────────────┤
│                      TDLib Client                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │  Auth State  │  │  Local Cache  │  │  API Handler │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
├─────────────────────────────────────────────────────────┤
│                   Telegram Servers                       │
└─────────────────────────────────────────────────────────┘
```

### Поток работы

1. **Инициализация** → TDLib запускается с параметрами
2. **Авторизация** → Проход через стейт-машину авторизации
3. **Синхронизация** → Загрузка базовых данных (чаты, контакты)
4. **Updates Stream** → Постоянный поток обновлений от сервера
5. **API Requests** → Запросы на получение данных / отправку сообщений

## Процесс авторизации

### Стейт-машина авторизации

TDLib работает через систему состояний. Приложение получает обновления `updateAuthorizationState` и реагирует на них:

```
authorizationStateWaitTdlibParameters
    ↓ (вызываем setTdlibParameters)
authorizationStateWaitPhoneNumber
    ↓ (вызываем setAuthenticationPhoneNumber)
authorizationStateWaitCode
    ↓ (вызываем checkAuthenticationCode)
authorizationStateWaitPassword (опционально, если 2FA)
    ↓ (вызываем checkAuthenticationPassword)
authorizationStateReady ✓
```

### Шаг 1: Получение API ключей

Перед началом работы нужно:
1. Зайти на https://my.telegram.org
2. Войти с номером телефона
3. Перейти в "API development tools"
4. Создать приложение и получить `api_id` и `api_hash`

### Шаг 2: Инициализация TDLib

```rust
use tdlib::{functions, types};

async fn init_tdlib() {
    // Параметры инициализации
    let params = types::TdlibParameters {
        database_directory: "./tdlib_db".to_string(),
        use_message_database: true,
        use_secret_chats: true,
        api_id: env::var("API_ID").unwrap().parse().unwrap(),
        api_hash: env::var("API_HASH").unwrap(),
        system_language_code: "en".to_string(),
        device_model: "Desktop".to_string(),
        system_version: "Unknown".to_string(),
        application_version: "0.1.0".to_string(),
        enable_storage_optimizer: true,
        ignore_file_names: false,
    };

    // Отправляем параметры
    functions::set_tdlib_parameters(params, &client).await?;
}
```

### Шаг 3: Ввод номера телефона

```rust
async fn authenticate_with_phone(phone: String, client: &Client) {
    let phone_number = types::SetAuthenticationPhoneNumber {
        phone_number: phone,
        settings: None,
    };

    functions::set_authentication_phone_number(phone_number, client).await?;
}
```

### Шаг 4: Ввод кода подтверждения

```rust
async fn verify_code(code: String, client: &Client) {
    let check_code = types::CheckAuthenticationCode {
        code,
    };

    functions::check_authentication_code(check_code, client).await?;
}
```

### Шаг 5: Ввод пароля 2FA (если включен)

```rust
async fn verify_password(password: String, client: &Client) {
    let check_password = types::CheckAuthenticationPassword {
        password,
    };

    functions::check_authentication_password(check_password, client).await?;
}
```

## Получение списка чатов

### Концепция чатов в TDLib

TDLib автоматически кэширует чаты локально. Приложение должно:
1. Подписаться на обновления `updateNewChat`
2. Вызвать `loadChats()` для загрузки чатов
3. Поддерживать локальный кэш с сортировкой

### Типы списков чатов

- **Main** — основные чаты
- **Archive** — архивные чаты
- **Folder** — пользовательские папки

### Загрузка чатов

```rust
use tdlib::{functions, types};

async fn load_chats(client: &Client) -> Result<Vec<Chat>> {
    // Указываем тип списка (Main, Archive, или конкретная папка)
    let chat_list = types::ChatList::Main;

    // Загружаем чаты
    // limit - количество чатов для загрузки
    functions::load_chats(
        types::LoadChats {
            chat_list: Some(chat_list),
            limit: 50,
        },
        client
    ).await?;

    // После вызова loadChats, чаты будут приходить через updateNewChat
    Ok(vec![])
}
```

### Получение информации о чате

```rust
async fn get_chat_info(chat_id: i64, client: &Client) -> Result<types::Chat> {
    let chat = functions::get_chat(
        types::GetChat { chat_id },
        client
    ).await?;

    Ok(chat)
}
```

### Сортировка чатов

Чаты нужно сортировать по паре `(position.order, chat.id)` в порядке убывания:

```rust
chats.sort_by(|a, b| {
    let order_a = a.positions.get(0).map(|p| p.order).unwrap_or(0);
    let order_b = b.positions.get(0).map(|p| p.order).unwrap_or(0);

    order_b.cmp(&order_a)
        .then_with(|| b.id.cmp(&a.id))
});
```

## Получение истории сообщений

### Загрузка сообщений из чата

```rust
async fn get_chat_history(
    chat_id: i64,
    from_message_id: i64,
    limit: i32,
    client: &Client
) -> Result<Vec<types::Message>> {
    let history = functions::get_chat_history(
        types::GetChatHistory {
            chat_id,
            from_message_id, // 0 для последних сообщений
            offset: 0,
            limit,
            only_local: false,
        },
        client
    ).await?;

    Ok(history.messages.unwrap_or_default())
}
```

### Пагинация сообщений

Сообщения возвращаются в обратном хронологическом порядке (новые → старые).

Для загрузки следующей страницы:
```rust
// Первая загрузка (последние сообщения)
let messages = get_chat_history(chat_id, 0, 50, &client).await?;

// Загрузка более старых сообщений
if let Some(oldest_msg) = messages.last() {
    let older_messages = get_chat_history(
        chat_id,
        oldest_msg.id,
        50,
        &client
    ).await?;
}
```

## Обработка обновлений (Updates Stream)

### Типы обновлений

TDLib отправляет обновления через `Update` enum:

- `UpdateNewMessage` — новое сообщение
- `UpdateMessageContent` — изменение контента сообщения
- `UpdateMessageSendSucceeded` — сообщение успешно отправлено
- `UpdateMessageSendFailed` — ошибка отправки
- `UpdateChatLastMessage` — изменилось последнее сообщение чата
- `UpdateChatPosition` — изменилась позиция чата в списке
- `UpdateNewChat` — новый чат добавлен
- `UpdateUser` — обновилась информация о пользователе
- `UpdateUserStatus` — изменился статус пользователя (онлайн/оффлайн)
- `UpdateChatReadInbox` — прочитаны входящие сообщения
- `UpdateChatReadOutbox` — прочитаны исходящие сообщения

### Слушатель обновлений

```rust
use tdlib::types::Update;

async fn handle_updates(client: Client) {
    loop {
        match client.receive() {
            Some(Update::NewMessage(update)) => {
                println!("New message in chat {}: {}",
                    update.message.chat_id,
                    update.message.content
                );
            }
            Some(Update::MessageSendSucceeded(update)) => {
                println!("Message sent successfully: {}", update.message.id);
            }
            Some(Update::UserStatus(update)) => {
                println!("User {} is now {:?}",
                    update.user_id,
                    update.status
                );
            }
            Some(Update::NewChat(update)) => {
                println!("New chat added: {}", update.chat.title);
            }
            _ => {}
        }
    }
}
```

## Отправка сообщений

### Отправка текстового сообщения

```rust
async fn send_message(
    chat_id: i64,
    text: String,
    client: &Client
) -> Result<types::Message> {
    let input_content = types::InputMessageContent::InputMessageText(
        types::InputMessageText {
            text: types::FormattedText {
                text,
                entities: vec![],
            },
            disable_web_page_preview: false,
            clear_draft: true,
        }
    );

    let message = functions::send_message(
        types::SendMessage {
            chat_id,
            message_thread_id: 0,
            reply_to: None,
            options: None,
            reply_markup: None,
            input_message_content: input_content,
        },
        client
    ).await?;

    Ok(message)
}
```

### Статусы доставки и прочтения

Для отображения ✓ и ✓✓:

```rust
fn get_message_status(message: &types::Message) -> &str {
    if message.is_outgoing {
        match &message.sending_state {
            Some(types::MessageSendingState::Pending) => "",  // отправляется
            Some(types::MessageSendingState::Failed(_)) => "✗",  // ошибка
            None => {
                // Отправлено успешно
                if message.chat_id > 0 {  // личный чат
                    // Проверяем, прочитано ли
                    // (нужно следить за UpdateChatReadOutbox)
                    "✓✓"  // или "✓" если не прочитано
                } else {
                    "✓"  // групповой чат
                }
            }
        }
    } else {
        ""  // входящее сообщение
    }
}
```

## Работа с папками (Folders)

### Получение списка папок

```rust
async fn get_chat_folders(client: &Client) -> Result<Vec<types::ChatFolderInfo>> {
    let folders = functions::get_chat_folders(
        types::GetChatFolders {},
        client
    ).await?;

    Ok(folders.chat_folders)
}
```

### Фильтрация чатов по папке

```rust
async fn get_chats_in_folder(folder_id: i32, client: &Client) {
    let chat_list = types::ChatList::Folder {
        chat_folder_id: folder_id
    };

    functions::load_chats(
        types::LoadChats {
            chat_list: Some(chat_list),
            limit: 50,
        },
        client
    ).await?;
}
```

## Архитектура приложения

### Рекомендуемая структура

```
src/
├── main.rs           # Entry point, UI loop
├── tdlib/
│   ├── mod.rs        # TDLib module
│   ├── client.rs     # Client wrapper
│   ├── auth.rs       # Authentication logic
│   └── updates.rs    # Update handlers
├── ui/
│   ├── mod.rs
│   ├── app.rs        # App state
│   ├── layout.rs     # UI layout
│   └── components/   # UI components
└── models/
    ├── chat.rs       # Chat models
    └── message.rs    # Message models
```

### Разделение ответственности

1. **TDLib Client** — управление клиентом, запросы к API
2. **Update Handler** — обработка обновлений в фоне
3. **App State** — состояние приложения (чаты, сообщения, UI)
4. **UI Layer** — отрисовка интерфейса (ratatui)

### Коммуникация между слоями

```rust
// Используем каналы для коммуникации
use tokio::sync::mpsc;

#[derive(Debug)]
enum AppEvent {
    NewMessage(Message),
    ChatUpdated(Chat),
    UserStatusChanged(i64, UserStatus),
}

#[tokio::main]
async fn main() {
    // Канал для событий от TDLib
    let (tx, mut rx) = mpsc::channel::<AppEvent>(100);

    // Запускаем TDLib в отдельной задаче
    tokio::spawn(async move {
        run_tdlib_client(tx).await;
    });

    // Основной UI loop
    loop {
        // Проверяем события
        while let Ok(event) = rx.try_recv() {
            match event {
                AppEvent::NewMessage(msg) => {
                    // Обновляем UI
                }
                _ => {}
            }
        }

        // Отрисовываем UI
        terminal.draw(|f| ui(f, &app))?;

        // Обрабатываем ввод пользователя
        handle_input()?;
    }
}
```

## Пример: Минимальный клиент

```rust
use tdlib::{Client, ClientState, functions, types};
use tokio::sync::mpsc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Создаем клиент
    let (sender, mut receiver) = mpsc::channel(100);
    let client = Client::new(sender);

    // 2. Запускаем клиент
    tokio::spawn(async move {
        client.start().await;
    });

    // 3. Ждем авторизации
    let mut authorized = false;

    while let Some(update) = receiver.recv().await {
        match update {
            types::Update::AuthorizationState(state) => {
                match state.authorization_state {
                    types::AuthorizationState::WaitTdlibParameters => {
                        // Отправляем параметры
                        init_tdlib(&client).await?;
                    }
                    types::AuthorizationState::WaitPhoneNumber => {
                        // Запрашиваем номер у пользователя
                        let phone = read_phone_from_user();
                        authenticate_with_phone(phone, &client).await?;
                    }
                    types::AuthorizationState::WaitCode(_) => {
                        // Запрашиваем код
                        let code = read_code_from_user();
                        verify_code(code, &client).await?;
                    }
                    types::AuthorizationState::Ready => {
                        authorized = true;
                        break;
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }

    // 4. Загружаем чаты
    if authorized {
        load_chats(&client).await?;

        // 5. Слушаем обновления
        while let Some(update) = receiver.recv().await {
            handle_update(update);
        }
    }

    Ok(())
}
```

## Best Practices

### 1. Кэширование
- Всегда включай `use_message_database: true`
- Храни кэш чатов и сообщений в памяти
- Используй `only_local: true` для быстрого доступа

### 2. Обработка ошибок
- Все TDLib функции возвращают `Result`
- Обрабатывай потерю соединения
- Переподключайся при ошибках сети

### 3. Производительность
- Не загружай все чаты сразу (используй пагинацию)
- Лимитируй количество сообщений в истории
- Используй `offset` для ленивой загрузки

### 4. UI/UX
- Показывай индикаторы загрузки
- Кэшируй отрисованные элементы
- Обновляй UI только при изменениях

## Полезные ссылки

### Официальная документация
- [TDLib Getting Started](https://core.telegram.org/tdlib/getting-started)
- [TDLib Documentation](https://core.telegram.org/tdlib/docs/)

### Rust библиотеки
- [rust-tdlib GitHub](https://github.com/antonio-antuan/rust-tdlib)
- [rust-tdlib docs.rs](https://docs.rs/rust-tdlib)
- [tdlib-rs GitHub](https://github.com/FedericoBruzzone/tdlib-rs)
- [tdlib-rs docs.rs](https://docs.rs/tdlib/latest/tdlib/)

### API Reference
- [tdlib::functions](https://docs.rs/tdlib/latest/tdlib/functions/index.html)
- [tdlib::types](https://docs.rs/tdlib-types/latest/tdlib_types/types/index.html)

## Следующие шаги

1. ✅ Изучить документацию TDLib
2. ⬜ Добавить зависимость tdlib-rs в проект
3. ⬜ Реализовать модуль авторизации
4. ⬜ Реализовать загрузку чатов
5. ⬜ Реализовать загрузку сообщений
6. ⬜ Интегрировать с существующим UI
7. ⬜ Добавить отправку сообщений
8. ⬜ Реализовать обработку обновлений в реальном времени
